diff options
Diffstat (limited to 'src/declarative/qml')
150 files changed, 62111 insertions, 0 deletions
diff --git a/src/declarative/qml/parser/parser.pri b/src/declarative/qml/parser/parser.pri new file mode 100644 index 00000000..fd4361c2 --- /dev/null +++ b/src/declarative/qml/parser/parser.pri @@ -0,0 +1,21 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/qdeclarativejsast_p.h \ + $$PWD/qdeclarativejsastfwd_p.h \ + $$PWD/qdeclarativejsastvisitor_p.h \ + $$PWD/qdeclarativejsengine_p.h \ + $$PWD/qdeclarativejsgrammar_p.h \ + $$PWD/qdeclarativejslexer_p.h \ + $$PWD/qdeclarativejsmemorypool_p.h \ + $$PWD/qdeclarativejsnodepool_p.h \ + $$PWD/qdeclarativejsparser_p.h \ + $$PWD/qdeclarativejsglobal_p.h + +SOURCES += \ + $$PWD/qdeclarativejsast.cpp \ + $$PWD/qdeclarativejsastvisitor.cpp \ + $$PWD/qdeclarativejsengine_p.cpp \ + $$PWD/qdeclarativejsgrammar.cpp \ + $$PWD/qdeclarativejslexer.cpp \ + $$PWD/qdeclarativejsparser.cpp diff --git a/src/declarative/qml/parser/qdeclarativejs.g b/src/declarative/qml/parser/qdeclarativejs.g new file mode 100644 index 00000000..3fb9412c --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejs.g @@ -0,0 +1,3149 @@ +---------------------------------------------------------------------------- +-- +-- Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +-- All rights reserved. +-- Contact: Nokia Corporation (qt-info@nokia.com) +-- +-- This file is part of the QtDeclarative module of the Qt Toolkit. +-- +-- $QT_BEGIN_LICENSE:LGPL-ONLY$ +-- GNU Lesser General Public License Usage +-- This file may be used under the terms of the GNU Lesser +-- General Public License version 2.1 as published by the Free Software +-- Foundation and appearing in the file LICENSE.LGPL included in the +-- packaging of this file. Please review the following information to +-- ensure the GNU Lesser General Public License version 2.1 requirements +-- will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +-- +-- If you have questions regarding the use of this file, please contact +-- Nokia at qt-info@nokia.com. +-- $QT_END_LICENSE$ +-- +---------------------------------------------------------------------------- + +%parser QDeclarativeJSGrammar +%decl qdeclarativejsparser_p.h +%impl qdeclarativejsparser.cpp +%expect 2 +%expect-rr 2 + +%token T_AND "&" T_AND_AND "&&" T_AND_EQ "&=" +%token T_BREAK "break" T_CASE "case" T_CATCH "catch" +%token T_COLON ":" T_COMMA ";" T_CONTINUE "continue" +%token T_DEFAULT "default" T_DELETE "delete" T_DIVIDE_ "/" +%token T_DIVIDE_EQ "/=" T_DO "do" T_DOT "." +%token T_ELSE "else" T_EQ "=" T_EQ_EQ "==" +%token T_EQ_EQ_EQ "===" T_FINALLY "finally" T_FOR "for" +%token T_FUNCTION "function" T_GE ">=" T_GT ">" +%token T_GT_GT ">>" T_GT_GT_EQ ">>=" T_GT_GT_GT ">>>" +%token T_GT_GT_GT_EQ ">>>=" T_IDENTIFIER "identifier" T_IF "if" +%token T_IN "in" T_INSTANCEOF "instanceof" T_LBRACE "{" +%token T_LBRACKET "[" T_LE "<=" T_LPAREN "(" +%token T_LT "<" T_LT_LT "<<" T_LT_LT_EQ "<<=" +%token T_MINUS "-" T_MINUS_EQ "-=" T_MINUS_MINUS "--" +%token T_NEW "new" T_NOT "!" T_NOT_EQ "!=" +%token T_NOT_EQ_EQ "!==" T_NUMERIC_LITERAL "numeric literal" T_OR "|" +%token T_OR_EQ "|=" T_OR_OR "||" T_PLUS "+" +%token T_PLUS_EQ "+=" T_PLUS_PLUS "++" T_QUESTION "?" +%token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%" +%token T_REMAINDER_EQ "%=" T_RETURN "return" T_RPAREN ")" +%token T_SEMICOLON ";" T_AUTOMATIC_SEMICOLON T_STAR "*" +%token T_STAR_EQ "*=" T_STRING_LITERAL "string literal" +%token T_PROPERTY "property" T_SIGNAL "signal" T_READONLY "readonly" +%token T_SWITCH "switch" T_THIS "this" T_THROW "throw" +%token T_TILDE "~" T_TRY "try" T_TYPEOF "typeof" +%token T_VAR "var" T_VOID "void" T_WHILE "while" +%token T_WITH "with" T_XOR "^" T_XOR_EQ "^=" +%token T_NULL "null" T_TRUE "true" T_FALSE "false" +%token T_CONST "const" +%token T_DEBUGGER "debugger" +%token T_RESERVED_WORD "reserved word" +%token T_MULTILINE_STRING_LITERAL "multiline string literal" +%token T_COMMENT "comment" + +--- context keywords. +%token T_PUBLIC "public" +%token T_IMPORT "import" +%token T_AS "as" +%token T_ON "on" + +--- feed tokens +%token T_FEED_UI_PROGRAM +%token T_FEED_UI_OBJECT_MEMBER +%token T_FEED_JS_STATEMENT +%token T_FEED_JS_EXPRESSION +%token T_FEED_JS_SOURCE_ELEMENT +%token T_FEED_JS_PROGRAM + +%nonassoc SHIFT_THERE +%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY +%nonassoc REDUCE_HERE + +%start TopLevel + +/./**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QtDebug> +#include <QtGui/QApplication> + +#include <string.h> + +#include "private/qdeclarativejsengine_p.h" +#include "private/qdeclarativejslexer_p.h" +#include "private/qdeclarativejsast_p.h" +#include "private/qdeclarativejsnodepool_p.h" + +./ + +/:/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// +// This file is automatically generated from qmljs.g. +// Changes will be lost. +// + +#ifndef QDECLARATIVEJSPARSER_P_H +#define QDECLARATIVEJSPARSER_P_H + +#include "private/qdeclarativejsglobal_p.h" +#include "private/qdeclarativejsgrammar_p.h" +#include "private/qdeclarativejsast_p.h" +#include "private/qdeclarativejsengine_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> + +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { + +class Engine; +class NameId; + +class QML_PARSER_EXPORT Parser: protected $table +{ +public: + union Value { + int ival; + double dval; + NameId *sval; + AST::ArgumentList *ArgumentList; + AST::CaseBlock *CaseBlock; + AST::CaseClause *CaseClause; + AST::CaseClauses *CaseClauses; + AST::Catch *Catch; + AST::DefaultClause *DefaultClause; + AST::ElementList *ElementList; + AST::Elision *Elision; + AST::ExpressionNode *Expression; + AST::Finally *Finally; + AST::FormalParameterList *FormalParameterList; + AST::FunctionBody *FunctionBody; + AST::FunctionDeclaration *FunctionDeclaration; + AST::Node *Node; + AST::PropertyName *PropertyName; + AST::PropertyNameAndValueList *PropertyNameAndValueList; + AST::SourceElement *SourceElement; + AST::SourceElements *SourceElements; + AST::Statement *Statement; + AST::StatementList *StatementList; + AST::Block *Block; + AST::VariableDeclaration *VariableDeclaration; + AST::VariableDeclarationList *VariableDeclarationList; + + AST::UiProgram *UiProgram; + AST::UiImportList *UiImportList; + AST::UiImport *UiImport; + AST::UiParameterList *UiParameterList; + AST::UiPublicMember *UiPublicMember; + AST::UiObjectDefinition *UiObjectDefinition; + AST::UiObjectInitializer *UiObjectInitializer; + AST::UiObjectBinding *UiObjectBinding; + AST::UiScriptBinding *UiScriptBinding; + AST::UiArrayBinding *UiArrayBinding; + AST::UiObjectMember *UiObjectMember; + AST::UiObjectMemberList *UiObjectMemberList; + AST::UiArrayMemberList *UiArrayMemberList; + AST::UiQualifiedId *UiQualifiedId; + AST::UiSignature *UiSignature; + AST::UiFormalList *UiFormalList; + AST::UiFormal *UiFormal; + }; + +public: + Parser(Engine *engine); + ~Parser(); + + // parse a UI program + bool parse() { return parse(T_FEED_UI_PROGRAM); } + bool parseStatement() { return parse(T_FEED_JS_STATEMENT); } + bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); } + bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); } + bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); } + bool parseProgram() { return parse(T_FEED_JS_PROGRAM); } + + AST::UiProgram *ast() const + { return AST::cast<AST::UiProgram *>(program); } + + AST::Statement *statement() const + { + if (! program) + return 0; + + return program->statementCast(); + } + + AST::ExpressionNode *expression() const + { + if (! program) + return 0; + + return program->expressionCast(); + } + + AST::UiObjectMember *uiObjectMember() const + { + if (! program) + return 0; + + return program->uiObjectMemberCast(); + } + + AST::Node *rootNode() const + { return program; } + + QList<DiagnosticMessage> diagnosticMessages() const + { return diagnostic_messages; } + + inline DiagnosticMessage diagnosticMessage() const + { + foreach (const DiagnosticMessage &d, diagnostic_messages) { + if (! d.kind == DiagnosticMessage::Warning) + return d; + } + + return DiagnosticMessage(); + } + + inline QString errorMessage() const + { return diagnosticMessage().message; } + + inline int errorLineNumber() const + { return diagnosticMessage().loc.startLine; } + + inline int errorColumnNumber() const + { return diagnosticMessage().loc.startColumn; } + +protected: + bool parse(int startToken); + + void reallocateStack(); + + inline Value &sym(int index) + { return sym_stack [tos + index - 1]; } + + inline AST::SourceLocation &loc(int index) + { return location_stack [tos + index - 1]; } + + AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr); + +protected: + Engine *driver; + int tos; + int stack_size; + Value *sym_stack; + int *state_stack; + AST::SourceLocation *location_stack; + + AST::Node *program; + + // error recovery + enum { TOKEN_BUFFER_SIZE = 3 }; + + struct SavedToken { + int token; + double dval; + AST::SourceLocation loc; + }; + + double yylval; + AST::SourceLocation yylloc; + AST::SourceLocation yyprevlloc; + + SavedToken token_buffer[TOKEN_BUFFER_SIZE]; + SavedToken *first_token; + SavedToken *last_token; + + QList<DiagnosticMessage> diagnostic_messages; +}; + +} // end of namespace QDeclarativeJS + + +:/ + + +/. + +#include "private/qdeclarativejsparser_p.h" +#include <QVarLengthArray> + +// +// This file is automatically generated from qmljs.g. +// Changes will be lost. +// + +using namespace QDeclarativeJS; + +QT_QML_BEGIN_NAMESPACE + +void Parser::reallocateStack() +{ + if (! stack_size) + stack_size = 128; + else + stack_size <<= 1; + + sym_stack = reinterpret_cast<Value*> (qRealloc(sym_stack, stack_size * sizeof(Value))); + state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int))); + location_stack = reinterpret_cast<AST::SourceLocation*> (qRealloc(location_stack, stack_size * sizeof(AST::SourceLocation))); +} + +inline static bool automatic(Engine *driver, int token) +{ + return token == $table::T_RBRACE + || token == 0 + || driver->lexer()->prevTerminator(); +} + + +Parser::Parser(Engine *engine): + driver(engine), + tos(0), + stack_size(0), + sym_stack(0), + state_stack(0), + location_stack(0), + first_token(0), + last_token(0) +{ +} + +Parser::~Parser() +{ + if (stack_size) { + qFree(sym_stack); + qFree(state_stack); + qFree(location_stack); + } +} + +static inline AST::SourceLocation location(Lexer *lexer) +{ + AST::SourceLocation loc; + loc.offset = lexer->tokenOffset(); + loc.length = lexer->tokenLength(); + loc.startLine = lexer->startLineNo(); + loc.startColumn = lexer->startColumnNo(); + return loc; +} + +AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) +{ + QVarLengthArray<NameId *, 4> nameIds; + QVarLengthArray<AST::SourceLocation, 4> locations; + + AST::ExpressionNode *it = expr; + while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) { + nameIds.append(m->name); + locations.append(m->identifierToken); + it = m->base; + } + + if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) { + AST::UiQualifiedId *q = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), idExpr->name); + q->identifierToken = idExpr->identifierToken; + + AST::UiQualifiedId *currentId = q; + for (int i = nameIds.size() - 1; i != -1; --i) { + currentId = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), currentId, nameIds[i]); + currentId->identifierToken = locations[i]; + } + + return currentId->finish(); + } + + return 0; +} + +bool Parser::parse(int startToken) +{ + Lexer *lexer = driver->lexer(); + bool hadErrors = false; + int yytoken = -1; + int action = 0; + + token_buffer[0].token = startToken; + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; + + tos = -1; + program = 0; + + do { + if (++tos == stack_size) + reallocateStack(); + + state_stack[tos] = action; + + _Lcheck_token: + if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) { + yyprevlloc = yylloc; + + if (first_token == last_token) { + yytoken = lexer->lex(); + yylval = lexer->dval(); + yylloc = location(lexer); + } else { + yytoken = first_token->token; + yylval = first_token->dval; + yylloc = first_token->loc; + ++first_token; + } + } + + action = t_action(action, yytoken); + if (action > 0) { + if (action != ACCEPT_STATE) { + yytoken = -1; + sym(1).dval = yylval; + loc(1) = yylloc; + } else { + --tos; + return ! hadErrors; + } + } else if (action < 0) { + const int r = -action - 1; + tos -= rhs[r]; + + switch (r) { +./ + +-------------------------------------------------------------------------------------------------------- +-- Declarative UI +-------------------------------------------------------------------------------------------------------- + +TopLevel: T_FEED_UI_PROGRAM UiProgram ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_STATEMENT Statement ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_EXPRESSION Expression ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_SOURCE_ELEMENT SourceElement ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_PROGRAM Program ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +UiProgram: UiImportListOpt UiRootMember ; +/. +case $rule_number: { + sym(1).UiProgram = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList, + sym(2).UiObjectMemberList->finish()); +} break; +./ + +UiImportListOpt: Empty ; +UiImportListOpt: UiImportList ; +/. +case $rule_number: { + sym(1).Node = sym(1).UiImportList->finish(); +} break; +./ + +UiImportList: UiImport ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImport); +} break; +./ + +UiImportList: UiImportList UiImport ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), + sym(1).UiImportList, sym(2).UiImport); +} break; +./ + +ImportId: MemberExpression ; + +UiImport: UiImportHead T_AUTOMATIC_SEMICOLON ; +UiImport: UiImportHead T_SEMICOLON ; +/. +case $rule_number: { + sym(1).UiImport->semicolonToken = loc(2); +} break; +./ + +UiImport: UiImportHead T_NUMERIC_LITERAL T_AUTOMATIC_SEMICOLON ; +UiImport: UiImportHead T_NUMERIC_LITERAL T_SEMICOLON ; +/. +case $rule_number: { + sym(1).UiImport->versionToken = loc(2); + sym(1).UiImport->semicolonToken = loc(3); +} break; +./ + +UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ; +UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_SEMICOLON ; +/. +case $rule_number: { + sym(1).UiImport->versionToken = loc(2); + sym(1).UiImport->asToken = loc(3); + sym(1).UiImport->importIdToken = loc(4); + sym(1).UiImport->importId = sym(4).sval; + sym(1).UiImport->semicolonToken = loc(5); +} break; +./ + +UiImport: UiImportHead T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ; +UiImport: UiImportHead T_AS JsIdentifier T_SEMICOLON ; +/. +case $rule_number: { + sym(1).UiImport->asToken = loc(2); + sym(1).UiImport->importIdToken = loc(3); + sym(1).UiImport->importId = sym(3).sval; + sym(1).UiImport->semicolonToken = loc(4); +} break; +./ + + +UiImportHead: T_IMPORT ImportId ; +/. +case $rule_number: { + AST::UiImport *node = 0; + + if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) { + node = makeAstNode<AST::UiImport>(driver->nodePool(), importIdLiteral->value); + node->fileNameToken = loc(2); + } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) { + node = makeAstNode<AST::UiImport>(driver->nodePool(), qualifiedId); + node->fileNameToken = loc(2); + } + + sym(1).Node = node; + + if (node) { + node->importToken = loc(1); + } else { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), + QLatin1String("Expected a qualified name id or a string literal"))); + + return false; // ### remove me + } +} break; +./ + +Empty: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +UiRootMember: UiObjectDefinition ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; +./ + +UiObjectMemberList: UiObjectMember ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; +./ + +UiObjectMemberList: UiObjectMemberList UiObjectMember ; +/. +case $rule_number: { + AST::UiObjectMemberList *node = makeAstNode<AST:: UiObjectMemberList> (driver->nodePool(), + sym(1).UiObjectMemberList, sym(2).UiObjectMember); + sym(1).Node = node; +} break; +./ + +UiArrayMemberList: UiObjectDefinition ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; +./ + +UiArrayMemberList: UiArrayMemberList T_COMMA UiObjectDefinition ; +/. +case $rule_number: { + AST::UiArrayMemberList *node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), + sym(1).UiArrayMemberList, sym(3).UiObjectMember); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiObjectInitializer: T_LBRACE T_RBRACE ; +/. +case $rule_number: { + AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), (AST::UiObjectMemberList*)0); + node->lbraceToken = loc(1); + node->rbraceToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiObjectInitializer: T_LBRACE UiObjectMemberList T_RBRACE ; +/. +case $rule_number: { + AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), sym(2).UiObjectMemberList->finish()); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; +./ + +UiObjectDefinition: UiQualifiedId UiObjectInitializer ; +/. +case $rule_number: { + AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId, + sym(2).UiObjectInitializer); + sym(1).Node = node; +} break; +./ + +UiObjectMember: UiObjectDefinition ; + +UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ; +/. +case $rule_number: { + AST::UiArrayBinding *node = makeAstNode<AST::UiArrayBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish()); + node->colonToken = loc(2); + node->lbracketToken = loc(3); + node->rbracketToken = loc(5); + sym(1).Node = node; +} break; +./ + +UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ; +/. +case $rule_number: { + AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer ; +/. +case $rule_number: { + AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), + sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer); + node->colonToken = loc(2); + node->hasOnToken = true; + sym(1).Node = node; +} break; +./ + +UiObjectMember: UiQualifiedId T_COLON Block ; +/.case $rule_number:./ + +UiObjectMember: UiQualifiedId T_COLON EmptyStatement ; +/.case $rule_number:./ + +UiObjectMember: UiQualifiedId T_COLON ExpressionStatement ; +/.case $rule_number:./ + +UiObjectMember: UiQualifiedId T_COLON IfStatement ; --- ### do we really want if statement in a binding? +/.case $rule_number:./ + +/. +{ + AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(3).Statement); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiPropertyType: T_VAR ; +/. +case $rule_number: +./ +UiPropertyType: T_RESERVED_WORD ; +/. +case $rule_number: { + sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); + break; +} +./ + +UiPropertyType: T_IDENTIFIER ; + +UiParameterListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +UiParameterListOpt: UiParameterList ; +/. +case $rule_number: { + sym(1).Node = sym(1).UiParameterList->finish (); +} break; +./ + +UiParameterList: UiPropertyType JsIdentifier ; +/. +case $rule_number: { + AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).sval, sym(2).sval); + node->identifierToken = loc(2); + sym(1).Node = node; +} break; +./ + +UiParameterList: UiParameterList T_COMMA UiPropertyType JsIdentifier ; +/. +case $rule_number: { + AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).UiParameterList, sym(3).sval, sym(4).sval); + node->commaToken = loc(2); + node->identifierToken = loc(4); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); + node->type = AST::UiPublicMember::Signal; + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(2); + node->parameters = sym(4).UiParameterList; + node->semicolonToken = loc(6); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_SIGNAL T_IDENTIFIER T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); + node->type = AST::UiPublicMember::Signal; + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval); + node->typeModifier = sym(2).sval; + node->propertyToken = loc(1); + node->typeModifierToken = loc(2); + node->typeToken = loc(4); + node->identifierToken = loc(6); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->semicolonToken = loc(4); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval); + node->isDefaultMember = true; + node->defaultToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->semicolonToken = loc(5); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval, + sym(5).Expression); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->colonToken = loc(4); + node->semicolonToken = loc(6); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval, + sym(6).Expression); + node->isReadonlyMember = true; + node->readonlyToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->colonToken = loc(5); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_AUTOMATIC_SEMICOLON ; +UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON Expression T_SEMICOLON ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval, + sym(6).Expression); + node->isDefaultMember = true; + node->defaultToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->colonToken = loc(5); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval); + node->typeModifier = sym(2).sval; + node->propertyToken = loc(1); + node->typeModifierToken = loc(2); + node->typeToken = loc(4); + node->identifierToken = loc(6); + node->semicolonToken = loc(7); // insert a fake ';' before ':' + + AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(6).sval); + propertyName->identifierToken = loc(6); + propertyName->next = 0; + + AST::UiArrayBinding *binding = makeAstNode<AST::UiArrayBinding> (driver->nodePool(), + propertyName, sym(9).UiArrayMemberList->finish()); + binding->colonToken = loc(7); + binding->lbracketToken = loc(8); + binding->rbracketToken = loc(10); + + node->binding = binding; + + sym(1).Node = node; +} break; +./ + +UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiQualifiedId UiObjectInitializer ; +/. +case $rule_number: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->semicolonToken = loc(4); // insert a fake ';' before ':' + + AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(3).sval); + propertyName->identifierToken = loc(3); + propertyName->next = 0; + + AST::UiObjectBinding *binding = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), + propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer); + binding->colonToken = loc(4); + + node->binding = binding; + + sym(1).Node = node; +} break; +./ + +UiObjectMember: FunctionDeclaration ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); +} break; +./ + +UiObjectMember: VariableStatement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); +} break; +./ + +JsIdentifier: T_IDENTIFIER; + +JsIdentifier: T_PROPERTY ; +/. +case $rule_number: { + QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_PROPERTY]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} +./ + +JsIdentifier: T_SIGNAL ; +/. +case $rule_number: { + QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_SIGNAL]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} +./ + +JsIdentifier: T_READONLY ; +/. +case $rule_number: { + QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_READONLY]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} +./ + +JsIdentifier: T_ON ; +/. +case $rule_number: { + QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_ON]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} +./ + +-------------------------------------------------------------------------------------------------------- +-- Expressions +-------------------------------------------------------------------------------------------------------- + +PrimaryExpression: T_THIS ; +/. +case $rule_number: { + AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool()); + node->thisToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: JsIdentifier ; +/. +case $rule_number: { + AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_NULL ; +/. +case $rule_number: { + AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool()); + node->nullToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_TRUE ; +/. +case $rule_number: { + AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool()); + node->trueToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_FALSE ; +/. +case $rule_number: { + AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool()); + node->falseToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_NUMERIC_LITERAL ; +/. +case $rule_number: { + AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_MULTILINE_STRING_LITERAL ; +/.case $rule_number:./ + +PrimaryExpression: T_STRING_LITERAL ; +/. +case $rule_number: { + AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_DIVIDE_ ; +/: +#define J_SCRIPT_REGEXPLITERAL_RULE1 $rule_number +:/ +/. +case $rule_number: { + bool rx = lexer->scanRegExp(Lexer::NoPrefix); + if (!rx) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); + return false; // ### remove me + } + + loc(1).length = lexer->tokenLength(); + + AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_DIVIDE_EQ ; +/: +#define J_SCRIPT_REGEXPLITERAL_RULE2 $rule_number +:/ +/. +case $rule_number: { + bool rx = lexer->scanRegExp(Lexer::EqualPrefix); + if (!rx) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); + return false; + } + + loc(1).length = lexer->tokenLength(); + + AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->rbracketToken = loc(2); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET Elision T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish()); + node->lbracketToken = loc(1); + node->rbracketToken = loc(3); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET ElementList T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ()); + node->lbracketToken = loc(1); + node->rbracketToken = loc(3); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET ElementList T_COMMA T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->commaToken = loc(3); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACKET ElementList T_COMMA Elision T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + sym(4).Elision->finish()); + node->lbracketToken = loc(1); + node->commaToken = loc(3); + node->rbracketToken = loc(5); + sym(1).Node = node; +} break; +./ + +-- PrimaryExpression: T_LBRACE T_RBRACE ; +-- /. +-- case $rule_number: { +-- sym(1).Node = makeAstNode<AST::ObjectLiteral> (driver->nodePool()); +-- } break; +-- ./ + +PrimaryExpression: T_LBRACE PropertyNameAndValueListOpt T_RBRACE ; +/. +case $rule_number: { + AST::ObjectLiteral *node = 0; + if (sym(2).Node) + node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), + sym(2).PropertyNameAndValueList->finish ()); + else + node = makeAstNode<AST::ObjectLiteral> (driver->nodePool()); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LBRACE PropertyNameAndValueList T_COMMA T_RBRACE ; +/. +case $rule_number: { + AST::ObjectLiteral *node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), + sym(2).PropertyNameAndValueList->finish ()); + node->lbraceToken = loc(1); + node->rbraceToken = loc(4); + sym(1).Node = node; +} break; +./ + +PrimaryExpression: T_LPAREN Expression T_RPAREN ; +/. +case $rule_number: { + AST::NestedExpression *node = makeAstNode<AST::NestedExpression>(driver->nodePool(), sym(2).Expression); + node->lparenToken = loc(1); + node->rparenToken = loc(3); + sym(1).Node = node; +} break; +./ + +UiQualifiedId: MemberExpression ; +/. +case $rule_number: { + if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken, + QLatin1String("Ignored annotation"))); + + sym(1).Expression = mem->base; + } + + if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) { + sym(1).UiQualifiedId = qualifiedId; + } else { + sym(1).UiQualifiedId = 0; + + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), + QLatin1String("Expected a qualified name id"))); + + return false; // ### recover + } +} break; +./ + +ElementList: AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression); +} break; +./ + +ElementList: Elision AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression); +} break; +./ + +ElementList: ElementList T_COMMA AssignmentExpression ; +/. +case $rule_number: { + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, + (AST::Elision *) 0, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +ElementList: ElementList T_COMMA Elision AssignmentExpression ; +/. +case $rule_number: { + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(), + sym(4).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +Elision: T_COMMA ; +/. +case $rule_number: { + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool()); + node->commaToken = loc(1); + sym(1).Node = node; +} break; +./ + +Elision: Elision T_COMMA ; +/. +case $rule_number: { + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +PropertyNameAndValueList: PropertyName T_COLON AssignmentExpression ; +/. +case $rule_number: { + AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), + sym(1).PropertyName, sym(3).Expression); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +PropertyNameAndValueList: PropertyNameAndValueList T_COMMA PropertyName T_COLON AssignmentExpression ; +/. +case $rule_number: { + AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), + sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); + node->commaToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; +./ + +PropertyName: T_IDENTIFIER %prec SHIFT_THERE ; +/. +case $rule_number: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: T_SIGNAL ; +/.case $rule_number:./ + +PropertyName: T_PROPERTY ; +/. +case $rule_number: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: T_STRING_LITERAL ; +/. +case $rule_number: { + AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: T_NUMERIC_LITERAL ; +/. +case $rule_number: { + AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +PropertyName: ReservedIdentifier ; +/. +case $rule_number: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +./ + +ReservedIdentifier: T_BREAK ; +/. +case $rule_number: +./ +ReservedIdentifier: T_CASE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_CATCH ; +/. +case $rule_number: +./ +ReservedIdentifier: T_CONTINUE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_DEFAULT ; +/. +case $rule_number: +./ +ReservedIdentifier: T_DELETE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_DO ; +/. +case $rule_number: +./ +ReservedIdentifier: T_ELSE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_FALSE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_FINALLY ; +/. +case $rule_number: +./ +ReservedIdentifier: T_FOR ; +/. +case $rule_number: +./ +ReservedIdentifier: T_FUNCTION ; +/. +case $rule_number: +./ +ReservedIdentifier: T_IF ; +/. +case $rule_number: +./ +ReservedIdentifier: T_IN ; +/. +case $rule_number: +./ +ReservedIdentifier: T_INSTANCEOF ; +/. +case $rule_number: +./ +ReservedIdentifier: T_NEW ; +/. +case $rule_number: +./ +ReservedIdentifier: T_NULL ; +/. +case $rule_number: +./ +ReservedIdentifier: T_RETURN ; +/. +case $rule_number: +./ +ReservedIdentifier: T_SWITCH ; +/. +case $rule_number: +./ +ReservedIdentifier: T_THIS ; +/. +case $rule_number: +./ +ReservedIdentifier: T_THROW ; +/. +case $rule_number: +./ +ReservedIdentifier: T_TRUE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_TRY ; +/. +case $rule_number: +./ +ReservedIdentifier: T_TYPEOF ; +/. +case $rule_number: +./ +ReservedIdentifier: T_VAR ; +/. +case $rule_number: +./ +ReservedIdentifier: T_VOID ; +/. +case $rule_number: +./ +ReservedIdentifier: T_WHILE ; +/. +case $rule_number: +./ +ReservedIdentifier: T_CONST ; +/. +case $rule_number: +./ +ReservedIdentifier: T_DEBUGGER ; +/. +case $rule_number: +./ +ReservedIdentifier: T_RESERVED_WORD ; +/. +case $rule_number: +./ +ReservedIdentifier: T_WITH ; +/. +case $rule_number: +{ + sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); +} break; +./ + +PropertyIdentifier: JsIdentifier ; +PropertyIdentifier: ReservedIdentifier ; + +MemberExpression: PrimaryExpression ; +MemberExpression: FunctionExpression ; + +MemberExpression: MemberExpression T_LBRACKET Expression T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->lbracketToken = loc(2); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; +./ + +MemberExpression: MemberExpression T_DOT PropertyIdentifier ; +/. +case $rule_number: { + AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + node->dotToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; +./ + +MemberExpression: T_NEW MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ; +/. +case $rule_number: { + AST::NewMemberExpression *node = makeAstNode<AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList); + node->newToken = loc(1); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + sym(1).Node = node; +} break; +./ + +NewExpression: MemberExpression ; + +NewExpression: T_NEW NewExpression ; +/. +case $rule_number: { + AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression); + node->newToken = loc(1); + sym(1).Node = node; +} break; +./ + +CallExpression: MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ; +/. +case $rule_number: { + AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +CallExpression: CallExpression T_LPAREN ArgumentListOpt T_RPAREN ; +/. +case $rule_number: { + AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +CallExpression: CallExpression T_LBRACKET Expression T_RBRACKET ; +/. +case $rule_number: { + AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->lbracketToken = loc(2); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; +./ + +CallExpression: CallExpression T_DOT PropertyIdentifier ; +/. +case $rule_number: { + AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + node->dotToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; +./ + +ArgumentListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +ArgumentListOpt: ArgumentList ; +/. +case $rule_number: { + sym(1).Node = sym(1).ArgumentList->finish(); +} break; +./ + +ArgumentList: AssignmentExpression ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression); +} break; +./ + +ArgumentList: ArgumentList T_COMMA AssignmentExpression ; +/. +case $rule_number: { + AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +LeftHandSideExpression: NewExpression ; +LeftHandSideExpression: CallExpression ; +PostfixExpression: LeftHandSideExpression ; + +PostfixExpression: LeftHandSideExpression T_PLUS_PLUS ; +/. +case $rule_number: { + AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression); + node->incrementToken = loc(2); + sym(1).Node = node; +} break; +./ + +PostfixExpression: LeftHandSideExpression T_MINUS_MINUS ; +/. +case $rule_number: { + AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression); + node->decrementToken = loc(2); + sym(1).Node = node; +} break; +./ + +UnaryExpression: PostfixExpression ; + +UnaryExpression: T_DELETE UnaryExpression ; +/. +case $rule_number: { + AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression); + node->deleteToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_VOID UnaryExpression ; +/. +case $rule_number: { + AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression); + node->voidToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_TYPEOF UnaryExpression ; +/. +case $rule_number: { + AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression); + node->typeofToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_PLUS_PLUS UnaryExpression ; +/. +case $rule_number: { + AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression); + node->incrementToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_MINUS_MINUS UnaryExpression ; +/. +case $rule_number: { + AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression); + node->decrementToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_PLUS UnaryExpression ; +/. +case $rule_number: { + AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression); + node->plusToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_MINUS UnaryExpression ; +/. +case $rule_number: { + AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression); + node->minusToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_TILDE UnaryExpression ; +/. +case $rule_number: { + AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression); + node->tildeToken = loc(1); + sym(1).Node = node; +} break; +./ + +UnaryExpression: T_NOT UnaryExpression ; +/. +case $rule_number: { + AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression); + node->notToken = loc(1); + sym(1).Node = node; +} break; +./ + +MultiplicativeExpression: UnaryExpression ; + +MultiplicativeExpression: MultiplicativeExpression T_STAR UnaryExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Mul, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +MultiplicativeExpression: MultiplicativeExpression T_DIVIDE_ UnaryExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Div, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +MultiplicativeExpression: MultiplicativeExpression T_REMAINDER UnaryExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Mod, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +AdditiveExpression: MultiplicativeExpression ; + +AdditiveExpression: AdditiveExpression T_PLUS MultiplicativeExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Add, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +AdditiveExpression: AdditiveExpression T_MINUS MultiplicativeExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Sub, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +ShiftExpression: AdditiveExpression ; + +ShiftExpression: ShiftExpression T_LT_LT AdditiveExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::LShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +ShiftExpression: ShiftExpression T_GT_GT AdditiveExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::RShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +ShiftExpression: ShiftExpression T_GT_GT_GT AdditiveExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::URShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: ShiftExpression ; + +RelationalExpression: RelationalExpression T_LT ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Lt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: RelationalExpression T_GT ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Gt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: RelationalExpression T_LE ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Le, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: RelationalExpression T_GE ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Ge, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: RelationalExpression T_INSTANCEOF ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::InstanceOf, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpression: RelationalExpression T_IN ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::In, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpressionNotIn: ShiftExpression ; + +RelationalExpressionNotIn: RelationalExpressionNotIn T_LT ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Lt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_GT ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Gt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_LE ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Le, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_GE ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Ge, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +RelationalExpressionNotIn: RelationalExpressionNotIn T_INSTANCEOF ShiftExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::InstanceOf, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpression: RelationalExpression ; + +EqualityExpression: EqualityExpression T_EQ_EQ RelationalExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Equal, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpression: EqualityExpression T_NOT_EQ RelationalExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::NotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpression: EqualityExpression T_EQ_EQ_EQ RelationalExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpression: EqualityExpression T_NOT_EQ_EQ RelationalExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictNotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpressionNotIn: RelationalExpressionNotIn ; + +EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ RelationalExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Equal, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ RelationalExpressionNotIn; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::NotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ_EQ RelationalExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ_EQ RelationalExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictNotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseANDExpression: EqualityExpression ; + +BitwiseANDExpression: BitwiseANDExpression T_AND EqualityExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitAnd, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseANDExpressionNotIn: EqualityExpressionNotIn ; + +BitwiseANDExpressionNotIn: BitwiseANDExpressionNotIn T_AND EqualityExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitAnd, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseXORExpression: BitwiseANDExpression ; + +BitwiseXORExpression: BitwiseXORExpression T_XOR BitwiseANDExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitXor, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseXORExpressionNotIn: BitwiseANDExpressionNotIn ; + +BitwiseXORExpressionNotIn: BitwiseXORExpressionNotIn T_XOR BitwiseANDExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitXor, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseORExpression: BitwiseXORExpression ; + +BitwiseORExpression: BitwiseORExpression T_OR BitwiseXORExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitOr, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +BitwiseORExpressionNotIn: BitwiseXORExpressionNotIn ; + +BitwiseORExpressionNotIn: BitwiseORExpressionNotIn T_OR BitwiseXORExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitOr, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +LogicalANDExpression: BitwiseORExpression ; + +LogicalANDExpression: LogicalANDExpression T_AND_AND BitwiseORExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::And, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +LogicalANDExpressionNotIn: BitwiseORExpressionNotIn ; + +LogicalANDExpressionNotIn: LogicalANDExpressionNotIn T_AND_AND BitwiseORExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::And, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +LogicalORExpression: LogicalANDExpression ; + +LogicalORExpression: LogicalORExpression T_OR_OR LogicalANDExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Or, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +LogicalORExpressionNotIn: LogicalANDExpressionNotIn ; + +LogicalORExpressionNotIn: LogicalORExpressionNotIn T_OR_OR LogicalANDExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Or, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +ConditionalExpression: LogicalORExpression ; + +ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression T_COLON AssignmentExpression ; +/. +case $rule_number: { + AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, + sym(3).Expression, sym(5).Expression); + node->questionToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; +./ + +ConditionalExpressionNotIn: LogicalORExpressionNotIn ; + +ConditionalExpressionNotIn: LogicalORExpressionNotIn T_QUESTION AssignmentExpressionNotIn T_COLON AssignmentExpressionNotIn ; +/. +case $rule_number: { + AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, + sym(3).Expression, sym(5).Expression); + node->questionToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; +./ + +AssignmentExpression: ConditionalExpression ; + +AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + sym(2).ival, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +AssignmentExpressionNotIn: ConditionalExpressionNotIn ; + +AssignmentExpressionNotIn: LeftHandSideExpression AssignmentOperator AssignmentExpressionNotIn ; +/. +case $rule_number: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + sym(2).ival, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; +./ + +AssignmentOperator: T_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::Assign; +} break; +./ + +AssignmentOperator: T_STAR_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceMul; +} break; +./ + +AssignmentOperator: T_DIVIDE_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceDiv; +} break; +./ + +AssignmentOperator: T_REMAINDER_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceMod; +} break; +./ + +AssignmentOperator: T_PLUS_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceAdd; +} break; +./ + +AssignmentOperator: T_MINUS_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceSub; +} break; +./ + +AssignmentOperator: T_LT_LT_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceLeftShift; +} break; +./ + +AssignmentOperator: T_GT_GT_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceRightShift; +} break; +./ + +AssignmentOperator: T_GT_GT_GT_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceURightShift; +} break; +./ + +AssignmentOperator: T_AND_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceAnd; +} break; +./ + +AssignmentOperator: T_XOR_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceXor; +} break; +./ + +AssignmentOperator: T_OR_EQ ; +/. +case $rule_number: { + sym(1).ival = QSOperator::InplaceOr; +} break; +./ + +Expression: AssignmentExpression ; + +Expression: Expression T_COMMA AssignmentExpression ; +/. +case $rule_number: { + AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +ExpressionOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +ExpressionOpt: Expression ; + +ExpressionNotIn: AssignmentExpressionNotIn ; + +ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ; +/. +case $rule_number: { + AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +ExpressionNotInOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +ExpressionNotInOpt: ExpressionNotIn ; + +Statement: Block ; +Statement: VariableStatement ; +Statement: EmptyStatement ; +Statement: ExpressionStatement ; +Statement: IfStatement ; +Statement: IterationStatement ; +Statement: ContinueStatement ; +Statement: BreakStatement ; +Statement: ReturnStatement ; +Statement: WithStatement ; +Statement: LabelledStatement ; +Statement: SwitchStatement ; +Statement: ThrowStatement ; +Statement: TryStatement ; +Statement: DebuggerStatement ; + + +Block: T_LBRACE StatementListOpt T_RBRACE ; +/. +case $rule_number: { + AST::Block *node = makeAstNode<AST::Block> (driver->nodePool(), sym(2).StatementList); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; +./ + +StatementList: Statement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement); +} break; +./ + +StatementList: StatementList Statement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement); +} break; +./ + +StatementListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +StatementListOpt: StatementList ; +/. +case $rule_number: { + sym(1).Node = sym(1).StatementList->finish (); +} break; +./ + +VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ; +/. +case $rule_number: { + AST::VariableStatement *node = makeAstNode<AST::VariableStatement> (driver->nodePool(), + sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); + node->declarationKindToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +VariableDeclarationKind: T_CONST ; +/. +case $rule_number: { + sym(1).ival = T_CONST; +} break; +./ + +VariableDeclarationKind: T_VAR ; +/. +case $rule_number: { + sym(1).ival = T_VAR; +} break; +./ + +VariableDeclarationList: VariableDeclaration ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); +} break; +./ + +VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration ; +/. +case $rule_number: { + AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), + sym(1).VariableDeclarationList, sym(3).VariableDeclaration); + node->commaToken = loc(2); + sym(1).Node = node; +} break; +./ + +VariableDeclarationListNotIn: VariableDeclarationNotIn ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); +} break; +./ + +VariableDeclarationListNotIn: VariableDeclarationListNotIn T_COMMA VariableDeclarationNotIn ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); +} break; +./ + +VariableDeclaration: JsIdentifier InitialiserOpt ; +/. +case $rule_number: { + AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ; +/. +case $rule_number: { + AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +Initialiser: T_EQ AssignmentExpression ; +/. +case $rule_number: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; +./ + +InitialiserOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +InitialiserOpt: Initialiser ; + +InitialiserNotIn: T_EQ AssignmentExpressionNotIn ; +/. +case $rule_number: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; +./ + +InitialiserNotInOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +InitialiserNotInOpt: InitialiserNotIn ; + +EmptyStatement: T_SEMICOLON ; +/. +case $rule_number: { + AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool()); + node->semicolonToken = loc(1); + sym(1).Node = node; +} break; +./ + +ExpressionStatement: Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ExpressionStatement: Expression T_SEMICOLON ; +/. +case $rule_number: { + AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; +./ + +IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement T_ELSE Statement ; +/. +case $rule_number: { + AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement); + node->ifToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + node->elseToken = loc(5); + sym(1).Node = node; +} break; +./ + +IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement ; +/. +case $rule_number: { + AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->ifToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + + +IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_SEMICOLON ; +/. +case $rule_number: { + AST::DoWhileStatement *node = makeAstNode<AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression); + node->doToken = loc(1); + node->whileToken = loc(3); + node->lparenToken = loc(4); + node->rparenToken = loc(6); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; +./ + +IterationStatement: T_WHILE T_LPAREN Expression T_RPAREN Statement ; +/. +case $rule_number: { + AST::WhileStatement *node = makeAstNode<AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->whileToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +IterationStatement: T_FOR T_LPAREN ExpressionNotInOpt T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ; +/. +case $rule_number: { + AST::ForStatement *node = makeAstNode<AST::ForStatement> (driver->nodePool(), sym(3).Expression, + sym(5).Expression, sym(7).Expression, sym(9).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->firstSemicolonToken = loc(4); + node->secondSemicolonToken = loc(6); + node->rparenToken = loc(8); + sym(1).Node = node; +} break; +./ + +IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ; +/. +case $rule_number: { + AST::LocalForStatement *node = makeAstNode<AST::LocalForStatement> (driver->nodePool(), + sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, + sym(8).Expression, sym(10).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->varToken = loc(3); + node->firstSemicolonToken = loc(5); + node->secondSemicolonToken = loc(7); + node->rparenToken = loc(9); + sym(1).Node = node; +} break; +./ + +IterationStatement: T_FOR T_LPAREN LeftHandSideExpression T_IN Expression T_RPAREN Statement ; +/. +case $rule_number: { + AST:: ForEachStatement *node = makeAstNode<AST::ForEachStatement> (driver->nodePool(), sym(3).Expression, + sym(5).Expression, sym(7).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->inToken = loc(4); + node->rparenToken = loc(6); + sym(1).Node = node; +} break; +./ + +IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationNotIn T_IN Expression T_RPAREN Statement ; +/. +case $rule_number: { + AST::LocalForEachStatement *node = makeAstNode<AST::LocalForEachStatement> (driver->nodePool(), + sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->varToken = loc(3); + node->inToken = loc(5); + node->rparenToken = loc(7); + sym(1).Node = node; +} break; +./ + +ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ContinueStatement: T_CONTINUE T_SEMICOLON ; +/. +case $rule_number: { + AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool()); + node->continueToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; +./ + +ContinueStatement: T_CONTINUE JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ContinueStatement: T_CONTINUE JsIdentifier T_SEMICOLON ; +/. +case $rule_number: { + AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool(), sym(2).sval); + node->continueToken = loc(1); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +BreakStatement: T_BREAK T_SEMICOLON ; +/. +case $rule_number: { + AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool()); + node->breakToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; +./ + +BreakStatement: T_BREAK JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +BreakStatement: T_BREAK JsIdentifier T_SEMICOLON ; +/. +case $rule_number: { + AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool(), sym(2).sval); + node->breakToken = loc(1); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +ReturnStatement: T_RETURN ExpressionOpt T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ReturnStatement: T_RETURN ExpressionOpt T_SEMICOLON ; +/. +case $rule_number: { + AST::ReturnStatement *node = makeAstNode<AST::ReturnStatement> (driver->nodePool(), sym(2).Expression); + node->returnToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +WithStatement: T_WITH T_LPAREN Expression T_RPAREN Statement ; +/. +case $rule_number: { + AST::WithStatement *node = makeAstNode<AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->withToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +SwitchStatement: T_SWITCH T_LPAREN Expression T_RPAREN CaseBlock ; +/. +case $rule_number: { + AST::SwitchStatement *node = makeAstNode<AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock); + node->switchToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +CaseBlock: T_LBRACE CaseClausesOpt T_RBRACE ; +/. +case $rule_number: { + AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; +./ + +CaseBlock: T_LBRACE CaseClausesOpt DefaultClause CaseClausesOpt T_RBRACE ; +/. +case $rule_number: { + AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); + node->lbraceToken = loc(1); + node->rbraceToken = loc(5); + sym(1).Node = node; +} break; +./ + +CaseClauses: CaseClause ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause); +} break; +./ + +CaseClauses: CaseClauses CaseClause ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause); +} break; +./ + +CaseClausesOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +CaseClausesOpt: CaseClauses ; +/. +case $rule_number: { + sym(1).Node = sym(1).CaseClauses->finish (); +} break; +./ + +CaseClause: T_CASE Expression T_COLON StatementListOpt ; +/. +case $rule_number: { + AST::CaseClause *node = makeAstNode<AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList); + node->caseToken = loc(1); + node->colonToken = loc(3); + sym(1).Node = node; +} break; +./ + +DefaultClause: T_DEFAULT T_COLON StatementListOpt ; +/. +case $rule_number: { + AST::DefaultClause *node = makeAstNode<AST::DefaultClause> (driver->nodePool(), sym(3).StatementList); + node->defaultToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +LabelledStatement: T_SIGNAL T_COLON Statement ; +/.case $rule_number:./ + +LabelledStatement: T_PROPERTY T_COLON Statement ; +/. +case $rule_number: { + AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement); + node->identifierToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +LabelledStatement: T_IDENTIFIER T_COLON Statement ; +/. +case $rule_number: { + AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement); + node->identifierToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +./ + +ThrowStatement: T_THROW Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +ThrowStatement: T_THROW Expression T_SEMICOLON ; +/. +case $rule_number: { + AST::ThrowStatement *node = makeAstNode<AST::ThrowStatement> (driver->nodePool(), sym(2).Expression); + node->throwToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; +./ + +TryStatement: T_TRY Block Catch ; +/. +case $rule_number: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch); + node->tryToken = loc(1); + sym(1).Node = node; +} break; +./ + +TryStatement: T_TRY Block Finally ; +/. +case $rule_number: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally); + node->tryToken = loc(1); + sym(1).Node = node; +} break; +./ + +TryStatement: T_TRY Block Catch Finally ; +/. +case $rule_number: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally); + node->tryToken = loc(1); + sym(1).Node = node; +} break; +./ + +Catch: T_CATCH T_LPAREN JsIdentifier T_RPAREN Block ; +/. +case $rule_number: { + AST::Catch *node = makeAstNode<AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Block); + node->catchToken = loc(1); + node->lparenToken = loc(2); + node->identifierToken = loc(3); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; +./ + +Finally: T_FINALLY Block ; +/. +case $rule_number: { + AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block); + node->finallyToken = loc(1); + sym(1).Node = node; +} break; +./ + +DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon +DebuggerStatement: T_DEBUGGER T_SEMICOLON ; +/. +case $rule_number: { + AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool()); + node->debuggerToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; +./ + +FunctionDeclaration: T_FUNCTION JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ; +/. +case $rule_number: { + AST::FunctionDeclaration *node = makeAstNode<AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + node->functionToken = loc(1); + node->identifierToken = loc(2); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + node->lbraceToken = loc(6); + node->rbraceToken = loc(8); + sym(1).Node = node; +} break; +./ + +FunctionExpression: T_FUNCTION IdentifierOpt T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ; +/. +case $rule_number: { + AST::FunctionExpression *node = makeAstNode<AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + node->functionToken = loc(1); + if (sym(2).sval) + node->identifierToken = loc(2); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + node->lbraceToken = loc(6); + node->rbraceToken = loc(8); + sym(1).Node = node; +} break; +./ + +FormalParameterList: JsIdentifier ; +/. +case $rule_number: { + AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; +./ + +FormalParameterList: FormalParameterList T_COMMA JsIdentifier ; +/. +case $rule_number: { + AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval); + node->commaToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; +./ + +FormalParameterListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +FormalParameterListOpt: FormalParameterList ; +/. +case $rule_number: { + sym(1).Node = sym(1).FormalParameterList->finish (); +} break; +./ + +FunctionBodyOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +FunctionBodyOpt: FunctionBody ; + +FunctionBody: SourceElements ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ()); +} break; +./ + +Program: SourceElements ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ()); +} break; +./ + +SourceElements: SourceElement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement); +} break; +./ + +SourceElements: SourceElements SourceElement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement); +} break; +./ + +SourceElement: Statement ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement); +} break; +./ + +SourceElement: FunctionDeclaration ; +/. +case $rule_number: { + sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration); +} break; +./ + +IdentifierOpt: ; +/. +case $rule_number: { + sym(1).sval = 0; +} break; +./ + +IdentifierOpt: JsIdentifier ; + +PropertyNameAndValueListOpt: ; +/. +case $rule_number: { + sym(1).Node = 0; +} break; +./ + +PropertyNameAndValueListOpt: PropertyNameAndValueList ; + +/. + } // switch + action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT); + } // if + } while (action != 0); + + if (first_token == last_token) { + const int errorState = state_stack[tos]; + + // automatic insertion of `;' + if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && automatic(driver, yytoken)) { + SavedToken &tk = token_buffer[0]; + tk.token = yytoken; + tk.dval = yylval; + tk.loc = yylloc; + + yylloc = yyprevlloc; + yylloc.offset += yylloc.length; + yylloc.startColumn += yylloc.length; + yylloc.length = 0; + + //const QString msg = qApp->translate("QDeclarativeParser", "Missing `;'"); + //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg)); + + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; + + yytoken = T_SEMICOLON; + yylval = 0; + + action = errorState; + + goto _Lcheck_token; + } + + hadErrors = true; + + token_buffer[0].token = yytoken; + token_buffer[0].dval = yylval; + token_buffer[0].loc = yylloc; + + token_buffer[1].token = yytoken = lexer->lex(); + token_buffer[1].dval = yylval = lexer->dval(); + token_buffer[1].loc = yylloc = location(lexer); + + if (t_action(errorState, yytoken)) { + QString msg; + int token = token_buffer[0].token; + if (token < 0 || token >= TERMINAL_COUNT) + msg = qApp->translate("QDeclarativeParser", "Syntax error"); + else + msg = qApp->translate("QDeclarativeParser", "Unexpected token `%1'").arg(QLatin1String(spell[token])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + action = errorState; + goto _Lcheck_token; + } + + static int tokens[] = { + T_PLUS, + T_EQ, + + T_COMMA, + T_COLON, + T_SEMICOLON, + + T_RPAREN, T_RBRACKET, T_RBRACE, + + T_NUMERIC_LITERAL, + T_IDENTIFIER, + + T_LPAREN, T_LBRACKET, T_LBRACE, + + EOF_SYMBOL + }; + + for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) { + int a = t_action(errorState, *tk); + if (a > 0 && t_action(a, yytoken)) { + const QString msg = qApp->translate("QDeclarativeParser", "Expected token `%1'").arg(QLatin1String(spell[*tk])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + yytoken = *tk; + yylval = 0; + yylloc = token_buffer[0].loc; + yylloc.length = 0; + + first_token = &token_buffer[0]; + last_token = &token_buffer[2]; + + action = errorState; + goto _Lcheck_token; + } + } + + for (int tk = 1; tk < TERMINAL_COUNT; ++tk) { + if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM || + tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION || + tk == T_FEED_JS_SOURCE_ELEMENT) + continue; + + int a = t_action(errorState, tk); + if (a > 0 && t_action(a, yytoken)) { + const QString msg = qApp->translate("QDeclarativeParser", "Expected token `%1'").arg(QLatin1String(spell[tk])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + yytoken = tk; + yylval = 0; + yylloc = token_buffer[0].loc; + yylloc.length = 0; + + action = errorState; + goto _Lcheck_token; + } + } + + const QString msg = qApp->translate("QDeclarativeParser", "Syntax error"); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + } + + return false; +} + +QT_QML_END_NAMESPACE + + +./ +/: +QT_QML_END_NAMESPACE + + + +#endif // QDECLARATIVEJSPARSER_P_H +:/ diff --git a/src/declarative/qml/parser/qdeclarativejsast.cpp b/src/declarative/qml/parser/qdeclarativejsast.cpp new file mode 100644 index 00000000..ad79dddd --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsast.cpp @@ -0,0 +1,956 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativejsast_p.h" + +#include "private/qdeclarativejsastvisitor_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { namespace AST { + +void Node::accept(Visitor *visitor) +{ + if (visitor->preVisit(this)) { + accept0(visitor); + } + visitor->postVisit(this); +} + +void Node::accept(Node *node, Visitor *visitor) +{ + if (node) + node->accept(visitor); +} + +ExpressionNode *Node::expressionCast() +{ + return 0; +} + +BinaryExpression *Node::binaryExpressionCast() +{ + return 0; +} + +Statement *Node::statementCast() +{ + return 0; +} + +UiObjectMember *Node::uiObjectMemberCast() +{ + return 0; +} + +ExpressionNode *ExpressionNode::expressionCast() +{ + return this; +} + +BinaryExpression *BinaryExpression::binaryExpressionCast() +{ + return this; +} + +Statement *Statement::statementCast() +{ + return this; +} + +UiObjectMember *UiObjectMember::uiObjectMemberCast() +{ + return this; +} + +void NestedExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + visitor->endVisit(this); +} + +void ThisExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void IdentifierExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void NullExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void TrueLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void FalseLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void StringLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void NumericLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void RegExpLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void ArrayLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(elements, visitor); + accept(elision, visitor); + } + + visitor->endVisit(this); +} + +void ObjectLiteral::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(properties, visitor); + } + + visitor->endVisit(this); +} + +void ElementList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (ElementList *it = this; it; it = it->next) { + accept(it->elision, visitor); + accept(it->expression, visitor); + } + } + + visitor->endVisit(this); +} + +void Elision::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + // ### + } + + visitor->endVisit(this); +} + +void PropertyNameAndValueList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (PropertyNameAndValueList *it = this; it; it = it->next) { + accept(it->name, visitor); + accept(it->value, visitor); + } + } + + visitor->endVisit(this); +} + +void IdentifierPropertyName::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void StringLiteralPropertyName::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void NumericLiteralPropertyName::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void ArrayMemberExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void FieldMemberExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + } + + visitor->endVisit(this); +} + +void NewMemberExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + accept(arguments, visitor); + } + + visitor->endVisit(this); +} + +void NewExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void CallExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + accept(arguments, visitor); + } + + visitor->endVisit(this); +} + +void ArgumentList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (ArgumentList *it = this; it; it = it->next) { + accept(it->expression, visitor); + } + } + + visitor->endVisit(this); +} + +void PostIncrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + } + + visitor->endVisit(this); +} + +void PostDecrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(base, visitor); + } + + visitor->endVisit(this); +} + +void DeleteExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void VoidExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void TypeOfExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void PreIncrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void PreDecrementExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void UnaryPlusExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void UnaryMinusExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void TildeExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void NotExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void BinaryExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(left, visitor); + accept(right, visitor); + } + + visitor->endVisit(this); +} + +void ConditionalExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(ok, visitor); + accept(ko, visitor); + } + + visitor->endVisit(this); +} + +void Expression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(left, visitor); + accept(right, visitor); + } + + visitor->endVisit(this); +} + +void Block::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statements, visitor); + } + + visitor->endVisit(this); +} + +void StatementList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (StatementList *it = this; it; it = it->next) { + accept(it->statement, visitor); + } + } + + visitor->endVisit(this); +} + +void VariableStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(declarations, visitor); + } + + visitor->endVisit(this); +} + +void VariableDeclarationList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (VariableDeclarationList *it = this; it; it = it->next) { + accept(it->declaration, visitor); + } + } + + visitor->endVisit(this); +} + +void VariableDeclaration::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void EmptyStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void ExpressionStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void IfStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(ok, visitor); + accept(ko, visitor); + } + + visitor->endVisit(this); +} + +void DoWhileStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void WhileStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void ForStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(initialiser, visitor); + accept(condition, visitor); + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void LocalForStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(declarations, visitor); + accept(condition, visitor); + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void ForEachStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(initialiser, visitor); + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void LocalForEachStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(declaration, visitor); + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void ContinueStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void BreakStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void ReturnStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void WithStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void SwitchStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(block, visitor); + } + + visitor->endVisit(this); +} + +void CaseBlock::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(clauses, visitor); + accept(defaultClause, visitor); + accept(moreClauses, visitor); + } + + visitor->endVisit(this); +} + +void CaseClauses::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (CaseClauses *it = this; it; it = it->next) { + accept(it->clause, visitor); + } + } + + visitor->endVisit(this); +} + +void CaseClause::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(statements, visitor); + } + + visitor->endVisit(this); +} + +void DefaultClause::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statements, visitor); + } + + visitor->endVisit(this); +} + +void LabelledStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void ThrowStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + } + + visitor->endVisit(this); +} + +void TryStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + accept(catchExpression, visitor); + accept(finallyExpression, visitor); + } + + visitor->endVisit(this); +} + +void Catch::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void Finally::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void FunctionDeclaration::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(formals, visitor); + accept(body, visitor); + } + + visitor->endVisit(this); +} + +void FunctionExpression::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(formals, visitor); + accept(body, visitor); + } + + visitor->endVisit(this); +} + +void FormalParameterList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + // ### + } + + visitor->endVisit(this); +} + +void FunctionBody::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(elements, visitor); + } + + visitor->endVisit(this); +} + +void Program::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(elements, visitor); + } + + visitor->endVisit(this); +} + +void SourceElements::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (SourceElements *it = this; it; it = it->next) { + accept(it->element, visitor); + } + } + + visitor->endVisit(this); +} + +void FunctionSourceElement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(declaration, visitor); + } + + visitor->endVisit(this); +} + +void StatementSourceElement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void DebuggerStatement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void UiProgram::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(imports, visitor); + accept(members, visitor); + } + + visitor->endVisit(this); +} + +void UiSignature::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(formals, visitor); + } + visitor->endVisit(this); +} + +void UiFormalList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (UiFormalList *it = this; it; it = it->next) { + accept(it->formal, visitor); + } + } + visitor->endVisit(this); +} + +void UiFormal::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + visitor->endVisit(this); +} + +void UiPublicMember::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(expression, visitor); + accept(binding, visitor); + } + + visitor->endVisit(this); +} + +void UiObjectDefinition::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(qualifiedTypeNameId, visitor); + accept(initializer, visitor); + } + + visitor->endVisit(this); +} + +void UiObjectInitializer::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(members, visitor); + } + + visitor->endVisit(this); +} + +void UiObjectBinding::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(qualifiedId, visitor); + accept(qualifiedTypeNameId, visitor); + accept(initializer, visitor); + } + + visitor->endVisit(this); +} + +void UiScriptBinding::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(qualifiedId, visitor); + accept(statement, visitor); + } + + visitor->endVisit(this); +} + +void UiArrayBinding::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(qualifiedId, visitor); + accept(members, visitor); + } + + visitor->endVisit(this); +} + +void UiObjectMemberList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (UiObjectMemberList *it = this; it; it = it->next) + accept(it->member, visitor); + } + + visitor->endVisit(this); +} + +void UiArrayMemberList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (UiArrayMemberList *it = this; it; it = it->next) + accept(it->member, visitor); + } + + visitor->endVisit(this); +} + +void UiQualifiedId::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + +void UiImport::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(importUri, visitor); + } + + visitor->endVisit(this); +} + +void UiImportList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(import, visitor); + accept(next, visitor); + } + + visitor->endVisit(this); +} + +void UiSourceElement::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(sourceElement, visitor); + } + + visitor->endVisit(this); +} + +} } // namespace QDeclarativeJS::AST + +QT_QML_END_NAMESPACE + + diff --git a/src/declarative/qml/parser/qdeclarativejsast_p.h b/src/declarative/qml/parser/qdeclarativejsast_p.h new file mode 100644 index 00000000..07ce3e09 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsast_p.h @@ -0,0 +1,2546 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEJSAST_P_H +#define QDECLARATIVEJSAST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativejsastvisitor_p.h" +#include "private/qdeclarativejsglobal_p.h" + +#include <QtCore/QString> + +QT_QML_BEGIN_NAMESPACE + +#define QDECLARATIVEJS_DECLARE_AST_NODE(name) \ + enum { K = Kind_##name }; + +namespace QSOperator // ### rename +{ + +enum Op { + Add, + And, + InplaceAnd, + Assign, + BitAnd, + BitOr, + BitXor, + InplaceSub, + Div, + InplaceDiv, + Equal, + Ge, + Gt, + In, + InplaceAdd, + InstanceOf, + Le, + LShift, + InplaceLeftShift, + Lt, + Mod, + InplaceMod, + Mul, + InplaceMul, + NotEqual, + Or, + InplaceOr, + RShift, + InplaceRightShift, + StrictEqual, + StrictNotEqual, + Sub, + URShift, + InplaceURightShift, + InplaceXor +}; + +} // namespace QSOperator + +namespace QDeclarativeJS { +class NameId; +namespace AST { + +template <typename _T1, typename _T2> +_T1 cast(_T2 *ast) +{ + if (ast && ast->kind == static_cast<_T1>(0)->K) + return static_cast<_T1>(ast); + + return 0; +} + +class QML_PARSER_EXPORT Node +{ +public: + enum Kind { + Kind_Undefined, + + Kind_ArgumentList, + Kind_ArrayLiteral, + Kind_ArrayMemberExpression, + Kind_BinaryExpression, + Kind_Block, + Kind_BreakStatement, + Kind_CallExpression, + Kind_CaseBlock, + Kind_CaseClause, + Kind_CaseClauses, + Kind_Catch, + Kind_ConditionalExpression, + Kind_ContinueStatement, + Kind_DebuggerStatement, + Kind_DefaultClause, + Kind_DeleteExpression, + Kind_DoWhileStatement, + Kind_ElementList, + Kind_Elision, + Kind_EmptyStatement, + Kind_Expression, + Kind_ExpressionStatement, + Kind_FalseLiteral, + Kind_FieldMemberExpression, + Kind_Finally, + Kind_ForEachStatement, + Kind_ForStatement, + Kind_FormalParameterList, + Kind_FunctionBody, + Kind_FunctionDeclaration, + Kind_FunctionExpression, + Kind_FunctionSourceElement, + Kind_IdentifierExpression, + Kind_IdentifierPropertyName, + Kind_IfStatement, + Kind_LabelledStatement, + Kind_LocalForEachStatement, + Kind_LocalForStatement, + Kind_NewExpression, + Kind_NewMemberExpression, + Kind_NotExpression, + Kind_NullExpression, + Kind_NumericLiteral, + Kind_NumericLiteralPropertyName, + Kind_ObjectLiteral, + Kind_PostDecrementExpression, + Kind_PostIncrementExpression, + Kind_PreDecrementExpression, + Kind_PreIncrementExpression, + Kind_Program, + Kind_PropertyName, + Kind_PropertyNameAndValueList, + Kind_RegExpLiteral, + Kind_ReturnStatement, + Kind_SourceElement, + Kind_SourceElements, + Kind_StatementList, + Kind_StatementSourceElement, + Kind_StringLiteral, + Kind_StringLiteralPropertyName, + Kind_SwitchStatement, + Kind_ThisExpression, + Kind_ThrowStatement, + Kind_TildeExpression, + Kind_TrueLiteral, + Kind_TryStatement, + Kind_TypeOfExpression, + Kind_UnaryMinusExpression, + Kind_UnaryPlusExpression, + Kind_VariableDeclaration, + Kind_VariableDeclarationList, + Kind_VariableStatement, + Kind_VoidExpression, + Kind_WhileStatement, + Kind_WithStatement, + Kind_NestedExpression, + + Kind_UiArrayBinding, + Kind_UiImport, + Kind_UiImportList, + Kind_UiObjectBinding, + Kind_UiObjectDefinition, + Kind_UiObjectInitializer, + Kind_UiObjectMemberList, + Kind_UiArrayMemberList, + Kind_UiProgram, + Kind_UiParameterList, + Kind_UiPublicMember, + Kind_UiQualifiedId, + Kind_UiScriptBinding, + Kind_UiSourceElement, + Kind_UiFormal, + Kind_UiFormalList, + Kind_UiSignature + }; + + inline Node() + : kind(Kind_Undefined) {} + + // NOTE: node destructors are never called, + // instead we block free the memory + // (see the NodePool class) + virtual ~Node() {} + + virtual ExpressionNode *expressionCast(); + virtual BinaryExpression *binaryExpressionCast(); + virtual Statement *statementCast(); + virtual UiObjectMember *uiObjectMemberCast(); + + void accept(Visitor *visitor); + static void accept(Node *node, Visitor *visitor); + + inline static void acceptChild(Node *node, Visitor *visitor) + { return accept(node, visitor); } // ### remove + + virtual void accept0(Visitor *visitor) = 0; + +// attributes + int kind; +}; + +class QML_PARSER_EXPORT ExpressionNode: public Node +{ +public: + ExpressionNode() {} + + virtual ExpressionNode *expressionCast(); + + virtual SourceLocation firstSourceLocation() const = 0; + virtual SourceLocation lastSourceLocation() const = 0; +}; + +class QML_PARSER_EXPORT Statement: public Node +{ +public: + Statement() {} + + virtual Statement *statementCast(); + + virtual SourceLocation firstSourceLocation() const = 0; + virtual SourceLocation lastSourceLocation() const = 0; +}; + +class QML_PARSER_EXPORT UiFormal: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiFormal) + + UiFormal(NameId *name, NameId *alias = 0) + : name(name), alias(alias) + { } + + virtual SourceLocation firstSourceLocation() const + { return SourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return SourceLocation(); } + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *name; + NameId *alias; + SourceLocation identifierToken; + SourceLocation asToken; + SourceLocation aliasToken; +}; + +class QML_PARSER_EXPORT UiFormalList: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiFormalList) + + UiFormalList(UiFormal *formal) + : formal(formal), next(this) {} + + UiFormalList(UiFormalList *previous, UiFormal *formal) + : formal(formal) + { + next = previous->next; + previous->next = this; + } + + UiFormalList *finish() + { + UiFormalList *head = next; + next = 0; + return head; + } + + virtual SourceLocation firstSourceLocation() const + { return SourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return SourceLocation(); } + + virtual void accept0(Visitor *visitor); + +// attributes + UiFormal *formal; + UiFormalList *next; +}; + +class QML_PARSER_EXPORT UiSignature: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiSignature) + + UiSignature(UiFormalList *formals = 0) + : formals(formals) + { } + + virtual SourceLocation firstSourceLocation() const + { return SourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return SourceLocation(); } + + virtual void accept0(Visitor *visitor); + +// attributes + SourceLocation lparenToken; + UiFormalList *formals; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT NestedExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(NestedExpression) + + NestedExpression(ExpressionNode *expression) + : expression(expression) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return lparenToken; } + + virtual SourceLocation lastSourceLocation() const + { return rparenToken; } + +// attributes + ExpressionNode *expression; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT ThisExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ThisExpression) + + ThisExpression() { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return thisToken; } + + virtual SourceLocation lastSourceLocation() const + { return thisToken; } + +// attributes + SourceLocation thisToken; +}; + +class QML_PARSER_EXPORT IdentifierExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(IdentifierExpression) + + IdentifierExpression(NameId *n): + name (n) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return identifierToken; } + +// attributes + NameId *name; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT NullExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(NullExpression) + + NullExpression() { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return nullToken; } + + virtual SourceLocation lastSourceLocation() const + { return nullToken; } + +// attributes + SourceLocation nullToken; +}; + +class QML_PARSER_EXPORT TrueLiteral: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(TrueLiteral) + + TrueLiteral() { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return trueToken; } + + virtual SourceLocation lastSourceLocation() const + { return trueToken; } + +// attributes + SourceLocation trueToken; +}; + +class QML_PARSER_EXPORT FalseLiteral: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(FalseLiteral) + + FalseLiteral() { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return falseToken; } + + virtual SourceLocation lastSourceLocation() const + { return falseToken; } + +// attributes + SourceLocation falseToken; +}; + +class QML_PARSER_EXPORT NumericLiteral: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(NumericLiteral) + + NumericLiteral(double v): + value(v) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return literalToken; } + + virtual SourceLocation lastSourceLocation() const + { return literalToken; } + +// attributes: + double value; + SourceLocation literalToken; +}; + +class QML_PARSER_EXPORT StringLiteral: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(StringLiteral) + + StringLiteral(NameId *v): + value (v) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return literalToken; } + + virtual SourceLocation lastSourceLocation() const + { return literalToken; } + +// attributes: + NameId *value; + SourceLocation literalToken; +}; + +class QML_PARSER_EXPORT RegExpLiteral: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(RegExpLiteral) + + RegExpLiteral(NameId *p, int f): + pattern (p), flags (f) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return literalToken; } + + virtual SourceLocation lastSourceLocation() const + { return literalToken; } + +// attributes: + NameId *pattern; + int flags; + SourceLocation literalToken; +}; + +class QML_PARSER_EXPORT ArrayLiteral: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ArrayLiteral) + + ArrayLiteral(Elision *e): + elements (0), elision (e) + { kind = K; } + + ArrayLiteral(ElementList *elts): + elements (elts), elision (0) + { kind = K; } + + ArrayLiteral(ElementList *elts, Elision *e): + elements (elts), elision (e) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return lbracketToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbracketToken; } + +// attributes + ElementList *elements; + Elision *elision; + SourceLocation lbracketToken; + SourceLocation commaToken; + SourceLocation rbracketToken; +}; + +class QML_PARSER_EXPORT ObjectLiteral: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ObjectLiteral) + + ObjectLiteral(): + properties (0) { kind = K; } + + ObjectLiteral(PropertyNameAndValueList *plist): + properties (plist) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return lbraceToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbraceToken; } + +// attributes + PropertyNameAndValueList *properties; + SourceLocation lbraceToken; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT ElementList: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ElementList) + + ElementList(Elision *e, ExpressionNode *expr): + elision (e), expression (expr), next (this) + { kind = K; } + + ElementList(ElementList *previous, Elision *e, ExpressionNode *expr): + elision (e), expression (expr) + { + kind = K; + next = previous->next; + previous->next = this; + } + + inline ElementList *finish () + { + ElementList *front = next; + next = 0; + return front; + } + + virtual void accept0(Visitor *visitor); + +// attributes + Elision *elision; + ExpressionNode *expression; + ElementList *next; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT Elision: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(Elision) + + Elision(): + next (this) { kind = K; } + + Elision(Elision *previous) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + inline Elision *finish () + { + Elision *front = next; + next = 0; + return front; + } + +// attributes + Elision *next; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT PropertyNameAndValueList: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(PropertyNameAndValueList) + + PropertyNameAndValueList(PropertyName *n, ExpressionNode *v): + name (n), value (v), next (this) + { kind = K; } + + PropertyNameAndValueList(PropertyNameAndValueList *previous, PropertyName *n, ExpressionNode *v): + name (n), value (v) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + inline PropertyNameAndValueList *finish () + { + PropertyNameAndValueList *front = next; + next = 0; + return front; + } + +// attributes + PropertyName *name; + ExpressionNode *value; + PropertyNameAndValueList *next; + SourceLocation colonToken; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT PropertyName: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(PropertyName) + + PropertyName() { kind = K; } + +// attributes + SourceLocation propertyNameToken; +}; + +class QML_PARSER_EXPORT IdentifierPropertyName: public PropertyName +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(IdentifierPropertyName) + + IdentifierPropertyName(NameId *n): + id (n) { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *id; +}; + +class QML_PARSER_EXPORT StringLiteralPropertyName: public PropertyName +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(StringLiteralPropertyName) + + StringLiteralPropertyName(NameId *n): + id (n) { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *id; +}; + +class QML_PARSER_EXPORT NumericLiteralPropertyName: public PropertyName +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(NumericLiteralPropertyName) + + NumericLiteralPropertyName(double n): + id (n) { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + double id; +}; + +class QML_PARSER_EXPORT ArrayMemberExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ArrayMemberExpression) + + ArrayMemberExpression(ExpressionNode *b, ExpressionNode *e): + base (b), expression (e) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return base->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return rbracketToken; } + +// attributes + ExpressionNode *base; + ExpressionNode *expression; + SourceLocation lbracketToken; + SourceLocation rbracketToken; +}; + +class QML_PARSER_EXPORT FieldMemberExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(FieldMemberExpression) + + FieldMemberExpression(ExpressionNode *b, NameId *n): + base (b), name (n) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return base->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return identifierToken; } + + // attributes + ExpressionNode *base; + NameId *name; + SourceLocation dotToken; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT NewMemberExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(NewMemberExpression) + + NewMemberExpression(ExpressionNode *b, ArgumentList *a): + base (b), arguments (a) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return newToken; } + + virtual SourceLocation lastSourceLocation() const + { return rparenToken; } + + // attributes + ExpressionNode *base; + ArgumentList *arguments; + SourceLocation newToken; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT NewExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(NewExpression) + + NewExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return newToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation newToken; +}; + +class QML_PARSER_EXPORT CallExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(CallExpression) + + CallExpression(ExpressionNode *b, ArgumentList *a): + base (b), arguments (a) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return base->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return rparenToken; } + +// attributes + ExpressionNode *base; + ArgumentList *arguments; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT ArgumentList: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ArgumentList) + + ArgumentList(ExpressionNode *e): + expression (e), next (this) + { kind = K; } + + ArgumentList(ArgumentList *previous, ExpressionNode *e): + expression (e) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + inline ArgumentList *finish () + { + ArgumentList *front = next; + next = 0; + return front; + } + +// attributes + ExpressionNode *expression; + ArgumentList *next; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT PostIncrementExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(PostIncrementExpression) + + PostIncrementExpression(ExpressionNode *b): + base (b) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return base->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return incrementToken; } + +// attributes + ExpressionNode *base; + SourceLocation incrementToken; +}; + +class QML_PARSER_EXPORT PostDecrementExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(PostDecrementExpression) + + PostDecrementExpression(ExpressionNode *b): + base (b) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return base->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return decrementToken; } + +// attributes + ExpressionNode *base; + SourceLocation decrementToken; +}; + +class QML_PARSER_EXPORT DeleteExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(DeleteExpression) + + DeleteExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return deleteToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation deleteToken; +}; + +class QML_PARSER_EXPORT VoidExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(VoidExpression) + + VoidExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return voidToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation voidToken; +}; + +class QML_PARSER_EXPORT TypeOfExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(TypeOfExpression) + + TypeOfExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return typeofToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation typeofToken; +}; + +class QML_PARSER_EXPORT PreIncrementExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(PreIncrementExpression) + + PreIncrementExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return incrementToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation incrementToken; +}; + +class QML_PARSER_EXPORT PreDecrementExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(PreDecrementExpression) + + PreDecrementExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return decrementToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation decrementToken; +}; + +class QML_PARSER_EXPORT UnaryPlusExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UnaryPlusExpression) + + UnaryPlusExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return plusToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation plusToken; +}; + +class QML_PARSER_EXPORT UnaryMinusExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UnaryMinusExpression) + + UnaryMinusExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return minusToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation minusToken; +}; + +class QML_PARSER_EXPORT TildeExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(TildeExpression) + + TildeExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return tildeToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation tildeToken; +}; + +class QML_PARSER_EXPORT NotExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(NotExpression) + + NotExpression(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return notToken; } + + virtual SourceLocation lastSourceLocation() const + { return expression->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + SourceLocation notToken; +}; + +class QML_PARSER_EXPORT BinaryExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(BinaryExpression) + + BinaryExpression(ExpressionNode *l, int o, ExpressionNode *r): + left (l), op (o), right (r) + { kind = K; } + + virtual BinaryExpression *binaryExpressionCast(); + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return left->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return right->lastSourceLocation(); } + +// attributes + ExpressionNode *left; + int op; + ExpressionNode *right; + SourceLocation operatorToken; +}; + +class QML_PARSER_EXPORT ConditionalExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ConditionalExpression) + + ConditionalExpression(ExpressionNode *e, ExpressionNode *t, ExpressionNode *f): + expression (e), ok (t), ko (f) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return expression->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return ko->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + ExpressionNode *ok; + ExpressionNode *ko; + SourceLocation questionToken; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT Expression: public ExpressionNode // ### rename +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(Expression) + + Expression(ExpressionNode *l, ExpressionNode *r): + left (l), right (r) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return left->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return right->lastSourceLocation(); } + +// attributes + ExpressionNode *left; + ExpressionNode *right; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT Block: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(Block) + + Block(StatementList *slist): + statements (slist) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return lbraceToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbraceToken; } + + // attributes + StatementList *statements; + SourceLocation lbraceToken; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT StatementList: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(StatementList) + + StatementList(Statement *stmt): + statement (stmt), next (this) + { kind = K; } + + StatementList(StatementList *previous, Statement *stmt): + statement (stmt) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + inline StatementList *finish () + { + StatementList *front = next; + next = 0; + return front; + } + +// attributes + Statement *statement; + StatementList *next; +}; + +class QML_PARSER_EXPORT VariableStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(VariableStatement) + + VariableStatement(VariableDeclarationList *vlist): + declarations (vlist) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return declarationKindToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + VariableDeclarationList *declarations; + SourceLocation declarationKindToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT VariableDeclaration: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(VariableDeclaration) + + VariableDeclaration(NameId *n, ExpressionNode *e): + name (n), expression (e), readOnly(false) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *name; + ExpressionNode *expression; + bool readOnly; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT VariableDeclarationList: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(VariableDeclarationList) + + VariableDeclarationList(VariableDeclaration *decl): + declaration (decl), next (this) + { kind = K; } + + VariableDeclarationList(VariableDeclarationList *previous, VariableDeclaration *decl): + declaration (decl) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + inline VariableDeclarationList *finish (bool readOnly) + { + VariableDeclarationList *front = next; + next = 0; + if (readOnly) { + VariableDeclarationList *vdl; + for (vdl = front; vdl != 0; vdl = vdl->next) + vdl->declaration->readOnly = true; + } + return front; + } + +// attributes + VariableDeclaration *declaration; + VariableDeclarationList *next; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT EmptyStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(EmptyStatement) + + EmptyStatement() { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return semicolonToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT ExpressionStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ExpressionStatement) + + ExpressionStatement(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return expression->firstSourceLocation(); } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + ExpressionNode *expression; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT IfStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(IfStatement) + + IfStatement(ExpressionNode *e, Statement *t, Statement *f = 0): + expression (e), ok (t), ko (f) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return ifToken; } + + virtual SourceLocation lastSourceLocation() const + { + if (ko) + return ko->lastSourceLocation(); + + return ok->lastSourceLocation(); + } + +// attributes + ExpressionNode *expression; + Statement *ok; + Statement *ko; + SourceLocation ifToken; + SourceLocation lparenToken; + SourceLocation rparenToken; + SourceLocation elseToken; +}; + +class QML_PARSER_EXPORT DoWhileStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(DoWhileStatement) + + DoWhileStatement(Statement *stmt, ExpressionNode *e): + statement (stmt), expression (e) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return doToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + Statement *statement; + ExpressionNode *expression; + SourceLocation doToken; + SourceLocation whileToken; + SourceLocation lparenToken; + SourceLocation rparenToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT WhileStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(WhileStatement) + + WhileStatement(ExpressionNode *e, Statement *stmt): + expression (e), statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return whileToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + Statement *statement; + SourceLocation whileToken; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT ForStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ForStatement) + + ForStatement(ExpressionNode *i, ExpressionNode *c, ExpressionNode *e, Statement *stmt): + initialiser (i), condition (c), expression (e), statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return forToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + ExpressionNode *initialiser; + ExpressionNode *condition; + ExpressionNode *expression; + Statement *statement; + SourceLocation forToken; + SourceLocation lparenToken; + SourceLocation firstSemicolonToken; + SourceLocation secondSemicolonToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT LocalForStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(LocalForStatement) + + LocalForStatement(VariableDeclarationList *vlist, ExpressionNode *c, ExpressionNode *e, Statement *stmt): + declarations (vlist), condition (c), expression (e), statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return forToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + VariableDeclarationList *declarations; + ExpressionNode *condition; + ExpressionNode *expression; + Statement *statement; + SourceLocation forToken; + SourceLocation lparenToken; + SourceLocation varToken; + SourceLocation firstSemicolonToken; + SourceLocation secondSemicolonToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT ForEachStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ForEachStatement) + + ForEachStatement(ExpressionNode *i, ExpressionNode *e, Statement *stmt): + initialiser (i), expression (e), statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return forToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + ExpressionNode *initialiser; + ExpressionNode *expression; + Statement *statement; + SourceLocation forToken; + SourceLocation lparenToken; + SourceLocation inToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT LocalForEachStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(LocalForEachStatement) + + LocalForEachStatement(VariableDeclaration *v, ExpressionNode *e, Statement *stmt): + declaration (v), expression (e), statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return forToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + VariableDeclaration *declaration; + ExpressionNode *expression; + Statement *statement; + SourceLocation forToken; + SourceLocation lparenToken; + SourceLocation varToken; + SourceLocation inToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT ContinueStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ContinueStatement) + + ContinueStatement(NameId *l = 0): + label (l) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return continueToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + NameId *label; + SourceLocation continueToken; + SourceLocation identifierToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT BreakStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(BreakStatement) + + BreakStatement(NameId *l = 0): + label (l) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return breakToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + + // attributes + NameId *label; + SourceLocation breakToken; + SourceLocation identifierToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT ReturnStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ReturnStatement) + + ReturnStatement(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return returnToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + ExpressionNode *expression; + SourceLocation returnToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT WithStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(WithStatement) + + WithStatement(ExpressionNode *e, Statement *stmt): + expression (e), statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return withToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + ExpressionNode *expression; + Statement *statement; + SourceLocation withToken; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT CaseBlock: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(CaseBlock) + + CaseBlock(CaseClauses *c, DefaultClause *d = 0, CaseClauses *r = 0): + clauses (c), defaultClause (d), moreClauses (r) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + CaseClauses *clauses; + DefaultClause *defaultClause; + CaseClauses *moreClauses; + SourceLocation lbraceToken; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT SwitchStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(SwitchStatement) + + SwitchStatement(ExpressionNode *e, CaseBlock *b): + expression (e), block (b) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return switchToken; } + + virtual SourceLocation lastSourceLocation() const + { return block->rbraceToken; } + +// attributes + ExpressionNode *expression; + CaseBlock *block; + SourceLocation switchToken; + SourceLocation lparenToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT CaseClauses: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(CaseClauses) + + CaseClauses(CaseClause *c): + clause (c), next (this) + { kind = K; } + + CaseClauses(CaseClauses *previous, CaseClause *c): + clause (c) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + inline CaseClauses *finish () + { + CaseClauses *front = next; + next = 0; + return front; + } + +//attributes + CaseClause *clause; + CaseClauses *next; +}; + +class QML_PARSER_EXPORT CaseClause: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(CaseClause) + + CaseClause(ExpressionNode *e, StatementList *slist): + expression (e), statements (slist) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + ExpressionNode *expression; + StatementList *statements; + SourceLocation caseToken; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT DefaultClause: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(DefaultClause) + + DefaultClause(StatementList *slist): + statements (slist) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + StatementList *statements; + SourceLocation defaultToken; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT LabelledStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(LabelledStatement) + + LabelledStatement(NameId *l, Statement *stmt): + label (l), statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + +// attributes + NameId *label; + Statement *statement; + SourceLocation identifierToken; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT ThrowStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(ThrowStatement) + + ThrowStatement(ExpressionNode *e): + expression (e) { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return throwToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + + // attributes + ExpressionNode *expression; + SourceLocation throwToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT Catch: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(Catch) + + Catch(NameId *n, Block *stmt): + name (n), statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *name; + Block *statement; + SourceLocation catchToken; + SourceLocation lparenToken; + SourceLocation identifierToken; + SourceLocation rparenToken; +}; + +class QML_PARSER_EXPORT Finally: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(Finally) + + Finally(Block *stmt): + statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + Block *statement; + SourceLocation finallyToken; +}; + +class QML_PARSER_EXPORT TryStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(TryStatement) + + TryStatement(Statement *stmt, Catch *c, Finally *f): + statement (stmt), catchExpression (c), finallyExpression (f) + { kind = K; } + + TryStatement(Statement *stmt, Finally *f): + statement (stmt), catchExpression (0), finallyExpression (f) + { kind = K; } + + TryStatement(Statement *stmt, Catch *c): + statement (stmt), catchExpression (c), finallyExpression (0) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return tryToken; } + + virtual SourceLocation lastSourceLocation() const + { + if (finallyExpression) + return finallyExpression->statement->rbraceToken; + else if (catchExpression) + return catchExpression->statement->rbraceToken; + + return statement->lastSourceLocation(); + } + +// attributes + Statement *statement; + Catch *catchExpression; + Finally *finallyExpression; + SourceLocation tryToken; +}; + +class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(FunctionExpression) + + FunctionExpression(NameId *n, FormalParameterList *f, FunctionBody *b): + name (n), formals (f), body (b) + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return functionToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbraceToken; } + +// attributes + NameId *name; + FormalParameterList *formals; + FunctionBody *body; + SourceLocation functionToken; + SourceLocation identifierToken; + SourceLocation lparenToken; + SourceLocation rparenToken; + SourceLocation lbraceToken; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(FunctionDeclaration) + + FunctionDeclaration(NameId *n, FormalParameterList *f, FunctionBody *b): + FunctionExpression(n, f, b) + { kind = K; } + + virtual void accept0(Visitor *visitor); +}; + +class QML_PARSER_EXPORT FormalParameterList: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(FormalParameterList) + + FormalParameterList(NameId *n): + name (n), next (this) + { kind = K; } + + FormalParameterList(FormalParameterList *previous, NameId *n): + name (n) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + inline FormalParameterList *finish () + { + FormalParameterList *front = next; + next = 0; + return front; + } + +// attributes + NameId *name; + FormalParameterList *next; + SourceLocation commaToken; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT FunctionBody: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(FunctionBody) + + FunctionBody(SourceElements *elts): + elements (elts) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + SourceElements *elements; +}; + +class QML_PARSER_EXPORT Program: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(Program) + + Program(SourceElements *elts): + elements (elts) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + SourceElements *elements; +}; + +class QML_PARSER_EXPORT SourceElements: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(SourceElements) + + SourceElements(SourceElement *elt): + element (elt), next (this) + { kind = K; } + + SourceElements(SourceElements *previous, SourceElement *elt): + element (elt) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + inline SourceElements *finish () + { + SourceElements *front = next; + next = 0; + return front; + } + +// attributes + SourceElement *element; + SourceElements *next; +}; + +class QML_PARSER_EXPORT SourceElement: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(SourceElement) + + inline SourceElement() + { kind = K; } +}; + +class QML_PARSER_EXPORT FunctionSourceElement: public SourceElement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(FunctionSourceElement) + + FunctionSourceElement(FunctionDeclaration *f): + declaration (f) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + FunctionDeclaration *declaration; +}; + +class QML_PARSER_EXPORT StatementSourceElement: public SourceElement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(StatementSourceElement) + + StatementSourceElement(Statement *stmt): + statement (stmt) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + Statement *statement; +}; + +class QML_PARSER_EXPORT DebuggerStatement: public Statement +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(DebuggerStatement) + + DebuggerStatement() + { kind = K; } + + virtual void accept0(Visitor *visitor); + + virtual SourceLocation firstSourceLocation() const + { return debuggerToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + +// attributes + SourceLocation debuggerToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT UiProgram: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiProgram) + + UiProgram(UiImportList *imports, UiObjectMemberList *members) + : imports(imports), members(members) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + UiImportList *imports; + UiObjectMemberList *members; +}; + +class QML_PARSER_EXPORT UiQualifiedId: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiQualifiedId) + + UiQualifiedId(NameId *name) + : next(this), name(name) + { kind = K; } + + UiQualifiedId(UiQualifiedId *previous, NameId *name) + : name(name) + { + kind = K; + next = previous->next; + previous->next = this; + } + + UiQualifiedId *finish() + { + UiQualifiedId *head = next; + next = 0; + return head; + } + + virtual void accept0(Visitor *visitor); + +// attributes + UiQualifiedId *next; + NameId *name; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT UiImport: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiImport) + + UiImport(NameId *fileName) + : fileName(fileName), importUri(0), importId(0) + { kind = K; } + + UiImport(UiQualifiedId *uri) + : fileName(0), importUri(uri), importId(0) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { return importToken; } + + virtual SourceLocation lastSourceLocation() const + { return semicolonToken; } + + virtual void accept0(Visitor *visitor); + +// attributes + NameId *fileName; + UiQualifiedId *importUri; + NameId *importId; + SourceLocation importToken; + SourceLocation fileNameToken; + SourceLocation versionToken; + SourceLocation asToken; + SourceLocation importIdToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT UiImportList: public Node +{ +public: + QDECLARATIVEJS_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; + } + + virtual SourceLocation firstSourceLocation() const + { + if (import) return import->firstSourceLocation(); + else return SourceLocation(); + } + + virtual SourceLocation lastSourceLocation() const + { + for (const UiImportList *it = this; it; it = it->next) + if (!it->next && it->import) + return it->import->lastSourceLocation(); + + return SourceLocation(); + } + + UiImportList *finish() + { + UiImportList *head = next; + next = 0; + return head; + } + + virtual void accept0(Visitor *visitor); + +// attributes + UiImport *import; + UiImportList *next; +}; + +class QML_PARSER_EXPORT UiObjectMember: public Node +{ +public: + virtual SourceLocation firstSourceLocation() const = 0; + virtual SourceLocation lastSourceLocation() const = 0; + + virtual UiObjectMember *uiObjectMemberCast(); +}; + +class QML_PARSER_EXPORT UiObjectMemberList: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiObjectMemberList) + + UiObjectMemberList(UiObjectMember *member) + : next(this), member(member) + { kind = K; } + + UiObjectMemberList(UiObjectMemberList *previous, UiObjectMember *member) + : member(member) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + UiObjectMemberList *finish() + { + UiObjectMemberList *head = next; + next = 0; + return head; + } + +// attributes + UiObjectMemberList *next; + UiObjectMember *member; +}; + +class QML_PARSER_EXPORT UiArrayMemberList: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiArrayMemberList) + + UiArrayMemberList(UiObjectMember *member) + : next(this), member(member) + { kind = K; } + + UiArrayMemberList(UiArrayMemberList *previous, UiObjectMember *member) + : member(member) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *visitor); + + UiArrayMemberList *finish() + { + UiArrayMemberList *head = next; + next = 0; + return head; + } + +// attributes + UiArrayMemberList *next; + UiObjectMember *member; + SourceLocation commaToken; +}; + +class QML_PARSER_EXPORT UiObjectInitializer: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiObjectInitializer) + + UiObjectInitializer(UiObjectMemberList *members) + : members(members) + { kind = K; } + + virtual void accept0(Visitor *visitor); + +// attributes + SourceLocation lbraceToken; + UiObjectMemberList *members; + SourceLocation rbraceToken; +}; + +class QML_PARSER_EXPORT UiParameterList: public Node +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiParameterList) + + UiParameterList(NameId *t, NameId *n): + type (t), name (n), next (this) + { kind = K; } + + UiParameterList(UiParameterList *previous, NameId *t, NameId *n): + type (t), name (n) + { + kind = K; + next = previous->next; + previous->next = this; + } + + virtual void accept0(Visitor *) {} + + inline UiParameterList *finish () + { + UiParameterList *front = next; + next = 0; + return front; + } + +// attributes + NameId *type; + NameId *name; + UiParameterList *next; + SourceLocation commaToken; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiPublicMember) + + UiPublicMember(NameId *memberType, + NameId *name) + : type(Property), typeModifier(0), memberType(memberType), name(name), expression(0), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0) + { kind = K; } + + UiPublicMember(NameId *memberType, + NameId *name, + ExpressionNode *expression) + : type(Property), typeModifier(0), memberType(memberType), name(name), expression(expression), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { + if (defaultToken.isValid()) + return defaultToken; + else if (readonlyToken.isValid()) + return readonlyToken; + + return propertyToken; + } + + virtual SourceLocation lastSourceLocation() const + { + if (binding) + return binding->lastSourceLocation(); + + return semicolonToken; + } + + virtual void accept0(Visitor *visitor); + +// attributes + enum { Signal, Property } type; + NameId *typeModifier; + NameId *memberType; + NameId *name; + ExpressionNode *expression; // initialized with a JS expression + UiObjectMember *binding; // initialized with a QML object or array. + bool isDefaultMember; + bool isReadonlyMember; + UiParameterList *parameters; + SourceLocation defaultToken; + SourceLocation readonlyToken; + SourceLocation propertyToken; + SourceLocation typeModifierToken; + SourceLocation typeToken; + SourceLocation identifierToken; + SourceLocation colonToken; + SourceLocation semicolonToken; +}; + +class QML_PARSER_EXPORT UiObjectDefinition: public UiObjectMember +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiObjectDefinition) + + UiObjectDefinition(UiQualifiedId *qualifiedTypeNameId, + UiObjectInitializer *initializer) + : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { return qualifiedTypeNameId->identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return initializer->rbraceToken; } + + virtual void accept0(Visitor *visitor); + +// attributes + UiQualifiedId *qualifiedTypeNameId; + UiObjectInitializer *initializer; +}; + +class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiSourceElement) + + UiSourceElement(Node *sourceElement) + : sourceElement(sourceElement) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { + if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement)) + return funDecl->firstSourceLocation(); + else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement)) + return varStmt->firstSourceLocation(); + + return SourceLocation(); + } + + virtual SourceLocation lastSourceLocation() const + { + if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement)) + return funDecl->lastSourceLocation(); + else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement)) + return varStmt->lastSourceLocation(); + + return SourceLocation(); + } + + + virtual void accept0(Visitor *visitor); + +// attributes + Node *sourceElement; +}; + +class QML_PARSER_EXPORT UiObjectBinding: public UiObjectMember +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiObjectBinding) + + UiObjectBinding(UiQualifiedId *qualifiedId, + UiQualifiedId *qualifiedTypeNameId, + UiObjectInitializer *initializer) + : qualifiedId(qualifiedId), + qualifiedTypeNameId(qualifiedTypeNameId), + initializer(initializer), + hasOnToken(false) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { + if (hasOnToken && qualifiedTypeNameId) + return qualifiedTypeNameId->identifierToken; + + return qualifiedId->identifierToken; + } + + virtual SourceLocation lastSourceLocation() const + { return initializer->rbraceToken; } + + virtual void accept0(Visitor *visitor); + +// attributes + UiQualifiedId *qualifiedId; + UiQualifiedId *qualifiedTypeNameId; + UiObjectInitializer *initializer; + SourceLocation colonToken; + bool hasOnToken; +}; + +class QML_PARSER_EXPORT UiScriptBinding: public UiObjectMember +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiScriptBinding) + + UiScriptBinding(UiQualifiedId *qualifiedId, + Statement *statement) + : qualifiedId(qualifiedId), + statement(statement) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { return qualifiedId->identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return statement->lastSourceLocation(); } + + virtual void accept0(Visitor *visitor); + +// attributes + UiQualifiedId *qualifiedId; + Statement *statement; + SourceLocation colonToken; +}; + +class QML_PARSER_EXPORT UiArrayBinding: public UiObjectMember +{ +public: + QDECLARATIVEJS_DECLARE_AST_NODE(UiArrayBinding) + + UiArrayBinding(UiQualifiedId *qualifiedId, + UiArrayMemberList *members) + : qualifiedId(qualifiedId), + members(members) + { kind = K; } + + virtual SourceLocation firstSourceLocation() const + { return qualifiedId->identifierToken; } + + virtual SourceLocation lastSourceLocation() const + { return rbracketToken; } + + virtual void accept0(Visitor *visitor); + +// attributes + UiQualifiedId *qualifiedId; + UiArrayMemberList *members; + SourceLocation colonToken; + SourceLocation lbracketToken; + SourceLocation rbracketToken; +}; + +} } // namespace AST + + + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/parser/qdeclarativejsastfwd_p.h b/src/declarative/qml/parser/qdeclarativejsastfwd_p.h new file mode 100644 index 00000000..83cde71f --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsastfwd_p.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEJSAST_FWD_P_H +#define QDECLARATIVEJSAST_FWD_P_H + +#include "private/qdeclarativejsglobal_p.h" + +#include <QtCore/qglobal.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { namespace AST { + +class SourceLocation +{ +public: + SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0) + : offset(offset), length(length), + startLine(line), startColumn(column) + { } + + bool isValid() const { return length != 0; } + + quint32 begin() const { return offset; } + quint32 end() const { return offset + length; } + +// attributes + // ### encode + quint32 offset; + quint32 length; + quint32 startLine; + quint32 startColumn; +}; + +class Visitor; +class Node; +class ExpressionNode; +class Statement; +class ThisExpression; +class IdentifierExpression; +class NullExpression; +class TrueLiteral; +class FalseLiteral; +class NumericLiteral; +class StringLiteral; +class RegExpLiteral; +class ArrayLiteral; +class ObjectLiteral; +class ElementList; +class Elision; +class PropertyNameAndValueList; +class PropertyName; +class IdentifierPropertyName; +class StringLiteralPropertyName; +class NumericLiteralPropertyName; +class ArrayMemberExpression; +class FieldMemberExpression; +class NewMemberExpression; +class NewExpression; +class CallExpression; +class ArgumentList; +class PostIncrementExpression; +class PostDecrementExpression; +class DeleteExpression; +class VoidExpression; +class TypeOfExpression; +class PreIncrementExpression; +class PreDecrementExpression; +class UnaryPlusExpression; +class UnaryMinusExpression; +class TildeExpression; +class NotExpression; +class BinaryExpression; +class ConditionalExpression; +class Expression; // ### rename +class Block; +class StatementList; +class VariableStatement; +class VariableDeclarationList; +class VariableDeclaration; +class EmptyStatement; +class ExpressionStatement; +class IfStatement; +class DoWhileStatement; +class WhileStatement; +class ForStatement; +class LocalForStatement; +class ForEachStatement; +class LocalForEachStatement; +class ContinueStatement; +class BreakStatement; +class ReturnStatement; +class WithStatement; +class SwitchStatement; +class CaseBlock; +class CaseClauses; +class CaseClause; +class DefaultClause; +class LabelledStatement; +class ThrowStatement; +class TryStatement; +class Catch; +class Finally; +class FunctionDeclaration; +class FunctionExpression; +class FormalParameterList; +class FunctionBody; +class Program; +class SourceElements; +class SourceElement; +class FunctionSourceElement; +class StatementSourceElement; +class DebuggerStatement; +class NestedExpression; + +// ui elements +class UiProgram; +class UiImportList; +class UiImport; +class UiPublicMember; +class UiObjectDefinition; +class UiObjectInitializer; +class UiObjectBinding; +class UiScriptBinding; +class UiSourceElement; +class UiArrayBinding; +class UiObjectMember; +class UiObjectMemberList; +class UiArrayMemberList; +class UiQualifiedId; +class UiFormalList; +class UiFormal; +class UiSignature; + +} } // namespace AST + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/parser/qdeclarativejsastvisitor.cpp b/src/declarative/qml/parser/qdeclarativejsastvisitor.cpp new file mode 100644 index 00000000..c5051218 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsastvisitor.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativejsastvisitor_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { namespace AST { + +Visitor::Visitor() +{ +} + +Visitor::~Visitor() +{ +} + +} } // namespace QDeclarativeJS::AST + +QT_QML_END_NAMESPACE diff --git a/src/declarative/qml/parser/qdeclarativejsastvisitor_p.h b/src/declarative/qml/parser/qdeclarativejsastvisitor_p.h new file mode 100644 index 00000000..8d6fc616 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsastvisitor_p.h @@ -0,0 +1,335 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEJSASTVISITOR_P_H +#define QDECLARATIVEJSASTVISITOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativejsastfwd_p.h" +#include "private/qdeclarativejsglobal_p.h" + +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { namespace AST { + +class QML_PARSER_EXPORT Visitor +{ +public: + Visitor(); + virtual ~Visitor(); + + virtual bool preVisit(Node *) { return true; } + virtual void postVisit(Node *) {} + + // Ui + virtual bool visit(UiProgram *) { return true; } + virtual bool visit(UiImportList *) { return true; } + virtual bool visit(UiImport *) { return true; } + virtual bool visit(UiPublicMember *) { return true; } + virtual bool visit(UiSourceElement *) { return true; } + virtual bool visit(UiObjectDefinition *) { return true; } + virtual bool visit(UiObjectInitializer *) { return true; } + virtual bool visit(UiObjectBinding *) { return true; } + virtual bool visit(UiScriptBinding *) { return true; } + virtual bool visit(UiArrayBinding *) { return true; } + virtual bool visit(UiObjectMemberList *) { return true; } + virtual bool visit(UiArrayMemberList *) { return true; } + virtual bool visit(UiQualifiedId *) { return true; } + virtual bool visit(UiSignature *) { return true; } + virtual bool visit(UiFormalList *) { return true; } + virtual bool visit(UiFormal *) { return true; } + + virtual void endVisit(UiProgram *) {} + virtual void endVisit(UiImportList *) {} + virtual void endVisit(UiImport *) {} + virtual void endVisit(UiPublicMember *) {} + virtual void endVisit(UiSourceElement *) {} + virtual void endVisit(UiObjectDefinition *) {} + virtual void endVisit(UiObjectInitializer *) {} + virtual void endVisit(UiObjectBinding *) {} + virtual void endVisit(UiScriptBinding *) {} + virtual void endVisit(UiArrayBinding *) {} + virtual void endVisit(UiObjectMemberList *) {} + virtual void endVisit(UiArrayMemberList *) {} + virtual void endVisit(UiQualifiedId *) {} + virtual void endVisit(UiSignature *) {} + virtual void endVisit(UiFormalList *) {} + virtual void endVisit(UiFormal *) {} + + // QDeclarativeJS + virtual bool visit(ThisExpression *) { return true; } + virtual void endVisit(ThisExpression *) {} + + virtual bool visit(IdentifierExpression *) { return true; } + virtual void endVisit(IdentifierExpression *) {} + + virtual bool visit(NullExpression *) { return true; } + virtual void endVisit(NullExpression *) {} + + virtual bool visit(TrueLiteral *) { return true; } + virtual void endVisit(TrueLiteral *) {} + + virtual bool visit(FalseLiteral *) { return true; } + virtual void endVisit(FalseLiteral *) {} + + virtual bool visit(StringLiteral *) { return true; } + virtual void endVisit(StringLiteral *) {} + + virtual bool visit(NumericLiteral *) { return true; } + virtual void endVisit(NumericLiteral *) {} + + virtual bool visit(RegExpLiteral *) { return true; } + virtual void endVisit(RegExpLiteral *) {} + + virtual bool visit(ArrayLiteral *) { return true; } + virtual void endVisit(ArrayLiteral *) {} + + virtual bool visit(ObjectLiteral *) { return true; } + virtual void endVisit(ObjectLiteral *) {} + + virtual bool visit(ElementList *) { return true; } + virtual void endVisit(ElementList *) {} + + virtual bool visit(Elision *) { return true; } + virtual void endVisit(Elision *) {} + + virtual bool visit(PropertyNameAndValueList *) { return true; } + virtual void endVisit(PropertyNameAndValueList *) {} + + virtual bool visit(NestedExpression *) { return true; } + virtual void endVisit(NestedExpression *) {} + + virtual bool visit(IdentifierPropertyName *) { return true; } + virtual void endVisit(IdentifierPropertyName *) {} + + virtual bool visit(StringLiteralPropertyName *) { return true; } + virtual void endVisit(StringLiteralPropertyName *) {} + + virtual bool visit(NumericLiteralPropertyName *) { return true; } + virtual void endVisit(NumericLiteralPropertyName *) {} + + virtual bool visit(ArrayMemberExpression *) { return true; } + virtual void endVisit(ArrayMemberExpression *) {} + + virtual bool visit(FieldMemberExpression *) { return true; } + virtual void endVisit(FieldMemberExpression *) {} + + virtual bool visit(NewMemberExpression *) { return true; } + virtual void endVisit(NewMemberExpression *) {} + + virtual bool visit(NewExpression *) { return true; } + virtual void endVisit(NewExpression *) {} + + virtual bool visit(CallExpression *) { return true; } + virtual void endVisit(CallExpression *) {} + + virtual bool visit(ArgumentList *) { return true; } + virtual void endVisit(ArgumentList *) {} + + virtual bool visit(PostIncrementExpression *) { return true; } + virtual void endVisit(PostIncrementExpression *) {} + + virtual bool visit(PostDecrementExpression *) { return true; } + virtual void endVisit(PostDecrementExpression *) {} + + virtual bool visit(DeleteExpression *) { return true; } + virtual void endVisit(DeleteExpression *) {} + + virtual bool visit(VoidExpression *) { return true; } + virtual void endVisit(VoidExpression *) {} + + virtual bool visit(TypeOfExpression *) { return true; } + virtual void endVisit(TypeOfExpression *) {} + + virtual bool visit(PreIncrementExpression *) { return true; } + virtual void endVisit(PreIncrementExpression *) {} + + virtual bool visit(PreDecrementExpression *) { return true; } + virtual void endVisit(PreDecrementExpression *) {} + + virtual bool visit(UnaryPlusExpression *) { return true; } + virtual void endVisit(UnaryPlusExpression *) {} + + virtual bool visit(UnaryMinusExpression *) { return true; } + virtual void endVisit(UnaryMinusExpression *) {} + + virtual bool visit(TildeExpression *) { return true; } + virtual void endVisit(TildeExpression *) {} + + virtual bool visit(NotExpression *) { return true; } + virtual void endVisit(NotExpression *) {} + + virtual bool visit(BinaryExpression *) { return true; } + virtual void endVisit(BinaryExpression *) {} + + virtual bool visit(ConditionalExpression *) { return true; } + virtual void endVisit(ConditionalExpression *) {} + + virtual bool visit(Expression *) { return true; } + virtual void endVisit(Expression *) {} + + virtual bool visit(Block *) { return true; } + virtual void endVisit(Block *) {} + + virtual bool visit(StatementList *) { return true; } + virtual void endVisit(StatementList *) {} + + virtual bool visit(VariableStatement *) { return true; } + virtual void endVisit(VariableStatement *) {} + + virtual bool visit(VariableDeclarationList *) { return true; } + virtual void endVisit(VariableDeclarationList *) {} + + virtual bool visit(VariableDeclaration *) { return true; } + virtual void endVisit(VariableDeclaration *) {} + + virtual bool visit(EmptyStatement *) { return true; } + virtual void endVisit(EmptyStatement *) {} + + virtual bool visit(ExpressionStatement *) { return true; } + virtual void endVisit(ExpressionStatement *) {} + + virtual bool visit(IfStatement *) { return true; } + virtual void endVisit(IfStatement *) {} + + virtual bool visit(DoWhileStatement *) { return true; } + virtual void endVisit(DoWhileStatement *) {} + + virtual bool visit(WhileStatement *) { return true; } + virtual void endVisit(WhileStatement *) {} + + virtual bool visit(ForStatement *) { return true; } + virtual void endVisit(ForStatement *) {} + + virtual bool visit(LocalForStatement *) { return true; } + virtual void endVisit(LocalForStatement *) {} + + virtual bool visit(ForEachStatement *) { return true; } + virtual void endVisit(ForEachStatement *) {} + + virtual bool visit(LocalForEachStatement *) { return true; } + virtual void endVisit(LocalForEachStatement *) {} + + virtual bool visit(ContinueStatement *) { return true; } + virtual void endVisit(ContinueStatement *) {} + + virtual bool visit(BreakStatement *) { return true; } + virtual void endVisit(BreakStatement *) {} + + virtual bool visit(ReturnStatement *) { return true; } + virtual void endVisit(ReturnStatement *) {} + + virtual bool visit(WithStatement *) { return true; } + virtual void endVisit(WithStatement *) {} + + virtual bool visit(SwitchStatement *) { return true; } + virtual void endVisit(SwitchStatement *) {} + + virtual bool visit(CaseBlock *) { return true; } + virtual void endVisit(CaseBlock *) {} + + virtual bool visit(CaseClauses *) { return true; } + virtual void endVisit(CaseClauses *) {} + + virtual bool visit(CaseClause *) { return true; } + virtual void endVisit(CaseClause *) {} + + virtual bool visit(DefaultClause *) { return true; } + virtual void endVisit(DefaultClause *) {} + + virtual bool visit(LabelledStatement *) { return true; } + virtual void endVisit(LabelledStatement *) {} + + virtual bool visit(ThrowStatement *) { return true; } + virtual void endVisit(ThrowStatement *) {} + + virtual bool visit(TryStatement *) { return true; } + virtual void endVisit(TryStatement *) {} + + virtual bool visit(Catch *) { return true; } + virtual void endVisit(Catch *) {} + + virtual bool visit(Finally *) { return true; } + virtual void endVisit(Finally *) {} + + virtual bool visit(FunctionDeclaration *) { return true; } + virtual void endVisit(FunctionDeclaration *) {} + + virtual bool visit(FunctionExpression *) { return true; } + virtual void endVisit(FunctionExpression *) {} + + virtual bool visit(FormalParameterList *) { return true; } + virtual void endVisit(FormalParameterList *) {} + + virtual bool visit(FunctionBody *) { return true; } + virtual void endVisit(FunctionBody *) {} + + virtual bool visit(Program *) { return true; } + virtual void endVisit(Program *) {} + + virtual bool visit(SourceElements *) { return true; } + virtual void endVisit(SourceElements *) {} + + virtual bool visit(FunctionSourceElement *) { return true; } + virtual void endVisit(FunctionSourceElement *) {} + + virtual bool visit(StatementSourceElement *) { return true; } + virtual void endVisit(StatementSourceElement *) {} + + virtual bool visit(DebuggerStatement *) { return true; } + virtual void endVisit(DebuggerStatement *) {} +}; + +} } // namespace AST + +QT_QML_END_NAMESPACE + +#endif // QDECLARATIVEJSASTVISITOR_P_H diff --git a/src/declarative/qml/parser/qdeclarativejsengine_p.cpp b/src/declarative/qml/parser/qdeclarativejsengine_p.cpp new file mode 100644 index 00000000..0d7a7f53 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsengine_p.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativejsengine_p.h" + +#include "private/qdeclarativejsglobal_p.h" +#include "private/qdeclarativejsnodepool_p.h" + +#include <qnumeric.h> +#include <QHash> + +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { + +uint qHash(const QDeclarativeJS::NameId &id) +{ return qHash(id.asString()); } + +QString numberToString(double value) +{ return QString::number(value); } + +int Ecma::RegExp::flagFromChar(const QChar &ch) +{ + static QHash<QChar, int> flagsHash; + if (flagsHash.isEmpty()) { + flagsHash[QLatin1Char('g')] = Global; + flagsHash[QLatin1Char('i')] = IgnoreCase; + flagsHash[QLatin1Char('m')] = Multiline; + } + QHash<QChar, int>::const_iterator it; + it = flagsHash.constFind(ch); + if (it == flagsHash.constEnd()) + return 0; + return it.value(); +} + +QString Ecma::RegExp::flagsToString(int flags) +{ + QString result; + if (flags & Global) + result += QLatin1Char('g'); + if (flags & IgnoreCase) + result += QLatin1Char('i'); + if (flags & Multiline) + result += QLatin1Char('m'); + return result; +} + +NodePool::NodePool(const QString &fileName, Engine *engine) + : m_fileName(fileName), m_engine(engine) +{ + m_engine->setNodePool(this); +} + +NodePool::~NodePool() +{ +} + +Code *NodePool::createCompiledCode(AST::Node *, CompilationUnit &) +{ + Q_ASSERT(0); + return 0; +} + +static int toDigit(char c) +{ + if ((c >= '0') && (c <= '9')) + return c - '0'; + else if ((c >= 'a') && (c <= 'z')) + return 10 + c - 'a'; + else if ((c >= 'A') && (c <= 'Z')) + return 10 + c - 'A'; + return -1; +} + +double integerFromString(const char *buf, int size, int radix) +{ + if (size == 0) + return qSNaN(); + + double sign = 1.0; + int i = 0; + if (buf[0] == '+') { + ++i; + } else if (buf[0] == '-') { + sign = -1.0; + ++i; + } + + if (((size-i) >= 2) && (buf[i] == '0')) { + if (((buf[i+1] == 'x') || (buf[i+1] == 'X')) + && (radix < 34)) { + if ((radix != 0) && (radix != 16)) + return 0; + radix = 16; + i += 2; + } else { + if (radix == 0) { + radix = 8; + ++i; + } + } + } else if (radix == 0) { + radix = 10; + } + + int j = i; + for ( ; i < size; ++i) { + int d = toDigit(buf[i]); + if ((d == -1) || (d >= radix)) + break; + } + double result; + if (j == i) { + if (!qstrcmp(buf, "Infinity")) + result = qInf(); + else + result = qSNaN(); + } else { + result = 0; + double multiplier = 1; + for (--i ; i >= j; --i, multiplier *= radix) + result += toDigit(buf[i]) * multiplier; + } + result *= sign; + return result; +} + +double integerFromString(const QString &str, int radix) +{ + QByteArray ba = str.trimmed().toLatin1(); + return integerFromString(ba.constData(), ba.size(), radix); +} + + +Engine::Engine() + : _lexer(0), _nodePool(0) +{ } + +Engine::~Engine() +{ } + +QSet<NameId> Engine::literals() const +{ return _literals; } + +void Engine::addComment(int pos, int len, int line, int col) +{ if (len > 0) _comments.append(QDeclarativeJS::AST::SourceLocation(pos, len, line, col)); } + +QList<QDeclarativeJS::AST::SourceLocation> Engine::comments() const +{ return _comments; } + +NameId *Engine::intern(const QChar *u, int s) +{ return const_cast<NameId *>(&*_literals.insert(NameId(u, s))); } + +QString Engine::toString(NameId *id) +{ return id->asString(); } + +Lexer *Engine::lexer() const +{ return _lexer; } + +void Engine::setLexer(Lexer *lexer) +{ _lexer = lexer; } + +NodePool *Engine::nodePool() const +{ return _nodePool; } + +void Engine::setNodePool(NodePool *nodePool) +{ _nodePool = nodePool; } + + + +} // end of namespace QDeclarativeJS + +QT_QML_END_NAMESPACE diff --git a/src/declarative/qml/parser/qdeclarativejsengine_p.h b/src/declarative/qml/parser/qdeclarativejsengine_p.h new file mode 100644 index 00000000..2603e7d2 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsengine_p.h @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEJSENGINE_P_H +#define QDECLARATIVEJSENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativejsglobal_p.h" +#include "private/qdeclarativejsastfwd_p.h" + +#include <QString> +#include <QSet> + +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { +class QML_PARSER_EXPORT NameId +{ + QString _text; + +public: + NameId(const QChar *u, int s) + : _text(u, s) + { } + + const QString asString() const + { return _text; } + + bool operator == (const NameId &other) const + { return _text == other._text; } + + bool operator != (const NameId &other) const + { return _text != other._text; } + + bool operator < (const NameId &other) const + { return _text < other._text; } +}; + +uint qHash(const QDeclarativeJS::NameId &id); + +} // end of namespace QDeclarativeJS + +namespace QDeclarativeJS { + +class Lexer; +class NodePool; + +namespace Ecma { + +class QML_PARSER_EXPORT RegExp +{ +public: + enum RegExpFlag { + Global = 0x01, + IgnoreCase = 0x02, + Multiline = 0x04 + }; + +public: + static int flagFromChar(const QChar &); + static QString flagsToString(int flags); +}; + +} // end of namespace Ecma + +class QML_PARSER_EXPORT DiagnosticMessage +{ +public: + enum Kind { Warning, Error }; + + DiagnosticMessage() + : kind(Error) {} + + DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message) + : kind(kind), loc(loc), message(message) {} + + bool isWarning() const + { return kind == Warning; } + + bool isError() const + { return kind == Error; } + + Kind kind; + AST::SourceLocation loc; + QString message; +}; + +class QML_PARSER_EXPORT Engine +{ + Lexer *_lexer; + NodePool *_nodePool; + QSet<NameId> _literals; + QList<QDeclarativeJS::AST::SourceLocation> _comments; + +public: + Engine(); + ~Engine(); + + QSet<NameId> literals() const; + + void addComment(int pos, int len, int line, int col); + QList<QDeclarativeJS::AST::SourceLocation> comments() const; + + NameId *intern(const QChar *u, int s); + + static QString toString(NameId *id); + + Lexer *lexer() const; + void setLexer(Lexer *lexer); + + NodePool *nodePool() const; + void setNodePool(NodePool *nodePool); +}; + +} // end of namespace QDeclarativeJS + +QT_QML_END_NAMESPACE + +#endif // QDECLARATIVEJSENGINE_P_H diff --git a/src/declarative/qml/parser/qdeclarativejsglobal_p.h b/src/declarative/qml/parser/qdeclarativejsglobal_p.h new file mode 100644 index 00000000..014d78ab --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsglobal_p.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QDECLARATIVEJSGLOBAL_P_H +#define QDECLARATIVEJSGLOBAL_P_H + +#include <QtCore/qglobal.h> + +#ifdef QT_CREATOR +# define QT_QML_BEGIN_NAMESPACE +# define QT_QML_END_NAMESPACE + +# ifdef QDECLARATIVEJS_BUILD_DIR +# define QML_PARSER_EXPORT Q_DECL_EXPORT +# elif QML_BUILD_STATIC_LIB +# define QML_PARSER_EXPORT +# else +# define QML_PARSER_EXPORT Q_DECL_IMPORT +# endif // QDECLARATIVEJS_BUILD_DIR + +#else // !QT_CREATOR +# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE +# define QT_QML_END_NAMESPACE QT_END_NAMESPACE +# define QML_PARSER_EXPORT +#endif // QT_CREATOR + +#endif // QDECLARATIVEJSGLOBAL_P_H diff --git a/src/declarative/qml/parser/qdeclarativejsgrammar.cpp b/src/declarative/qml/parser/qdeclarativejsgrammar.cpp new file mode 100644 index 00000000..02b23663 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsgrammar.cpp @@ -0,0 +1,989 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This file was generated by qlalr - DO NOT EDIT! +#include "qdeclarativejsgrammar_p.h" + +QT_BEGIN_NAMESPACE + +const char *const QDeclarativeJSGrammar::spell [] = { + "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ";", "continue", + "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===", + "finally", "for", "function", ">=", ">", ">>", ">>=", ">>>", ">>>=", "identifier", + "if", "in", "instanceof", "{", "[", "<=", "(", "<", "<<", "<<=", + "-", "-=", "--", "new", "!", "!=", "!==", "numeric literal", "|", "|=", + "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return", + ")", ";", 0, "*", "*=", "string literal", "property", "signal", "readonly", "switch", + "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^", + "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "comment", "public", + "import", "as", "on", 0, 0, 0, 0, 0, 0, 0, + 0}; + +const short QDeclarativeJSGrammar::lhs [] = { + 101, 101, 101, 101, 101, 101, 102, 108, 108, 111, + 111, 113, 112, 112, 112, 112, 112, 112, 112, 112, + 115, 110, 109, 118, 118, 119, 119, 120, 120, 117, + 106, 106, 106, 106, 106, 106, 106, 106, 126, 126, + 126, 127, 127, 128, 128, 106, 106, 106, 106, 106, + 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, + 106, 106, 106, 106, 106, 116, 116, 116, 116, 116, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 121, 133, + 133, 133, 133, 132, 132, 135, 135, 137, 137, 137, + 137, 137, 137, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 139, 139, 114, 114, 114, 114, + 114, 142, 142, 143, 143, 143, 143, 141, 141, 144, + 144, 145, 145, 146, 146, 146, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 148, 148, 148, 148, + 149, 149, 149, 150, 150, 150, 150, 151, 151, 151, + 151, 151, 151, 151, 152, 152, 152, 152, 152, 152, + 153, 153, 153, 153, 153, 154, 154, 154, 154, 154, + 155, 155, 156, 156, 157, 157, 158, 158, 159, 159, + 160, 160, 161, 161, 162, 162, 163, 163, 164, 164, + 165, 165, 166, 166, 136, 136, 167, 167, 168, 168, + 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, + 104, 104, 169, 169, 170, 170, 171, 171, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 122, 183, 183, 182, 182, 130, 130, + 184, 184, 185, 185, 187, 187, 186, 188, 191, 189, + 189, 192, 190, 190, 123, 124, 124, 125, 125, 172, + 172, 172, 172, 172, 172, 172, 173, 173, 173, 173, + 174, 174, 174, 174, 175, 175, 176, 178, 193, 193, + 196, 196, 194, 194, 197, 195, 177, 177, 177, 179, + 179, 180, 180, 180, 198, 199, 181, 181, 129, 140, + 203, 203, 200, 200, 201, 201, 204, 107, 205, 205, + 105, 105, 202, 202, 134, 134, 206}; + +const short QDeclarativeJSGrammar::rhs [] = { + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, + 2, 1, 2, 2, 3, 3, 5, 5, 4, 4, + 2, 0, 1, 1, 2, 1, 3, 2, 3, 2, + 1, 5, 4, 4, 3, 3, 3, 3, 1, 1, + 1, 0, 1, 2, 4, 6, 6, 3, 3, 7, + 7, 4, 4, 5, 5, 6, 6, 7, 7, 7, + 7, 10, 6, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 3, 4, 5, 3, 4, 3, 1, 1, + 2, 3, 4, 1, 2, 3, 5, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 4, 3, + 5, 1, 2, 4, 4, 4, 3, 0, 1, 1, + 3, 1, 1, 1, 2, 2, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 3, 3, 3, + 1, 3, 3, 1, 3, 3, 3, 1, 3, 3, + 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, + 1, 3, 3, 3, 3, 1, 3, 3, 3, 3, + 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, + 1, 5, 1, 5, 1, 3, 1, 3, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 0, 1, 1, 3, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 2, 0, 1, 3, 3, + 1, 1, 1, 3, 1, 3, 2, 2, 2, 0, + 1, 2, 0, 1, 1, 2, 2, 7, 5, 7, + 7, 5, 9, 10, 7, 8, 2, 2, 3, 3, + 2, 2, 3, 3, 3, 3, 5, 5, 3, 5, + 1, 2, 0, 1, 4, 3, 3, 3, 3, 3, + 3, 3, 3, 4, 5, 2, 2, 2, 8, 8, + 1, 3, 0, 1, 0, 1, 1, 1, 1, 2, + 1, 1, 0, 1, 0, 1, 2}; + +const short QDeclarativeJSGrammar::action_default [] = { + 0, 0, 0, 0, 0, 0, 22, 0, 174, 241, + 205, 213, 209, 153, 225, 201, 3, 138, 72, 154, + 217, 221, 142, 171, 152, 157, 137, 191, 178, 0, + 79, 80, 75, 343, 66, 345, 0, 0, 0, 0, + 77, 0, 0, 73, 76, 70, 0, 0, 67, 69, + 68, 78, 71, 0, 74, 0, 0, 167, 0, 0, + 154, 173, 156, 155, 0, 0, 0, 169, 170, 168, + 172, 0, 202, 0, 0, 0, 0, 192, 0, 0, + 0, 0, 0, 0, 182, 0, 0, 0, 176, 177, + 175, 180, 184, 183, 181, 179, 194, 193, 195, 0, + 210, 0, 206, 0, 0, 148, 135, 147, 136, 104, + 105, 106, 131, 107, 132, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 133, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 134, + 0, 0, 146, 242, 149, 0, 150, 0, 151, 145, + 0, 238, 231, 229, 236, 237, 235, 234, 240, 233, + 232, 230, 239, 226, 0, 214, 0, 0, 218, 0, + 0, 222, 0, 0, 148, 140, 0, 139, 0, 144, + 158, 0, 344, 333, 334, 0, 331, 0, 332, 0, + 335, 249, 256, 255, 263, 251, 0, 252, 336, 0, + 342, 253, 254, 259, 257, 339, 337, 341, 260, 0, + 271, 0, 0, 0, 0, 343, 66, 0, 345, 67, + 243, 285, 68, 0, 0, 0, 272, 0, 0, 261, + 262, 0, 250, 258, 286, 287, 330, 340, 0, 301, + 302, 303, 304, 0, 297, 298, 299, 300, 327, 328, + 0, 0, 0, 0, 0, 290, 291, 247, 245, 207, + 215, 211, 227, 203, 248, 0, 154, 219, 223, 196, + 185, 0, 0, 204, 0, 0, 0, 0, 197, 0, + 0, 0, 0, 0, 189, 187, 190, 188, 186, 199, + 198, 200, 0, 212, 0, 208, 0, 246, 154, 0, + 228, 243, 244, 0, 243, 0, 0, 293, 0, 0, + 0, 295, 0, 216, 0, 0, 220, 0, 0, 224, + 283, 0, 275, 284, 278, 0, 282, 0, 243, 276, + 0, 243, 0, 0, 294, 0, 0, 0, 296, 344, + 333, 0, 0, 335, 0, 329, 0, 319, 0, 0, + 0, 289, 0, 288, 0, 346, 0, 103, 265, 268, + 0, 104, 271, 107, 132, 109, 110, 75, 114, 115, + 66, 116, 119, 73, 76, 67, 243, 68, 78, 122, + 71, 124, 74, 126, 127, 272, 129, 130, 134, 0, + 96, 0, 0, 98, 102, 100, 87, 99, 101, 0, + 97, 86, 266, 264, 142, 143, 148, 0, 141, 0, + 318, 0, 305, 306, 0, 317, 0, 0, 0, 308, + 313, 311, 314, 0, 0, 312, 313, 0, 309, 0, + 310, 267, 316, 0, 267, 315, 0, 320, 321, 0, + 267, 322, 323, 0, 0, 324, 0, 0, 0, 325, + 326, 160, 159, 0, 0, 0, 292, 0, 0, 0, + 307, 280, 273, 0, 281, 277, 0, 279, 269, 0, + 270, 274, 90, 0, 0, 94, 81, 0, 83, 92, + 0, 84, 93, 95, 85, 91, 82, 0, 88, 164, + 162, 166, 163, 161, 165, 6, 338, 4, 2, 64, + 89, 0, 0, 67, 69, 68, 31, 5, 0, 65, + 0, 41, 40, 39, 0, 0, 54, 0, 55, 0, + 60, 61, 0, 41, 0, 0, 0, 0, 0, 50, + 0, 51, 0, 0, 26, 0, 0, 62, 27, 0, + 30, 28, 24, 0, 29, 25, 0, 52, 0, 53, + 0, 142, 0, 56, 57, 63, 0, 0, 0, 0, + 0, 58, 59, 0, 48, 42, 49, 43, 0, 0, + 0, 0, 45, 0, 46, 47, 44, 0, 0, 35, + 36, 37, 38, 142, 267, 0, 0, 104, 271, 107, + 132, 109, 110, 75, 114, 115, 66, 116, 119, 73, + 76, 67, 243, 68, 78, 122, 71, 124, 74, 126, + 127, 272, 129, 130, 134, 0, 32, 33, 0, 34, + 8, 0, 10, 0, 9, 0, 1, 21, 12, 0, + 13, 0, 14, 0, 19, 20, 0, 15, 16, 0, + 17, 18, 11, 23, 7, 347}; + +const short QDeclarativeJSGrammar::goto_default [] = { + 7, 626, 207, 196, 205, 507, 495, 625, 644, 620, + 624, 622, 627, 22, 623, 18, 506, 543, 533, 540, + 535, 191, 195, 197, 201, 524, 568, 567, 200, 232, + 26, 474, 473, 356, 355, 9, 354, 357, 107, 17, + 145, 24, 13, 144, 19, 25, 57, 23, 8, 28, + 27, 269, 15, 263, 10, 259, 12, 261, 11, 260, + 20, 267, 21, 268, 14, 262, 258, 299, 411, 264, + 265, 202, 193, 192, 204, 233, 203, 208, 229, 230, + 194, 360, 359, 231, 463, 462, 321, 322, 465, 324, + 464, 323, 419, 423, 426, 422, 421, 441, 442, 185, + 199, 181, 184, 198, 206, 0}; + +const short QDeclarativeJSGrammar::action_index [] = { + 421, 1288, 2322, 2322, 2419, 1016, -52, 37, 140, -101, + 35, -13, -40, 190, -101, 272, 34, -101, -101, 658, + 42, 103, 194, 201, -101, -101, -101, 439, 256, 1288, + -101, -101, -101, 282, -101, 2128, 1751, 1288, 1288, 1288, + -101, 917, 1288, -101, -101, -101, 1288, 1288, -101, -101, + -101, -101, -101, 1288, -101, 1288, 1288, -101, 1288, 1288, + 109, 245, -101, -101, 1288, 1288, 1288, -101, -101, -101, + 185, 1288, 295, 1288, 1288, 1288, 1288, 461, 1288, 1288, + 1288, 1288, 1288, 1288, 256, 1288, 1288, 1288, 155, 119, + 114, 176, 256, 332, 202, 332, 560, 560, 471, 1288, + -23, 1288, 53, 2031, 1288, 1288, -101, -101, -101, -101, + -101, -101, -101, -101, -101, -101, -101, -101, -101, -101, + -101, -101, -101, -101, -101, -101, -101, -101, -101, -101, + -101, -101, -101, -101, -101, -101, -101, -101, -101, -101, + 100, 1288, -101, -101, 70, 59, -101, 1288, -101, -101, + 1288, -101, -101, -101, -101, -101, -101, -101, -101, -101, + -101, -101, -101, -101, 1288, 41, 1288, 1288, 98, 91, + 1288, -101, 2031, 1288, 1288, -101, 121, -101, 73, -101, + -101, 39, -101, 385, 180, 78, -101, 391, -101, 64, + 2322, -101, -101, -101, -101, -101, 208, -101, -101, 82, + -101, -101, -101, -101, -101, -101, 2322, -101, -101, 538, + -101, 495, 128, 2419, 54, 358, 62, 44, 2613, 67, + 1288, -101, 76, 63, 1288, 58, -101, 60, 46, -101, + -101, 309, -101, -101, -101, -101, -101, -101, 86, -101, + -101, -101, -101, 107, -101, -101, -101, -101, -101, -101, + 28, 52, 1288, 101, 102, -101, -101, 1472, -101, 83, + 75, 79, -101, 287, 84, 80, 585, 69, 89, 321, + 177, 482, 1288, 297, 1288, 1288, 1288, 1288, 331, 1288, + 1288, 1288, 1288, 1288, 332, 222, 332, 332, 332, 410, + 410, 410, 1288, 57, 1288, 72, 1288, -101, 658, 1288, + -101, 1288, 71, 45, 1288, 61, 2419, -101, 1288, 132, + 2419, -101, 1288, 47, 1288, 1288, 66, 65, 1288, -101, + 68, 112, 81, -101, -101, 1288, -101, 369, 1288, -101, + 85, 1288, 74, 2419, -101, 1288, 122, 2419, -101, 77, + 294, 16, -29, 2322, -53, -101, 2419, -101, 1288, 127, + 2419, -15, 2419, -101, 10, 11, -34, -101, -101, 2419, + -48, 504, 4, 476, 113, 1288, 2419, 2, -28, 420, + 6, -21, 719, 7, 87, -101, 1382, -101, -4, -16, + 5, 1288, 3, -27, 1288, 9, 1288, -18, -31, 1288, + -101, 2225, -7, -101, -101, -101, -101, -101, -101, 1288, + -101, -101, -101, -101, 246, -101, 1288, -38, -101, 2419, + -101, 88, -101, -101, 2419, -101, 1288, 106, 26, -101, + 55, -101, 50, 105, 1288, -101, 48, 38, -101, -8, + -101, 2419, -101, 94, 2419, -101, 238, -101, -101, 104, + 2419, 31, -101, 21, 19, -101, 305, 1, 30, -101, + -101, -101, -101, 1288, 136, 2419, -101, 1288, 134, 2419, + -101, 49, -101, 173, -101, -101, 1288, -101, -101, 363, + -101, -101, -101, 137, 1565, -101, -101, 1658, -101, -101, + 1844, -101, -101, -101, -101, -101, -101, 95, -101, -101, + -101, -101, -101, -101, -101, -101, 2322, -101, -101, -101, + 92, 15, 925, 169, 27, -6, -101, -101, 212, -101, + 191, -101, -101, -101, 323, 211, -101, 1288, -101, 214, + -101, -101, 216, 40, 317, 210, 43, 259, 236, -101, + 36, -101, 747, 96, -101, 29, 747, -101, -101, 1198, + -101, -101, -101, 1107, -101, -101, 231, -101, 1288, -101, + 217, 286, 32, -101, -101, -101, 188, 340, 51, 1288, + 175, -101, -101, 171, -101, 179, -101, 56, -11, 351, + 181, 336, -101, 110, -101, -101, -101, 1934, 647, -101, + -101, -101, -101, 253, 2516, 1751, -5, 460, 22, 468, + 138, 1288, 2419, 24, -2, 412, 23, -3, 836, 20, + 87, -101, 1382, -101, 17, -10, 18, 1288, 25, 8, + 1288, 33, 1288, 12, 14, 120, -101, -101, 13, -101, + -101, 747, -101, 248, -47, 828, -101, -101, 152, 482, + -101, 150, -101, 123, -101, -101, 398, -101, -101, 117, + -101, -101, -101, -101, -101, -101, + + -106, 6, -92, 10, 5, 278, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -42, + -106, -106, -106, -106, -106, -106, -106, -106, -106, 109, + -106, -106, -106, -10, -106, -106, -35, 24, 73, 90, + -106, 219, 181, -106, -106, -106, 171, 120, -106, -106, + -106, -106, -106, 174, -106, 170, 167, -106, 175, 163, + -106, -106, -106, -106, 184, 177, 180, -106, -106, -106, + -106, 125, -106, 132, 134, 162, 130, -106, 121, 124, + 123, 141, 142, 152, -106, 154, 161, 160, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, 139, + -106, 143, -106, 156, 91, 55, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, 32, -106, -106, -106, -106, -106, 33, -106, -106, + 26, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, 96, -106, 119, 52, -106, -106, + 66, -106, 220, 69, 71, -106, -106, -106, -106, -106, + -106, -106, -106, 25, -106, -106, -106, 64, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, 70, -106, -106, 61, + -106, 41, -106, 39, -106, 37, -106, -106, 42, -106, + 79, -106, -106, -106, 81, 72, -106, -106, -106, -106, + -106, -5, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, 21, -106, -106, -106, -106, 112, -106, -106, + -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, 17, 237, -106, 192, 236, 224, 225, -106, 97, + 98, 101, 99, 113, -106, -106, -106, -106, -106, -106, + -106, -106, 204, -106, 223, -106, 235, -106, -106, 239, + -106, 197, -106, -106, 228, -106, 27, -106, 13, -106, + 2, -106, 233, -106, 190, 198, -106, -106, 196, -106, + -106, -106, -106, -106, -106, 200, -106, 107, 135, -106, + -106, 186, -106, 84, -106, 80, -106, 76, -106, -106, + 89, -106, -106, -49, -106, -106, 47, -106, 40, -106, + 44, -106, 68, -106, -106, -106, -106, -106, -106, 53, + -106, 35, -106, 49, -106, 87, 63, -106, -106, 30, + -106, -106, 103, -106, -106, -106, 51, -106, -106, -106, + -106, 86, -106, 67, 114, -106, 74, -106, -106, 65, + -106, 56, -106, -106, -106, -106, -106, -106, -106, 62, + -106, -106, -106, -106, -106, -106, 95, -106, -106, 78, + -106, -106, -106, -106, 75, -106, 88, -106, -106, -106, + -106, -106, -54, -106, 45, -106, -40, -106, -106, -106, + -106, 94, -106, -106, 100, -106, -106, -106, -106, -106, + 150, -41, -106, -106, 54, -106, 43, -106, 48, -106, + -106, -106, -106, 59, -106, 57, -106, 60, -106, 58, + -106, -106, -106, -106, -106, -106, 38, -106, -106, 144, + -106, -106, -106, -106, 31, -106, -106, 202, -106, -106, + 50, -106, -106, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, 77, -106, -106, -106, + -106, -106, 82, -106, -106, -106, -106, -106, -106, -106, + -17, -106, -106, -106, -4, -106, -106, 12, -106, -106, + -106, -106, -106, -106, -14, 46, -106, -13, -106, -106, + -106, -106, 108, -106, -106, -106, 243, -106, -106, 295, + -106, -106, -106, 290, -106, -106, -106, -106, 346, -106, + -106, -106, 16, -106, -106, -106, 22, 23, -106, 34, + -106, -106, -106, -106, -106, 11, -106, -106, -106, 7, + 1, 8, -106, -106, -106, -106, -106, 307, 179, -106, + -106, -106, -106, -106, 18, 281, 9, 15, -106, 4, + -106, 83, 29, -106, -106, -2, -106, -106, 85, -106, + -106, -106, 3, -106, -106, -106, -106, 14, -106, 0, + 105, -106, 93, -106, -106, -106, -106, -106, -1, -106, + -106, 20, -106, -106, 28, 92, -106, -106, -106, 19, + -106, -106, -106, -106, -106, -106, -12, -106, -106, -106, + -106, -106, -106, -106, -106, -106}; + +const short QDeclarativeJSGrammar::action_info [] = { + 399, 352, 345, -101, 343, 457, 440, 403, 257, -112, + -125, -131, -123, 346, -120, 348, -128, 389, 453, 391, + 416, 401, 408, 563, -101, -123, 416, -120, 539, -131, + 346, -112, -125, 348, 257, 99, 71, 645, 621, 101, + -128, 440, 141, 621, 164, 431, 539, 430, 453, 573, + 457, 444, 440, 424, 71, 424, 101, 446, 559, 420, + 424, 448, 539, 440, 570, 539, 466, 527, 312, 346, + 532, 312, 318, 272, 409, 183, 342, 525, 147, 141, + 348, 510, 457, 414, 272, 325, 0, 0, 252, 99, + 257, 440, 296, 556, -102, 292, 453, 190, 170, 416, + 164, 434, 141, 141, 536, 251, 304, 172, 141, 141, + 443, 0, 335, 340, 141, 427, 0, 0, 0, 149, + 327, 306, 0, 292, 444, 0, 173, 0, 536, 141, + 141, 0, 0, 179, 333, 141, 294, 236, 189, 314, + 141, 301, 141, 315, 141, 477, 331, 242, 241, 413, + 412, 62, 537, 166, 58, 488, 142, 167, 294, 58, + 428, 254, 63, 256, 255, 59, 418, 172, 247, 246, + 59, 575, 574, 328, 249, 248, 616, 177, 641, 640, + 58, 469, 337, 141, 635, 634, 173, 350, 187, 249, + 248, 59, 310, 478, 459, 58, 455, 64, 523, 249, + 248, 85, 85, 86, 86, 103, 59, 565, 511, 172, + 511, 638, 637, 64, 87, 87, 141, 511, 517, 577, + 511, 0, 141, 0, 104, 141, 105, 85, 173, 86, + 174, 172, 566, 564, 470, 468, 562, 561, 548, 511, + 87, 636, 65, 530, 513, 539, 141, 85, 66, 86, + 173, 0, 406, 0, 513, 512, 513, 64, 65, 0, + 87, 172, 0, 513, 66, 512, 513, 512, 172, 235, + 234, 0, 518, 516, 512, 521, 520, 512, 554, 553, + 173, 85, 406, 86, 0, 513, -89, 173, 34, 174, + 73, 74, 549, 547, 87, 631, 512, 531, 529, 438, + 437, 172, 65, 0, 578, 274, 275, 0, 66, 632, + 630, 34, 0, 73, 74, 274, 275, 75, 76, -89, + 173, 0, 174, 34, 0, 48, 50, 49, 0, 0, + 0, 0, 276, 277, 34, 0, 0, 0, 34, 629, + 75, 76, 276, 277, 279, 280, 34, 0, 48, 50, + 49, 45, 34, 281, 279, 280, 282, 85, 283, 86, + 48, 50, 49, 281, 0, 34, 282, 0, 283, 34, + 87, 48, 50, 49, 45, 48, 50, 49, 0, 0, + 34, 0, 0, 48, 50, 49, 45, 34, 0, 48, + 50, 49, 34, 0, 0, 0, 0, 45, 34, 0, + 0, 45, 48, 50, 49, 0, 48, 50, 49, 45, + 0, 0, 0, 0, 34, 45, 0, 48, 50, 49, + 34, 0, 0, 0, 48, 50, 49, 34, 45, 48, + 50, 49, 45, 279, 280, 48, 50, 49, 0, 0, + 0, 34, 281, 45, 0, 282, 0, 283, -343, 34, + 45, 48, 50, 49, 0, 45, -343, 48, 50, 49, + 0, 45, 78, 79, 48, 50, 49, 0, 0, 0, + 80, 81, 0, 0, 82, 0, 83, 45, 48, 50, + 49, 0, 0, 45, 78, 79, 48, 50, 49, 34, + 45, 0, 80, 81, 78, 79, 82, 34, 83, 0, + 0, 0, 80, 81, 45, 34, 82, 0, 83, 0, + 0, 34, 45, 0, 6, 5, 4, 1, 3, 2, + 0, 240, 239, 0, 34, 0, 48, 50, 49, 245, + 244, 0, 0, 34, 48, 50, 49, 245, 244, 0, + 0, 0, 48, 50, 49, 0, 0, 0, 48, 50, + 49, 0, 45, 0, 0, 0, 245, 244, 0, 0, + 45, 48, 50, 49, 0, 240, 239, 34, 45, 0, + 48, 50, 49, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 78, 79, 0, 0, 45, 151, 0, + 0, 80, 81, 0, 0, 82, 45, 83, 152, 240, + 239, 0, 153, 0, 48, 50, 49, 0, 0, 0, + 0, 154, 0, 155, 0, 0, 308, 0, 0, 0, + 0, 0, 0, 0, 156, 0, 157, 62, 0, 0, + 45, 0, 0, 0, 158, 0, 0, 159, 63, 0, + 0, 0, 0, 160, 0, 0, 0, 0, 0, 161, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, + 31, 151, 0, 0, 0, 162, 0, 0, 0, 33, + 0, 152, 0, 0, 0, 153, 34, 0, 0, 0, + 35, 36, 0, 37, 154, 0, 155, 0, 0, 0, + 502, 0, 0, 0, 44, 0, 0, 156, 0, 157, + 62, 0, 0, 0, 0, 0, 0, 158, 0, 0, + 159, 63, 51, 48, 50, 49, 160, 52, 0, 0, + 0, 0, 161, 0, 0, 0, 0, 0, 43, 54, + 32, 30, 31, 0, 40, 0, 0, 0, 162, 45, + 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, + 0, 0, 35, 36, 0, 37, 0, 0, 0, 30, + 31, 0, 41, 0, 0, 0, 44, 0, 0, 33, + 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, + 35, 36, 0, 37, 51, 48, 50, 49, 0, 52, + 502, 0, 0, 0, 44, 0, 0, 0, 0, 0, + 43, 54, 32, 0, 0, 0, 40, 0, 0, 0, + 0, 45, 51, 48, 50, 49, 0, 52, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 43, 54, + 32, 0, 0, 0, 40, 0, 0, 0, 0, 45, + 30, 31, 0, 0, 0, 0, 0, 0, 30, 31, + 33, 0, 0, 0, 0, 0, 0, 34, 33, 0, + 0, 35, 36, 0, 37, 34, 0, 0, 0, 35, + 36, 502, 37, 0, 0, 44, 0, 0, 0, 41, + 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 51, 48, 50, 49, 0, 52, 0, + 0, 51, 48, 50, 49, 0, 52, 0, 0, 43, + 54, 32, 0, 0, 0, 40, 0, 43, 54, 32, + 45, 0, 0, 40, 0, 0, 0, 0, 45, 30, + 31, 0, 0, 0, 0, 0, 0, 30, 31, 33, + 0, 0, 0, 0, 0, 0, 34, 33, 0, 0, + 35, 36, 0, 37, 34, 0, 0, 0, 35, 36, + 41, 37, 0, 0, 44, 0, 0, 0, 502, 0, + 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 51, 48, 50, 49, 0, 52, 0, 0, + 51, 48, 50, 49, 0, 52, 0, 0, 43, 54, + 32, 0, 0, 0, 40, 0, 43, 54, 32, 45, + 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 501, 0, 30, 31, + 0, 0, 0, 0, 0, 0, 0, 0, 215, 0, + 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, + 36, 0, 37, 0, 0, 0, 0, 0, 0, 502, + 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 51, 503, 505, 504, 0, 52, 0, 0, 0, + 0, 226, 0, 0, 0, 0, 0, 43, 54, 32, + 210, 0, 0, 40, 0, 0, 0, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 501, 0, 30, + 31, 0, 0, 0, 0, 0, 0, 0, 0, 215, + 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, + 35, 36, 0, 37, 0, 0, 0, 0, 0, 0, + 502, 0, 0, 0, 44, 0, 0, 0, 0, 0, + 0, 0, 544, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 51, 503, 505, 504, 0, 52, 0, 0, + 0, 0, 226, 0, 0, 0, 0, 0, 43, 54, + 32, 210, 0, 0, 40, 0, 0, 0, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 501, 0, + 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 215, 0, 0, 0, 0, 0, 0, 34, 0, 0, + 0, 35, 36, 0, 37, 0, 0, 0, 0, 0, + 0, 502, 0, 0, 0, 44, 0, 0, 0, 0, + 0, 0, 0, 541, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 51, 503, 505, 504, 0, 52, 0, + 0, 0, 0, 226, 0, 0, 0, 0, 0, 43, + 54, 32, 210, 0, 0, 40, 0, 0, 0, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 29, + 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, + 0, 35, 36, 0, 37, 0, 0, 0, 38, 0, + 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, + 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 51, 48, 50, 49, 0, 52, 0, + 53, 0, 55, 0, 56, 0, 0, 0, 0, 43, + 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, -121, + 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, + 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, + 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, + 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, + 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 51, 48, 50, + 49, 0, 52, 0, 53, 0, 55, 0, 56, 0, + 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, + 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, + 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, + 0, 34, 0, 0, 0, 35, 36, 0, 37, 0, + 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, + 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 51, 48, 50, + 49, 0, 52, 0, 53, 0, 55, 271, 56, 0, + 0, 0, 0, 43, 54, 32, 0, 0, 0, 40, + 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 483, 0, 0, 29, 30, 31, 0, + 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, + 0, 0, 0, 0, 34, 0, 0, 0, 35, 36, + 0, 37, 0, 0, 0, 38, 0, 39, 41, 42, + 0, 0, 44, 0, 0, 0, 46, 0, 47, 0, + 0, 486, 0, 0, 0, 0, 0, 0, 0, 0, + 51, 48, 50, 49, 0, 52, 0, 53, 0, 55, + 0, 56, 0, 0, 0, 0, 43, 54, 32, 0, + 0, 0, 40, 0, 0, 0, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 475, 0, 0, 29, + 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, + 0, 35, 36, 0, 37, 0, 0, 0, 38, 0, + 39, 41, 42, 0, 0, 44, 0, 0, 0, 46, + 0, 47, 0, 0, 481, 0, 0, 0, 0, 0, + 0, 0, 0, 51, 48, 50, 49, 0, 52, 0, + 53, 0, 55, 0, 56, 0, 0, 0, 0, 43, + 54, 32, 0, 0, 0, 40, 0, 0, 0, 0, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 475, + 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, + 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, + 34, 0, 0, 0, 35, 36, 0, 37, 0, 0, + 0, 38, 0, 39, 41, 42, 0, 0, 44, 0, + 0, 0, 46, 0, 47, 0, 0, 476, 0, 0, + 0, 0, 0, 0, 0, 0, 51, 48, 50, 49, + 0, 52, 0, 53, 0, 55, 0, 56, 0, 0, + 0, 0, 43, 54, 32, 0, 0, 0, 40, 0, + 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 483, 0, 0, 29, 30, 31, 0, 0, + 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, + 0, 0, 0, 34, 0, 0, 0, 35, 36, 0, + 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, + 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, + 484, 0, 0, 0, 0, 0, 0, 0, 0, 51, + 48, 50, 49, 0, 52, 0, 53, 0, 55, 0, + 56, 0, 0, 0, 0, 43, 54, 32, 0, 0, + 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 29, 30, 31, 0, 0, + 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, + 0, 0, 0, 34, 217, 0, 0, 584, 585, 0, + 37, 0, 0, 0, 38, 0, 39, 41, 42, 0, + 0, 44, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 221, 0, 0, 0, 51, + 48, 50, 49, 0, 52, 0, 53, 0, 55, 0, + 56, 0, 0, 0, 0, 43, 54, 32, 0, 0, + 0, 40, 0, 0, 0, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 109, 110, 111, 0, 0, + 113, 115, 116, 0, 0, 117, 0, 118, 0, 0, + 0, 120, 121, 122, 0, 0, 0, 0, 0, 0, + 34, 123, 124, 125, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 126, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 129, 0, 0, 0, 0, 0, 0, 48, 50, 49, + 130, 131, 132, 0, 134, 135, 136, 137, 138, 139, + 0, 0, 127, 133, 119, 112, 114, 128, 0, 0, + 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 109, 110, 111, 0, 0, 113, 115, 116, + 0, 0, 117, 0, 118, 0, 0, 0, 120, 121, + 122, 0, 0, 0, 0, 0, 0, 393, 123, 124, + 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 126, 0, 0, 0, 394, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 129, 0, 0, + 0, 0, 0, 398, 395, 397, 0, 130, 131, 132, + 0, 134, 135, 136, 137, 138, 139, 0, 0, 127, + 133, 119, 112, 114, 128, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, + 110, 111, 0, 0, 113, 115, 116, 0, 0, 117, + 0, 118, 0, 0, 0, 120, 121, 122, 0, 0, + 0, 0, 0, 0, 393, 123, 124, 125, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 126, 0, + 0, 0, 394, 0, 0, 0, 0, 0, 0, 0, + 396, 0, 0, 0, 129, 0, 0, 0, 0, 0, + 398, 395, 397, 0, 130, 131, 132, 0, 134, 135, + 136, 137, 138, 139, 0, 0, 127, 133, 119, 112, + 114, 128, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, + 0, 211, 0, 29, 30, 31, 213, 0, 0, 0, + 0, 0, 0, 214, 215, 0, 0, 0, 0, 0, + 0, 216, 217, 0, 0, 218, 36, 0, 37, 0, + 0, 0, 38, 0, 39, 41, 42, 0, 0, 44, + 0, 0, 0, 46, 0, 47, 0, 0, 0, 0, + 0, 220, 0, 221, 0, 0, 0, 51, 219, 222, + 49, 223, 52, 224, 53, 225, 55, 226, 56, 227, + 228, 0, 0, 43, 54, 32, 210, 212, 0, 40, + 0, 0, 0, 0, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 209, 0, 0, 0, 0, 211, 0, + 29, 30, 31, 213, 0, 0, 0, 0, 0, 0, + 214, 33, 0, 0, 0, 0, 0, 0, 216, 217, + 0, 0, 218, 36, 0, 37, 0, 0, 0, 38, + 0, 39, 41, 42, 0, 0, 44, 0, 0, 0, + 46, 0, 47, 0, 0, 0, 0, 0, 220, 0, + 221, 0, 0, 0, 51, 219, 222, 49, 223, 52, + 224, 53, 225, 55, 226, 56, 227, 228, 0, 0, + 43, 54, 32, 210, 212, 0, 40, 0, 0, 0, + 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, + 587, 110, 111, 0, 0, 589, 115, 591, 30, 31, + 592, 0, 118, 0, 0, 0, 120, 594, 595, 0, + 0, 0, 0, 0, 0, 596, 597, 124, 125, 218, + 36, 0, 37, 0, 0, 0, 38, 0, 39, 598, + 42, 0, 0, 600, 0, 0, 0, 46, 0, 47, + 0, 0, 0, 0, 0, 602, 0, 221, 0, 0, + 0, 604, 601, 603, 49, 605, 606, 607, 53, 609, + 610, 611, 612, 613, 614, 0, 0, 599, 608, 593, + 588, 590, 128, 40, 0, 0, 0, 0, 45, 0, + 0, 0, 0, 0, 0, 0, 0, 361, 110, 111, + 0, 0, 363, 115, 365, 30, 31, 366, 0, 118, + 0, 0, 0, 120, 368, 369, 0, 0, 0, 0, + 0, 0, 370, 371, 124, 125, 218, 36, 0, 37, + 0, 0, 0, 38, 0, 39, 372, 42, 0, 0, + 374, 0, 0, 0, 46, 0, 47, 0, -267, 0, + 0, 0, 376, 0, 221, 0, 0, 0, 378, 375, + 377, 49, 379, 380, 381, 53, 383, 384, 385, 386, + 387, 388, 0, 0, 373, 382, 367, 362, 364, 128, + 40, 0, 0, 0, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, + + 472, 546, 528, 639, 311, 182, 302, 498, 514, 16, + 461, 515, 496, 182, 497, 519, 309, 436, 619, 243, + 358, 439, 576, 572, 253, 150, 571, 487, 617, 307, + 238, 250, 320, 628, 633, 555, 569, 560, 558, 642, + 186, 250, 425, 349, 358, 182, 351, 557, 433, 347, + 238, 344, 339, 429, 302, 402, 243, 445, 447, 456, + 460, 163, 454, 458, 243, 250, 485, 143, 148, 449, + 353, 526, 176, 467, 237, 450, 238, 415, 338, 188, + 410, 237, 302, 336, 436, 482, 334, 169, 439, 436, + 146, 417, 392, 439, 140, 522, 358, 400, 404, 0, + 390, 171, 358, 0, 186, 500, 146, 0, 643, 0, + 0, 178, 0, 0, 0, 0, 404, 60, 60, 489, + 452, 500, 320, 0, 534, 0, 405, 60, 0, 180, + 146, 60, 0, 180, 60, 407, 490, 60, 302, 452, + 60, 60, 60, 60, 405, 60, 284, 285, 287, 60, + 286, 451, 358, 60, 165, 180, 266, 60, 60, 461, + 451, 270, 288, 60, 60, 60, 493, 60, 60, 60, + 84, 106, 92, 91, 60, 432, 60, 72, 60, 168, + 98, 435, 77, 60, 96, 60, 60, 60, 341, 302, + 93, 94, 500, 108, 329, 100, 60, 102, 60, 618, + 302, 95, 88, 330, 60, 60, 60, 60, 90, 89, + 70, 60, 97, 452, 60, 60, 451, 492, 60, 60, + 494, 60, 61, 68, 60, 60, 69, 491, 60, 471, + 67, 302, 404, 480, 60, 106, 60, 479, 0, 270, + 298, 270, 298, 278, 298, 270, 0, 270, 60, 270, + 0, 316, 0, 270, 332, 0, 500, 108, 175, 538, + 405, 293, 319, 0, 317, 303, 326, 60, 60, 60, + 0, 0, 270, 270, 270, 290, 291, 60, 295, 298, + 60, 60, 270, 298, 270, 270, 270, 289, 270, 0, + 273, 500, 313, 0, 551, 545, 305, 534, 508, 615, + 542, 297, 0, 500, 0, 300, 499, 509, 500, 0, + 508, 0, 0, 0, 0, 508, 472, 0, 499, 509, + 583, 0, 0, 499, 509, 0, 0, 586, 579, 580, + 581, 582, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 550, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 551, + 0, 0, 0, 0, 0, 0, 552, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; + +const short QDeclarativeJSGrammar::action_check [] = { + 7, 16, 55, 7, 33, 36, 33, 55, 36, 7, + 7, 7, 7, 7, 7, 36, 7, 7, 36, 8, + 36, 55, 60, 29, 7, 7, 36, 7, 33, 7, + 7, 7, 7, 36, 36, 48, 1, 0, 90, 79, + 7, 33, 8, 90, 2, 7, 33, 55, 36, 60, + 36, 20, 33, 5, 1, 5, 79, 36, 7, 33, + 5, 60, 33, 33, 8, 33, 17, 24, 2, 7, + 34, 2, 7, 1, 7, 36, 60, 37, 8, 8, + 36, 66, 36, 7, 1, 17, -1, -1, 36, 48, + 36, 33, 8, 66, 7, 48, 36, 33, 7, 36, + 2, 7, 8, 8, 8, 77, 61, 15, 8, 8, + 6, -1, 31, 36, 8, 10, -1, -1, -1, 60, + 8, 60, -1, 48, 20, -1, 34, -1, 8, 8, + 8, -1, -1, 60, 60, 8, 79, 55, 60, 50, + 8, 61, 8, 54, 8, 8, 61, 61, 62, 61, + 62, 42, 56, 50, 40, 60, 56, 54, 79, 40, + 55, 60, 53, 61, 62, 51, 60, 15, 61, 62, + 51, 61, 62, 61, 61, 62, 56, 56, 61, 62, + 40, 8, 60, 8, 61, 62, 34, 60, 8, 61, + 62, 51, 60, 56, 60, 40, 60, 12, 29, 61, + 62, 25, 25, 27, 27, 15, 51, 36, 29, 15, + 29, 61, 62, 12, 38, 38, 8, 29, 7, 7, + 29, -1, 8, -1, 34, 8, 36, 25, 34, 27, + 36, 15, 61, 62, 61, 62, 61, 62, 7, 29, + 38, 91, 57, 7, 75, 33, 8, 25, 63, 27, + 34, -1, 36, -1, 75, 86, 75, 12, 57, -1, + 38, 15, -1, 75, 63, 86, 75, 86, 15, 61, + 62, -1, 61, 62, 86, 61, 62, 86, 61, 62, + 34, 25, 36, 27, -1, 75, 33, 34, 29, 36, + 18, 19, 61, 62, 38, 47, 86, 61, 62, 61, + 62, 15, 57, -1, 92, 18, 19, -1, 63, 61, + 62, 29, -1, 18, 19, 18, 19, 45, 46, 33, + 34, -1, 36, 29, -1, 66, 67, 68, -1, -1, + -1, -1, 45, 46, 29, -1, -1, -1, 29, 91, + 45, 46, 45, 46, 23, 24, 29, -1, 66, 67, + 68, 92, 29, 32, 23, 24, 35, 25, 37, 27, + 66, 67, 68, 32, -1, 29, 35, -1, 37, 29, + 38, 66, 67, 68, 92, 66, 67, 68, -1, -1, + 29, -1, -1, 66, 67, 68, 92, 29, -1, 66, + 67, 68, 29, -1, -1, -1, -1, 92, 29, -1, + -1, 92, 66, 67, 68, -1, 66, 67, 68, 92, + -1, -1, -1, -1, 29, 92, -1, 66, 67, 68, + 29, -1, -1, -1, 66, 67, 68, 29, 92, 66, + 67, 68, 92, 23, 24, 66, 67, 68, -1, -1, + -1, 29, 32, 92, -1, 35, -1, 37, 36, 29, + 92, 66, 67, 68, -1, 92, 36, 66, 67, 68, + -1, 92, 23, 24, 66, 67, 68, -1, -1, -1, + 31, 32, -1, -1, 35, -1, 37, 92, 66, 67, + 68, -1, -1, 92, 23, 24, 66, 67, 68, 29, + 92, -1, 31, 32, 23, 24, 35, 29, 37, -1, + -1, -1, 31, 32, 92, 29, 35, -1, 37, -1, + -1, 29, 92, -1, 93, 94, 95, 96, 97, 98, + -1, 61, 62, -1, 29, -1, 66, 67, 68, 61, + 62, -1, -1, 29, 66, 67, 68, 61, 62, -1, + -1, -1, 66, 67, 68, -1, -1, -1, 66, 67, + 68, -1, 92, -1, -1, -1, 61, 62, -1, -1, + 92, 66, 67, 68, -1, 61, 62, 29, 92, -1, + 66, 67, 68, -1, 92, -1, -1, -1, -1, -1, + -1, -1, -1, 23, 24, -1, -1, 92, 3, -1, + -1, 31, 32, -1, -1, 35, 92, 37, 13, 61, + 62, -1, 17, -1, 66, 67, 68, -1, -1, -1, + -1, 26, -1, 28, -1, -1, 31, -1, -1, -1, + -1, -1, -1, -1, 39, -1, 41, 42, -1, -1, + 92, -1, -1, -1, 49, -1, -1, 52, 53, -1, + -1, -1, -1, 58, -1, -1, -1, -1, -1, 64, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, + 13, 3, -1, -1, -1, 80, -1, -1, -1, 22, + -1, 13, -1, -1, -1, 17, 29, -1, -1, -1, + 33, 34, -1, 36, 26, -1, 28, -1, -1, -1, + 43, -1, -1, -1, 47, -1, -1, 39, -1, 41, + 42, -1, -1, -1, -1, -1, -1, 49, -1, -1, + 52, 53, 65, 66, 67, 68, 58, 70, -1, -1, + -1, -1, 64, -1, -1, -1, -1, -1, 81, 82, + 83, 12, 13, -1, 87, -1, -1, -1, 80, 92, + -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, + -1, -1, 33, 34, -1, 36, -1, -1, -1, 12, + 13, -1, 43, -1, -1, -1, 47, -1, -1, 22, + -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, + 33, 34, -1, 36, 65, 66, 67, 68, -1, 70, + 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, + 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, + -1, 92, 65, 66, 67, 68, -1, 70, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 81, 82, + 83, -1, -1, -1, 87, -1, -1, -1, -1, 92, + 12, 13, -1, -1, -1, -1, -1, -1, 12, 13, + 22, -1, -1, -1, -1, -1, -1, 29, 22, -1, + -1, 33, 34, -1, 36, 29, -1, -1, -1, 33, + 34, 43, 36, -1, -1, 47, -1, -1, -1, 43, + -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, + -1, 65, 66, 67, 68, -1, 70, -1, -1, 81, + 82, 83, -1, -1, -1, 87, -1, 81, 82, 83, + 92, -1, -1, 87, -1, -1, -1, -1, 92, 12, + 13, -1, -1, -1, -1, -1, -1, 12, 13, 22, + -1, -1, -1, -1, -1, -1, 29, 22, -1, -1, + 33, 34, -1, 36, 29, -1, -1, -1, 33, 34, + 43, 36, -1, -1, 47, -1, -1, -1, 43, -1, + -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 65, 66, 67, 68, -1, 70, -1, -1, + 65, 66, 67, 68, -1, 70, -1, -1, 81, 82, + 83, -1, -1, -1, 87, -1, 81, 82, 83, 92, + -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, + -1, -1, -1, -1, -1, -1, 10, -1, 12, 13, + -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, + -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, + 34, -1, 36, -1, -1, -1, -1, -1, -1, 43, + -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 65, 66, 67, 68, -1, 70, -1, -1, -1, + -1, 75, -1, -1, -1, -1, -1, 81, 82, 83, + 84, -1, -1, 87, -1, -1, -1, -1, 92, -1, + -1, -1, -1, -1, -1, -1, -1, 10, -1, 12, + 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, + -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, + 33, 34, -1, 36, -1, -1, -1, -1, -1, -1, + 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, + -1, -1, 55, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 65, 66, 67, 68, -1, 70, -1, -1, + -1, -1, 75, -1, -1, -1, -1, -1, 81, 82, + 83, 84, -1, -1, 87, -1, -1, -1, -1, 92, + -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, + -1, 33, 34, -1, 36, -1, -1, -1, -1, -1, + -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, + -1, -1, -1, 55, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, + -1, -1, -1, 75, -1, -1, -1, -1, -1, 81, + 82, 83, 84, -1, -1, 87, -1, -1, -1, -1, + 92, -1, -1, -1, -1, -1, -1, -1, -1, 11, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, + -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, + 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, + -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, + 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, + 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, + 92, -1, -1, -1, -1, -1, -1, -1, -1, 7, + -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, + -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, + 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, + -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, + -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, + -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, + -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, + 68, -1, 70, -1, 72, -1, 74, 75, 76, -1, + -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, + -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, + -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, + -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, + -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, + -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, + -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, + -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, + 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, + -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, + -1, -1, 87, -1, -1, -1, -1, 92, -1, -1, + -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, + -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, + 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, + -1, 53, -1, -1, 56, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, + 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, + 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, + 92, -1, -1, -1, -1, -1, -1, -1, -1, 8, + -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, + -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, + 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, + -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, + -1, -1, 51, -1, 53, -1, -1, 56, -1, -1, + -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, + -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, + -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, + -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, + -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, + -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, + -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, + 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, + -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, + 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, + 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, + 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, + -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, + -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, + -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, + -1, -1, -1, 29, 30, -1, -1, 33, 34, -1, + 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, + -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, + -1, -1, -1, -1, -1, 61, -1, -1, -1, 65, + 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, + 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, + -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, + -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, + 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, + -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, + 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 59, -1, -1, -1, -1, -1, -1, 66, 67, 68, + 69, 70, 71, -1, 73, 74, 75, 76, 77, 78, + -1, -1, 81, 82, 83, 84, 85, 86, -1, -1, + -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, + -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, + -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, + 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, + 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 59, -1, -1, + -1, -1, -1, 65, 66, 67, -1, 69, 70, 71, + -1, 73, 74, 75, 76, 77, 78, -1, -1, 81, + 82, 83, 84, 85, 86, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, + 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, + -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, + -1, -1, -1, -1, 29, 30, 31, 32, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, + -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, + 55, -1, -1, -1, 59, -1, -1, -1, -1, -1, + 65, 66, 67, -1, 69, 70, 71, -1, 73, 74, + 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, + 85, 86, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, + -1, 9, -1, 11, 12, 13, 14, -1, -1, -1, + -1, -1, -1, 21, 22, -1, -1, -1, -1, -1, + -1, 29, 30, -1, -1, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, + -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, -1, -1, 81, 82, 83, 84, 85, -1, 87, + -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, + -1, -1, -1, 4, -1, -1, -1, -1, 9, -1, + 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, + 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, + -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, + -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, + 51, -1, 53, -1, -1, -1, -1, -1, 59, -1, + 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, -1, -1, + 81, 82, 83, 84, 85, -1, 87, -1, -1, -1, + -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 5, 6, -1, -1, 9, 10, 11, 12, 13, + 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, + -1, -1, -1, -1, -1, 29, 30, 31, 32, 33, + 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, + 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, + -1, -1, -1, -1, -1, 59, -1, 61, -1, -1, + -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, + 84, 85, 86, 87, -1, -1, -1, -1, 92, -1, + -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, + -1, -1, 9, 10, 11, 12, 13, 14, -1, 16, + -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, + -1, -1, 29, 30, 31, 32, 33, 34, -1, 36, + -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, + 47, -1, -1, -1, 51, -1, 53, -1, 55, -1, + -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, -1, -1, 81, 82, 83, 84, 85, 86, + 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, + -1, -1, -1, -1, + + 35, 15, 15, 15, 2, 15, 3, 2, 25, 3, + 15, 15, 104, 15, 4, 3, 3, 3, 19, 15, + 2, 21, 15, 15, 3, 67, 25, 3, 19, 2, + 15, 2, 15, 13, 15, 19, 25, 3, 15, 11, + 15, 2, 96, 3, 2, 15, 2, 25, 3, 2, + 15, 100, 15, 93, 3, 2, 15, 98, 15, 2, + 2, 35, 3, 3, 15, 2, 35, 35, 35, 21, + 2, 25, 3, 35, 4, 21, 15, 2, 2, 15, + 2, 4, 3, 3, 3, 35, 2, 35, 21, 3, + 35, 3, 36, 21, 3, 13, 2, 35, 13, -1, + 35, 35, 2, -1, 15, 13, 35, -1, 16, -1, + -1, 40, -1, -1, -1, -1, 13, 44, 44, 46, + 46, 13, 15, -1, 16, -1, 41, 44, -1, 46, + 35, 44, -1, 46, 44, 40, 46, 44, 3, 46, + 44, 44, 44, 44, 41, 44, 49, 49, 49, 44, + 49, 46, 2, 44, 58, 46, 44, 44, 44, 15, + 46, 49, 49, 44, 44, 44, 46, 44, 44, 44, + 49, 15, 49, 49, 44, 81, 44, 52, 44, 60, + 50, 81, 50, 44, 50, 44, 44, 44, 99, 3, + 49, 49, 13, 37, 87, 56, 44, 54, 44, 20, + 3, 49, 48, 68, 44, 44, 44, 44, 48, 48, + 47, 44, 50, 46, 44, 44, 46, 46, 44, 44, + 46, 44, 47, 46, 44, 44, 46, 46, 44, 85, + 46, 3, 13, 31, 44, 15, 44, 35, -1, 49, + 44, 49, 44, 51, 44, 49, -1, 49, 44, 49, + -1, 61, -1, 49, 68, -1, 13, 37, 38, 16, + 41, 57, 66, -1, 66, 68, 66, 44, 44, 44, + -1, -1, 49, 49, 49, 51, 51, 44, 55, 44, + 44, 44, 49, 44, 49, 49, 49, 51, 49, -1, + 53, 13, 59, -1, 13, 5, 68, 16, 20, 18, + 5, 66, -1, 13, -1, 66, 28, 29, 13, -1, + 20, -1, -1, -1, -1, 20, 35, -1, 28, 29, + 13, -1, -1, 28, 29, -1, -1, 20, 21, 22, + 23, 24, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, + -1, -1, -1, -1, -1, -1, 20, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1}; + +QT_END_NAMESPACE diff --git a/src/declarative/qml/parser/qdeclarativejsgrammar_p.h b/src/declarative/qml/parser/qdeclarativejsgrammar_p.h new file mode 100644 index 00000000..70570766 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsgrammar_p.h @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// This file was generated by qlalr - DO NOT EDIT! +#ifndef QDECLARATIVEJSGRAMMAR_P_H +#define QDECLARATIVEJSGRAMMAR_P_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeJSGrammar +{ +public: + enum VariousConstants { + EOF_SYMBOL = 0, + REDUCE_HERE = 100, + SHIFT_THERE = 99, + T_AND = 1, + T_AND_AND = 2, + T_AND_EQ = 3, + T_AS = 91, + T_AUTOMATIC_SEMICOLON = 62, + T_BREAK = 4, + T_CASE = 5, + T_CATCH = 6, + T_COLON = 7, + T_COMMA = 8, + T_COMMENT = 88, + T_CONST = 84, + T_CONTINUE = 9, + T_DEBUGGER = 85, + T_DEFAULT = 10, + T_DELETE = 11, + T_DIVIDE_ = 12, + T_DIVIDE_EQ = 13, + T_DO = 14, + T_DOT = 15, + T_ELSE = 16, + T_EQ = 17, + T_EQ_EQ = 18, + T_EQ_EQ_EQ = 19, + T_FALSE = 83, + T_FEED_JS_EXPRESSION = 96, + T_FEED_JS_PROGRAM = 98, + T_FEED_JS_SOURCE_ELEMENT = 97, + T_FEED_JS_STATEMENT = 95, + T_FEED_UI_OBJECT_MEMBER = 94, + T_FEED_UI_PROGRAM = 93, + T_FINALLY = 20, + T_FOR = 21, + T_FUNCTION = 22, + T_GE = 23, + T_GT = 24, + T_GT_GT = 25, + T_GT_GT_EQ = 26, + T_GT_GT_GT = 27, + T_GT_GT_GT_EQ = 28, + T_IDENTIFIER = 29, + T_IF = 30, + T_IMPORT = 90, + T_IN = 31, + T_INSTANCEOF = 32, + T_LBRACE = 33, + T_LBRACKET = 34, + T_LE = 35, + T_LPAREN = 36, + T_LT = 37, + T_LT_LT = 38, + T_LT_LT_EQ = 39, + T_MINUS = 40, + T_MINUS_EQ = 41, + T_MINUS_MINUS = 42, + T_MULTILINE_STRING_LITERAL = 87, + T_NEW = 43, + T_NOT = 44, + T_NOT_EQ = 45, + T_NOT_EQ_EQ = 46, + T_NULL = 81, + T_NUMERIC_LITERAL = 47, + T_ON = 92, + T_OR = 48, + T_OR_EQ = 49, + T_OR_OR = 50, + T_PLUS = 51, + T_PLUS_EQ = 52, + T_PLUS_PLUS = 53, + T_PROPERTY = 66, + T_PUBLIC = 89, + T_QUESTION = 54, + T_RBRACE = 55, + T_RBRACKET = 56, + T_READONLY = 68, + T_REMAINDER = 57, + T_REMAINDER_EQ = 58, + T_RESERVED_WORD = 86, + T_RETURN = 59, + T_RPAREN = 60, + T_SEMICOLON = 61, + T_SIGNAL = 67, + T_STAR = 63, + T_STAR_EQ = 64, + T_STRING_LITERAL = 65, + T_SWITCH = 69, + T_THIS = 70, + T_THROW = 71, + T_TILDE = 72, + T_TRUE = 82, + T_TRY = 73, + T_TYPEOF = 74, + T_VAR = 75, + T_VOID = 76, + T_WHILE = 77, + T_WITH = 78, + T_XOR = 79, + T_XOR_EQ = 80, + + ACCEPT_STATE = 645, + RULE_COUNT = 347, + STATE_COUNT = 646, + TERMINAL_COUNT = 101, + NON_TERMINAL_COUNT = 106, + + GOTO_INDEX_OFFSET = 646, + GOTO_INFO_OFFSET = 2714, + GOTO_CHECK_OFFSET = 2714 + }; + + static const char *const spell []; + static const short lhs []; + static const short rhs []; + static const short goto_default []; + static const short action_default []; + static const short action_index []; + static const short action_info []; + static const short action_check []; + + static inline int nt_action (int state, int nt) + { + const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; + if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) + return goto_default [nt]; + + return action_info [GOTO_INFO_OFFSET + yyn]; + } + + static inline int t_action (int state, int token) + { + const int yyn = action_index [state] + token; + + if (yyn < 0 || action_check [yyn] != token) + return - action_default [state]; + + return action_info [yyn]; + } +}; + + +QT_END_NAMESPACE +#endif // QDECLARATIVEJSGRAMMAR_P_H + diff --git a/src/declarative/qml/parser/qdeclarativejslexer.cpp b/src/declarative/qml/parser/qdeclarativejslexer.cpp new file mode 100644 index 00000000..0fa18be7 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejslexer.cpp @@ -0,0 +1,1258 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "private/qdeclarativejslexer_p.h" + +#include "private/qdeclarativejsglobal_p.h" +#include "private/qdeclarativejsengine_p.h" +#include "private/qdeclarativejsgrammar_p.h" + +#include <QtCore/qcoreapplication.h> + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +QT_BEGIN_NAMESPACE +Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); +QT_END_NAMESPACE + +QT_QML_BEGIN_NAMESPACE + +#define shiftWindowsLineBreak() \ + do { \ + if (((current == '\r') && (next1 == '\n')) \ + || ((current == '\n') && (next1 == '\r'))) { \ + shift(1); \ + } \ + } \ + while (0) + +namespace QDeclarativeJS { +extern double integerFromString(const char *buf, int size, int radix); +} + +using namespace QDeclarativeJS; + +Lexer::Lexer(Engine *eng, bool tokenizeComments) + : driver(eng), + yylineno(0), + done(false), + size8(128), size16(128), + pos8(0), pos16(0), + terminator(false), + restrKeyword(false), + delimited(false), + stackToken(-1), + state(Start), + pos(0), + code(0), length(0), + yycolumn(0), + startpos(0), + startlineno(0), startcolumn(0), + bol(true), + current(0), next1(0), next2(0), next3(0), + err(NoError), + wantRx(false), + check_reserved(true), + parenthesesState(IgnoreParentheses), + parenthesesCount(0), + prohibitAutomaticSemicolon(false), + tokenizeComments(tokenizeComments) +{ + if (driver) driver->setLexer(this); + // allocate space for read buffers + buffer8 = new char[size8]; + buffer16 = new QChar[size16]; + pattern = 0; + flags = 0; + +} + +Lexer::~Lexer() +{ + delete [] buffer8; + delete [] buffer16; +} + +void Lexer::setCode(const QString &c, int lineno) +{ + errmsg.clear(); + yylineno = lineno; + yycolumn = 1; + restrKeyword = false; + delimited = false; + stackToken = -1; + pos = 0; + code = c.unicode(); + length = c.length(); + bol = true; + + // read first characters + current = (length > 0) ? code[0].unicode() : 0; + next1 = (length > 1) ? code[1].unicode() : 0; + next2 = (length > 2) ? code[2].unicode() : 0; + next3 = (length > 3) ? code[3].unicode() : 0; +} + +void Lexer::shift(uint p) +{ + while (p--) { + ++pos; + ++yycolumn; + current = next1; + next1 = next2; + next2 = next3; + next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0; + } +} + +void Lexer::setDone(State s) +{ + state = s; + done = true; +} + +int Lexer::findReservedWord(const QChar *c, int size) const +{ + switch (size) { + case 2: { + if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o')) + return QDeclarativeJSGrammar::T_DO; + else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('f')) + return QDeclarativeJSGrammar::T_IF; + else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')) + return QDeclarativeJSGrammar::T_IN; + else if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('s')) + return QDeclarativeJSGrammar::T_AS; + else if (c[0] == QLatin1Char('o') && c[1] == QLatin1Char('n')) + return QDeclarativeJSGrammar::T_ON; + } break; + + case 3: { + if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('o') && c[2] == QLatin1Char('r')) + return QDeclarativeJSGrammar::T_FOR; + else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('e') && c[2] == QLatin1Char('w')) + return QDeclarativeJSGrammar::T_NEW; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') && c[2] == QLatin1Char('y')) + return QDeclarativeJSGrammar::T_TRY; + else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('a') && c[2] == QLatin1Char('r')) + return QDeclarativeJSGrammar::T_VAR; + else if (check_reserved) { + if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') && c[2] == QLatin1Char('t')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + } + } break; + + case 4: { + if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a') + && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_CASE; + else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('l') + && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_ELSE; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('s')) + return QDeclarativeJSGrammar::T_THIS; + else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('d')) + return QDeclarativeJSGrammar::T_VOID; + else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('i') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('h')) + return QDeclarativeJSGrammar::T_WITH; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_TRUE; + else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('u') + && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('l')) + return QDeclarativeJSGrammar::T_NULL; + else if (check_reserved) { + if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('n') + && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('m')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('y') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('l') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('g')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('r')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('g') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('o')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + } + } break; + + case 5: { + if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('e') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('k')) + return QDeclarativeJSGrammar::T_BREAK; + else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('c') + && c[4] == QLatin1Char('h')) + return QDeclarativeJSGrammar::T_CATCH; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o') + && c[4] == QLatin1Char('w')) + return QDeclarativeJSGrammar::T_THROW; + else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('l') + && c[4] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_WHILE; + else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('s') + && c[4] == QLatin1Char('t')) + return QDeclarativeJSGrammar::T_CONST; + else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('a') + && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('s') + && c[4] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_FALSE; + else if (check_reserved) { + if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('r') + && c[4] == QLatin1Char('t')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('u') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e') + && c[4] == QLatin1Char('r')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('l')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('l') + && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('s') + && c[4] == QLatin1Char('s')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('l') + && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('t')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + } + } break; + + case 6: { + if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') + && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('e') + && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_DELETE; + else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('u') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('n')) + return QDeclarativeJSGrammar::T_RETURN; + else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('w') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('c') && c[5] == QLatin1Char('h')) + return QDeclarativeJSGrammar::T_SWITCH; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('y') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e') + && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('f')) + return QDeclarativeJSGrammar::T_TYPEOF; + else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) + return QDeclarativeJSGrammar::T_IMPORT; + else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('i') + && c[2] == QLatin1Char('g') && c[3] == QLatin1Char('n') + && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('l')) + return QDeclarativeJSGrammar::T_SIGNAL; + else if (check_reserved) { + if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('t') + && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('b') + && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('u') + && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('l') + && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c')) + return QDeclarativeJSGrammar::T_PUBLIC; + else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('a') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('i') + && c[4] == QLatin1Char('v') && c[5] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') + && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o') + && c[4] == QLatin1Char('w') && c[5] == QLatin1Char('s')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + } + } break; + + case 7: { + if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') + && c[2] == QLatin1Char('f') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('u') && c[5] == QLatin1Char('l') + && c[6] == QLatin1Char('t')) + return QDeclarativeJSGrammar::T_DEFAULT; + else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('l') + && c[6] == QLatin1Char('y')) + return QDeclarativeJSGrammar::T_FINALLY; + else if (check_reserved) { + if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('l') + && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('a') + && c[6] == QLatin1Char('n')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e') + && c[4] == QLatin1Char('n') && c[5] == QLatin1Char('d') + && c[6] == QLatin1Char('s')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('a') + && c[2] == QLatin1Char('c') && c[3] == QLatin1Char('k') + && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('g') + && c[6] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('v') + && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('t') + && c[6] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + } + } break; + + case 8: { + if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('n') + && c[6] == QLatin1Char('u') && c[7] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_CONTINUE; + else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('u') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c') + && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i') + && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n')) + return QDeclarativeJSGrammar::T_FUNCTION; + else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') + && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('u') + && c[4] == QLatin1Char('g') && c[5] == QLatin1Char('g') + && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('r')) + return QDeclarativeJSGrammar::T_DEBUGGER; + else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('p') + && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('r') + && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('y')) + return QDeclarativeJSGrammar::T_PROPERTY; + else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e') + && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('d') + && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('n') + && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('y')) + return QDeclarativeJSGrammar::T_READONLY; + else if (check_reserved) { + if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('b') + && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('a') + && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('t')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o') + && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('a') + && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i') + && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + } + } break; + + case 9: { + if (check_reserved) { + if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') + && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e') + && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('f') + && c[6] == QLatin1Char('a') && c[7] == QLatin1Char('c') + && c[8] == QLatin1Char('e')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('n') + && c[4] == QLatin1Char('s') && c[5] == QLatin1Char('i') + && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n') + && c[8] == QLatin1Char('t')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') + && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('c') + && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('e') + && c[8] == QLatin1Char('d')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + } + } break; + + case 10: { + if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') + && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t') + && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('n') + && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('e') + && c[8] == QLatin1Char('o') && c[9] == QLatin1Char('f')) + return QDeclarativeJSGrammar::T_INSTANCEOF; + else if (check_reserved) { + if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') + && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('l') + && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('m') + && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n') + && c[8] == QLatin1Char('t') && c[9] == QLatin1Char('s')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + } + } break; + + case 12: { + if (check_reserved) { + if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('y') + && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c') + && c[4] == QLatin1Char('h') && c[5] == QLatin1Char('r') + && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n') + && c[8] == QLatin1Char('i') && c[9] == QLatin1Char('z') + && c[10] == QLatin1Char('e') && c[11] == QLatin1Char('d')) + return QDeclarativeJSGrammar::T_RESERVED_WORD; + } + } break; + + } // switch + + return -1; +} + +int Lexer::lex() +{ + int token = 0; + state = Start; + ushort stringType = 0; // either single or double quotes + bool multiLineString = false; + pos8 = pos16 = 0; + done = false; + terminator = false; + + // did we push a token on the stack previously ? + // (after an automatic semicolon insertion) + if (stackToken >= 0) { + setDone(Other); + token = stackToken; + stackToken = -1; + } + + bool identifierWithEscapedUnicode = false; + + while (!done) { + switch (state) { + case Start: + if (isWhiteSpace()) { + // do nothing + } else if (current == '/' && next1 == '/') { + recordStartPos(); + shift(1); + state = InSingleLineComment; + } else if (current == '/' && next1 == '*') { + recordStartPos(); + shift(1); + state = InMultiLineComment; + } else if (current == 0) { + syncProhibitAutomaticSemicolon(); + if (!terminator && !delimited && !prohibitAutomaticSemicolon) { + // automatic semicolon insertion if program incomplete + token = QDeclarativeJSGrammar::T_SEMICOLON; + stackToken = 0; + setDone(Other); + } else { + setDone(Eof); + } + } else if (isLineTerminator()) { + if (restrKeyword) { + // automatic semicolon insertion + recordStartPos(); + token = QDeclarativeJSGrammar::T_SEMICOLON; + setDone(Other); + } else { + shiftWindowsLineBreak(); + yylineno++; + yycolumn = 0; + bol = true; + terminator = true; + syncProhibitAutomaticSemicolon(); + } + } else if (current == '"' || current == '\'') { + recordStartPos(); + state = InString; + multiLineString = false; + stringType = current; + } else if (current == '\\' && next1 == 'u') { + identifierWithEscapedUnicode = true; + recordStartPos(); + + shift(2); // skip the unicode escape prefix `\u' + + if (isHexDigit(current) && isHexDigit(next1) && + isHexDigit(next2) && isHexDigit(next3)) { + record16(convertUnicode(current, next1, next2, next3)); + shift(3); + state = InIdentifier; + } else { + setDone(Bad); + err = IllegalUnicodeEscapeSequence; + errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence"); + break; + } + + } else if (isIdentLetter(current)) { + identifierWithEscapedUnicode = false; + recordStartPos(); + record16(current); + state = InIdentifier; + } else if (current == '0') { + recordStartPos(); + record8(current); + state = InNum0; + } else if (isDecimalDigit(current)) { + recordStartPos(); + record8(current); + state = InNum; + } else if (current == '.' && isDecimalDigit(next1)) { + recordStartPos(); + record8(current); + state = InDecimal; + } else { + recordStartPos(); + token = matchPunctuator(current, next1, next2, next3); + if (token != -1) { + if (terminator && !delimited && !prohibitAutomaticSemicolon + && (token == QDeclarativeJSGrammar::T_PLUS_PLUS + || token == QDeclarativeJSGrammar::T_MINUS_MINUS)) { + // automatic semicolon insertion + stackToken = token; + token = QDeclarativeJSGrammar::T_SEMICOLON; + } + setDone(Other); + } + else { + setDone(Bad); + err = IllegalCharacter; + errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal character"); + } + } + break; + case InString: + if (current == stringType) { + shift(1); + setDone(String); + } else if (isLineTerminator()) { + multiLineString = true; + record16(current); + } else if (current == 0 || isLineTerminator()) { + setDone(Bad); + err = UnclosedStringLiteral; + errmsg = QCoreApplication::translate("QDeclarativeParser", "Unclosed string at end of line"); + } else if (current == '\\') { + state = InEscapeSequence; + } else { + record16(current); + } + break; + // Escape Sequences inside of strings + case InEscapeSequence: + if (isOctalDigit(current)) { + if (current >= '0' && current <= '3' && + isOctalDigit(next1) && isOctalDigit(next2)) { + record16(convertOctal(current, next1, next2)); + shift(2); + state = InString; + } else if (isOctalDigit(current) && + isOctalDigit(next1)) { + record16(convertOctal('0', current, next1)); + shift(1); + state = InString; + } else if (isOctalDigit(current)) { + record16(convertOctal('0', '0', current)); + state = InString; + } else { + setDone(Bad); + err = IllegalEscapeSequence; + errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal escape sequence"); + } + } else if (current == 'x') + state = InHexEscape; + else if (current == 'u') + state = InUnicodeEscape; + else { + if (isLineTerminator()) { + shiftWindowsLineBreak(); + yylineno++; + yycolumn = 0; + bol = true; + } else { + record16(singleEscape(current)); + } + state = InString; + } + break; + case InHexEscape: + if (isHexDigit(current) && isHexDigit(next1)) { + state = InString; + record16(QLatin1Char(convertHex(current, next1))); + shift(1); + } else if (current == stringType) { + record16(QLatin1Char('x')); + shift(1); + setDone(String); + } else { + record16(QLatin1Char('x')); + record16(current); + state = InString; + } + break; + case InUnicodeEscape: + if (isHexDigit(current) && isHexDigit(next1) && + isHexDigit(next2) && isHexDigit(next3)) { + record16(convertUnicode(current, next1, next2, next3)); + shift(3); + state = InString; + } else if (current == stringType) { + record16(QLatin1Char('u')); + shift(1); + setDone(String); + } else { + setDone(Bad); + err = IllegalUnicodeEscapeSequence; + errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence"); + } + break; + case InSingleLineComment: + if (isLineTerminator()) { + shiftWindowsLineBreak(); + yylineno++; + yycolumn = 0; + terminator = true; + bol = true; + if (restrKeyword) { + token = QDeclarativeJSGrammar::T_SEMICOLON; + setDone(Other); + } else + state = Start; + if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2); + } else if (current == 0) { + if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2); + setDone(Eof); + } + + break; + case InMultiLineComment: + if (current == 0) { + setDone(Bad); + err = UnclosedComment; + errmsg = QCoreApplication::translate("QDeclarativeParser", "Unclosed comment at end of file"); + if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2); + } else if (isLineTerminator()) { + shiftWindowsLineBreak(); + yylineno++; + } else if (current == '*' && next1 == '/') { + state = Start; + shift(1); + if (driver) driver->addComment(startpos+2, tokenLength()-3, startlineno, startcolumn+2); + } + + break; + case InIdentifier: + if (isIdentLetter(current) || isDecimalDigit(current)) { + record16(current); + break; + } else if (current == '\\' && next1 == 'u') { + identifierWithEscapedUnicode = true; + shift(2); // skip the unicode escape prefix `\u' + + if (isHexDigit(current) && isHexDigit(next1) && + isHexDigit(next2) && isHexDigit(next3)) { + record16(convertUnicode(current, next1, next2, next3)); + shift(3); + break; + } else { + setDone(Bad); + err = IllegalUnicodeEscapeSequence; + errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence"); + break; + } + } + setDone(Identifier); + break; + case InNum0: + if (current == 'x' || current == 'X') { + record8(current); + state = InHex; + } else if (current == '.') { + record8(current); + state = InDecimal; + } else if (current == 'e' || current == 'E') { + record8(current); + state = InExponentIndicator; + } else if (isOctalDigit(current)) { + record8(current); + state = InOctal; + } else if (isDecimalDigit(current)) { + record8(current); + state = InDecimal; + } else { + setDone(Number); + } + break; + case InHex: + if (isHexDigit(current)) + record8(current); + else + setDone(Hex); + break; + case InOctal: + if (isOctalDigit(current)) { + record8(current); + } else if (isDecimalDigit(current)) { + record8(current); + state = InDecimal; + } else { + setDone(Octal); + } + break; + case InNum: + if (isDecimalDigit(current)) { + record8(current); + } else if (current == '.') { + record8(current); + state = InDecimal; + } else if (current == 'e' || current == 'E') { + record8(current); + state = InExponentIndicator; + } else { + setDone(Number); + } + break; + case InDecimal: + if (isDecimalDigit(current)) { + record8(current); + } else if (current == 'e' || current == 'E') { + record8(current); + state = InExponentIndicator; + } else { + setDone(Number); + } + break; + case InExponentIndicator: + if (current == '+' || current == '-') { + record8(current); + } else if (isDecimalDigit(current)) { + record8(current); + state = InExponent; + } else { + setDone(Bad); + err = IllegalExponentIndicator; + errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal syntax for exponential number"); + } + break; + case InExponent: + if (isDecimalDigit(current)) { + record8(current); + } else { + setDone(Number); + } + break; + default: + Q_ASSERT_X(0, "Lexer::lex", "Unhandled state in switch statement"); + } + + // move on to the next character + if (!done) + shift(1); + if (state != Start && state != InSingleLineComment) + bol = false; + } + + // no identifiers allowed directly after numeric literal, e.g. "3in" is bad + if ((state == Number || state == Octal || state == Hex) + && isIdentLetter(current)) { + state = Bad; + err = IllegalIdentifier; + errmsg = QCoreApplication::translate("QDeclarativeParser", "Identifier cannot start with numeric literal"); + } + + // terminate string + buffer8[pos8] = '\0'; + + double dval = 0; + if (state == Number) { + dval = qstrtod(buffer8, 0, 0); + } else if (state == Hex) { // scan hex numbers + dval = integerFromString(buffer8, pos8, 16); + state = Number; + } else if (state == Octal) { // scan octal number + dval = integerFromString(buffer8, pos8, 8); + state = Number; + } + + restrKeyword = false; + delimited = false; + + switch (parenthesesState) { + case IgnoreParentheses: + break; + case CountParentheses: + if (token == QDeclarativeJSGrammar::T_RPAREN) { + --parenthesesCount; + if (parenthesesCount == 0) + parenthesesState = BalancedParentheses; + } else if (token == QDeclarativeJSGrammar::T_LPAREN) { + ++parenthesesCount; + } + break; + case BalancedParentheses: + parenthesesState = IgnoreParentheses; + break; + } + + switch (state) { + case Eof: + return 0; + case Other: + if (token == QDeclarativeJSGrammar::T_RBRACE || token == QDeclarativeJSGrammar::T_SEMICOLON) + delimited = true; + return token; + case Identifier: + token = -1; + if (! identifierWithEscapedUnicode) + token = findReservedWord(buffer16, pos16); + + if (token < 0) { + /* TODO: close leak on parse error. same holds true for String */ + if (driver) + qsyylval.ustr = driver->intern(buffer16, pos16); + else + qsyylval.ustr = 0; + return QDeclarativeJSGrammar::T_IDENTIFIER; + } + if (token == QDeclarativeJSGrammar::T_CONTINUE || token == QDeclarativeJSGrammar::T_BREAK + || token == QDeclarativeJSGrammar::T_RETURN || token == QDeclarativeJSGrammar::T_THROW) { + restrKeyword = true; + } else if (token == QDeclarativeJSGrammar::T_IF || token == QDeclarativeJSGrammar::T_FOR + || token == QDeclarativeJSGrammar::T_WHILE || token == QDeclarativeJSGrammar::T_WITH) { + parenthesesState = CountParentheses; + parenthesesCount = 0; + } else if (token == QDeclarativeJSGrammar::T_DO) { + parenthesesState = BalancedParentheses; + } + return token; + case String: + if (driver) + qsyylval.ustr = driver->intern(buffer16, pos16); + else + qsyylval.ustr = 0; + return multiLineString?QDeclarativeJSGrammar::T_MULTILINE_STRING_LITERAL:QDeclarativeJSGrammar::T_STRING_LITERAL; + case Number: + qsyylval.dval = dval; + return QDeclarativeJSGrammar::T_NUMERIC_LITERAL; + case Bad: + return -1; + default: + Q_ASSERT(!"unhandled numeration value in switch"); + return -1; + } +} + +bool Lexer::isWhiteSpace() const +{ + return (current == ' ' || current == '\t' || + current == 0x0b || current == 0x0c); +} + +bool Lexer::isLineTerminator() const +{ + return (current == '\n' || current == '\r'); +} + +bool Lexer::isIdentLetter(ushort c) +{ + // ASCII-biased, since all reserved words are ASCII, aand hence the + // bulk of content to be parsed. + if ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || c == '$' + || c == '_') + return true; + if (c < 128) + return false; + return QChar(c).isLetterOrNumber(); +} + +bool Lexer::isDecimalDigit(ushort c) +{ + return (c >= '0' && c <= '9'); +} + +bool Lexer::isHexDigit(ushort c) const +{ + return ((c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F')); +} + +bool Lexer::isOctalDigit(ushort c) const +{ + return (c >= '0' && c <= '7'); +} + +int Lexer::matchPunctuator(ushort c1, ushort c2, + ushort c3, ushort c4) +{ + if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') { + shift(4); + return QDeclarativeJSGrammar::T_GT_GT_GT_EQ; + } else if (c1 == '=' && c2 == '=' && c3 == '=') { + shift(3); + return QDeclarativeJSGrammar::T_EQ_EQ_EQ; + } else if (c1 == '!' && c2 == '=' && c3 == '=') { + shift(3); + return QDeclarativeJSGrammar::T_NOT_EQ_EQ; + } else if (c1 == '>' && c2 == '>' && c3 == '>') { + shift(3); + return QDeclarativeJSGrammar::T_GT_GT_GT; + } else if (c1 == '<' && c2 == '<' && c3 == '=') { + shift(3); + return QDeclarativeJSGrammar::T_LT_LT_EQ; + } else if (c1 == '>' && c2 == '>' && c3 == '=') { + shift(3); + return QDeclarativeJSGrammar::T_GT_GT_EQ; + } else if (c1 == '<' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_LE; + } else if (c1 == '>' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_GE; + } else if (c1 == '!' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_NOT_EQ; + } else if (c1 == '+' && c2 == '+') { + shift(2); + return QDeclarativeJSGrammar::T_PLUS_PLUS; + } else if (c1 == '-' && c2 == '-') { + shift(2); + return QDeclarativeJSGrammar::T_MINUS_MINUS; + } else if (c1 == '=' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_EQ_EQ; + } else if (c1 == '+' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_PLUS_EQ; + } else if (c1 == '-' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_MINUS_EQ; + } else if (c1 == '*' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_STAR_EQ; + } else if (c1 == '/' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_DIVIDE_EQ; + } else if (c1 == '&' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_AND_EQ; + } else if (c1 == '^' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_XOR_EQ; + } else if (c1 == '%' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_REMAINDER_EQ; + } else if (c1 == '|' && c2 == '=') { + shift(2); + return QDeclarativeJSGrammar::T_OR_EQ; + } else if (c1 == '<' && c2 == '<') { + shift(2); + return QDeclarativeJSGrammar::T_LT_LT; + } else if (c1 == '>' && c2 == '>') { + shift(2); + return QDeclarativeJSGrammar::T_GT_GT; + } else if (c1 == '&' && c2 == '&') { + shift(2); + return QDeclarativeJSGrammar::T_AND_AND; + } else if (c1 == '|' && c2 == '|') { + shift(2); + return QDeclarativeJSGrammar::T_OR_OR; + } + + switch(c1) { + case '=': shift(1); return QDeclarativeJSGrammar::T_EQ; + case '>': shift(1); return QDeclarativeJSGrammar::T_GT; + case '<': shift(1); return QDeclarativeJSGrammar::T_LT; + case ',': shift(1); return QDeclarativeJSGrammar::T_COMMA; + case '!': shift(1); return QDeclarativeJSGrammar::T_NOT; + case '~': shift(1); return QDeclarativeJSGrammar::T_TILDE; + case '?': shift(1); return QDeclarativeJSGrammar::T_QUESTION; + case ':': shift(1); return QDeclarativeJSGrammar::T_COLON; + case '.': shift(1); return QDeclarativeJSGrammar::T_DOT; + case '+': shift(1); return QDeclarativeJSGrammar::T_PLUS; + case '-': shift(1); return QDeclarativeJSGrammar::T_MINUS; + case '*': shift(1); return QDeclarativeJSGrammar::T_STAR; + case '/': shift(1); return QDeclarativeJSGrammar::T_DIVIDE_; + case '&': shift(1); return QDeclarativeJSGrammar::T_AND; + case '|': shift(1); return QDeclarativeJSGrammar::T_OR; + case '^': shift(1); return QDeclarativeJSGrammar::T_XOR; + case '%': shift(1); return QDeclarativeJSGrammar::T_REMAINDER; + case '(': shift(1); return QDeclarativeJSGrammar::T_LPAREN; + case ')': shift(1); return QDeclarativeJSGrammar::T_RPAREN; + case '{': shift(1); return QDeclarativeJSGrammar::T_LBRACE; + case '}': shift(1); return QDeclarativeJSGrammar::T_RBRACE; + case '[': shift(1); return QDeclarativeJSGrammar::T_LBRACKET; + case ']': shift(1); return QDeclarativeJSGrammar::T_RBRACKET; + case ';': shift(1); return QDeclarativeJSGrammar::T_SEMICOLON; + + default: return -1; + } +} + +ushort Lexer::singleEscape(ushort c) const +{ + switch(c) { + case 'b': + return 0x08; + case 't': + return 0x09; + case 'n': + return 0x0A; + case 'v': + return 0x0B; + case 'f': + return 0x0C; + case 'r': + return 0x0D; + case '"': + return 0x22; + case '\'': + return 0x27; + case '\\': + return 0x5C; + default: + return c; + } +} + +ushort Lexer::convertOctal(ushort c1, ushort c2, + ushort c3) const +{ + return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0'); +} + +unsigned char Lexer::convertHex(ushort c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + else if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + else + return (c - 'A' + 10); +} + +unsigned char Lexer::convertHex(ushort c1, ushort c2) +{ + return ((convertHex(c1) << 4) + convertHex(c2)); +} + +QChar Lexer::convertUnicode(ushort c1, ushort c2, + ushort c3, ushort c4) +{ + return QChar((convertHex(c3) << 4) + convertHex(c4), + (convertHex(c1) << 4) + convertHex(c2)); +} + +void Lexer::record8(ushort c) +{ + Q_ASSERT(c <= 0xff); + + // enlarge buffer if full + if (pos8 >= size8 - 1) { + char *tmp = new char[2 * size8]; + memcpy(tmp, buffer8, size8 * sizeof(char)); + delete [] buffer8; + buffer8 = tmp; + size8 *= 2; + } + + buffer8[pos8++] = (char) c; +} + +void Lexer::record16(QChar c) +{ + // enlarge buffer if full + if (pos16 >= size16 - 1) { + QChar *tmp = new QChar[2 * size16]; + memcpy(tmp, buffer16, size16 * sizeof(QChar)); + delete [] buffer16; + buffer16 = tmp; + size16 *= 2; + } + + buffer16[pos16++] = c; +} + +void Lexer::recordStartPos() +{ + startpos = pos; + startlineno = yylineno; + startcolumn = yycolumn; +} + +bool Lexer::scanRegExp(RegExpBodyPrefix prefix) +{ + pos16 = 0; + pattern = 0; + + if (prefix == EqualPrefix) + record16(QLatin1Char('=')); + + while (true) { + switch (current) { + + case 0: // eof + case '\n': case '\r': // line terminator + errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression literal"); + return false; + + case '/': + shift(1); + + if (driver) // create the pattern + pattern = driver->intern(buffer16, pos16); + + // scan the flags + pos16 = 0; + flags = 0; + while (isIdentLetter(current)) { + int flag = Ecma::RegExp::flagFromChar(current); + if (flag == 0) { + errmsg = QCoreApplication::translate("QDeclarativeParser", "Invalid regular expression flag '%0'") + .arg(QChar(current)); + return false; + } + flags |= flag; + record16(current); + shift(1); + } + return true; + + case '\\': + // regular expression backslash sequence + record16(current); + shift(1); + + if (! current || isLineTerminator()) { + errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression backslash sequence"); + return false; + } + + record16(current); + shift(1); + break; + + case '[': + // regular expression class + record16(current); + shift(1); + + while (current && ! isLineTerminator()) { + if (current == ']') + break; + else if (current == '\\') { + // regular expression backslash sequence + record16(current); + shift(1); + + if (! current || isLineTerminator()) { + errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression backslash sequence"); + return false; + } + + record16(current); + shift(1); + } else { + record16(current); + shift(1); + } + } + + if (current != ']') { + errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression class"); + return false; + } + + record16(current); + shift(1); // skip ] + break; + + default: + record16(current); + shift(1); + } // switch + } // while + + return false; +} + +void Lexer::syncProhibitAutomaticSemicolon() +{ + if (parenthesesState == BalancedParentheses) { + // we have seen something like "if (foo)", which means we should + // never insert an automatic semicolon at this point, since it would + // then be expanded into an empty statement (ECMA-262 7.9.1) + prohibitAutomaticSemicolon = true; + parenthesesState = IgnoreParentheses; + } else { + prohibitAutomaticSemicolon = false; + } +} + +QT_QML_END_NAMESPACE + + diff --git a/src/declarative/qml/parser/qdeclarativejslexer_p.h b/src/declarative/qml/parser/qdeclarativejslexer_p.h new file mode 100644 index 00000000..10621e54 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejslexer_p.h @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEJSLEXER_P_H +#define QDECLARATIVEJSLEXER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativejsglobal_p.h" + +#include <QtCore/QString> + +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { + +class Engine; +class NameId; + +class QML_PARSER_EXPORT Lexer +{ +public: + Lexer(Engine *eng, bool tokenizeComments = false); + ~Lexer(); + + void setCode(const QString &c, int lineno); + int lex(); + + int currentLineNo() const { return yylineno; } + int currentColumnNo() const { return yycolumn; } + + int tokenOffset() const { return startpos; } + int tokenLength() const { return pos - startpos; } + + int startLineNo() const { return startlineno; } + int startColumnNo() const { return startcolumn; } + + int endLineNo() const { return currentLineNo(); } + int endColumnNo() const + { int col = currentColumnNo(); return (col > 0) ? col - 1 : col; } + + bool prevTerminator() const { return terminator; } + + enum State { Start, + Identifier, + InIdentifier, + InSingleLineComment, + InMultiLineComment, + InNum, + InNum0, + InHex, + InOctal, + InDecimal, + InExponentIndicator, + InExponent, + Hex, + Octal, + Number, + String, + Eof, + InString, + InEscapeSequence, + InHexEscape, + InUnicodeEscape, + Other, + Bad }; + + enum Error { + NoError, + IllegalCharacter, + UnclosedStringLiteral, + IllegalEscapeSequence, + IllegalUnicodeEscapeSequence, + UnclosedComment, + IllegalExponentIndicator, + IllegalIdentifier + }; + + enum ParenthesesState { + IgnoreParentheses, + CountParentheses, + BalancedParentheses + }; + + enum RegExpBodyPrefix { + NoPrefix, + EqualPrefix + }; + + bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix); + + NameId *pattern; + int flags; + + State lexerState() const + { return state; } + + QString errorMessage() const + { return errmsg; } + void setErrorMessage(const QString &err) + { errmsg = err; } + void setErrorMessage(const char *err) + { setErrorMessage(QString::fromLatin1(err)); } + + Error error() const + { return err; } + void clearError() + { err = NoError; } + +private: + Engine *driver; + int yylineno; + bool done; + char *buffer8; + QChar *buffer16; + uint size8, size16; + uint pos8, pos16; + bool terminator; + bool restrKeyword; + // encountered delimiter like "'" and "}" on last run + bool delimited; + int stackToken; + + State state; + void setDone(State s); + uint pos; + void shift(uint p); + int lookupKeyword(const char *); + + bool isWhiteSpace() const; + bool isLineTerminator() const; + bool isHexDigit(ushort c) const; + bool isOctalDigit(ushort c) const; + + int matchPunctuator(ushort c1, ushort c2, + ushort c3, ushort c4); + ushort singleEscape(ushort c) const; + ushort convertOctal(ushort c1, ushort c2, + ushort c3) const; +public: + static unsigned char convertHex(ushort c1); + static unsigned char convertHex(ushort c1, ushort c2); + static QChar convertUnicode(ushort c1, ushort c2, + ushort c3, ushort c4); + static bool isIdentLetter(ushort c); + static bool isDecimalDigit(ushort c); + + inline int ival() const { return qsyylval.ival; } + inline double dval() const { return qsyylval.dval; } + inline NameId *ustr() const { return qsyylval.ustr; } + + const QChar *characterBuffer() const { return buffer16; } + int characterCount() const { return pos16; } + +private: + void record8(ushort c); + void record16(QChar c); + void recordStartPos(); + + int findReservedWord(const QChar *buffer, int size) const; + + void syncProhibitAutomaticSemicolon(); + + const QChar *code; + uint length; + int yycolumn; + int startpos; + int startlineno; + int startcolumn; + int bol; // begin of line + + union { + int ival; + double dval; + NameId *ustr; + } qsyylval; + + // current and following unicode characters + ushort current, next1, next2, next3; + + struct keyword { + const char *name; + int token; + }; + + QString errmsg; + Error err; + + bool wantRx; + bool check_reserved; + + ParenthesesState parenthesesState; + int parenthesesCount; + bool prohibitAutomaticSemicolon; + bool tokenizeComments; +}; + +} // namespace QDeclarativeJS + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h b/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h new file mode 100644 index 00000000..79941ecc --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsmemorypool_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEJSMEMORYPOOL_P_H +#define QDECLARATIVEJSMEMORYPOOL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativejsglobal_p.h" + +#include <QtCore/qglobal.h> +#include <QtCore/qshareddata.h> + +#include <string.h> + +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { + +class QML_PARSER_EXPORT MemoryPool : public QSharedData +{ +public: + enum { maxBlockCount = -1 }; + enum { defaultBlockSize = 1 << 12 }; + + MemoryPool() { + m_blockIndex = maxBlockCount; + m_currentIndex = 0; + m_storage = 0; + m_currentBlock = 0; + m_currentBlockSize = 0; + } + + virtual ~MemoryPool() { + for (int index = 0; index < m_blockIndex + 1; ++index) + qFree(m_storage[index]); + + qFree(m_storage); + } + + char *allocate(int bytes) { + bytes += (8 - bytes) & 7; // ensure multiple of 8 bytes (maintain alignment) + if (m_currentBlock == 0 || m_currentBlockSize < m_currentIndex + bytes) { + ++m_blockIndex; + m_currentBlockSize = defaultBlockSize << m_blockIndex; + + m_storage = reinterpret_cast<char**>(qRealloc(m_storage, sizeof(char*) * (1 + m_blockIndex))); + m_currentBlock = m_storage[m_blockIndex] = reinterpret_cast<char*>(qMalloc(m_currentBlockSize)); + ::memset(m_currentBlock, 0, m_currentBlockSize); + + m_currentIndex = (8 - quintptr(m_currentBlock)) & 7; // ensure first chunk is 64-bit aligned + Q_ASSERT(m_currentIndex + bytes <= m_currentBlockSize); + } + + char *p = reinterpret_cast<char *> + (m_currentBlock + m_currentIndex); + + m_currentIndex += bytes; + + return p; + } + + int bytesAllocated() const { + int bytes = 0; + for (int index = 0; index < m_blockIndex; ++index) + bytes += (defaultBlockSize << index); + bytes += m_currentIndex; + return bytes; + } + +private: + int m_blockIndex; + int m_currentIndex; + char *m_currentBlock; + int m_currentBlockSize; + char **m_storage; + +private: + Q_DISABLE_COPY(MemoryPool) +}; + +} // namespace QDeclarativeJS + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/parser/qdeclarativejsnodepool_p.h b/src/declarative/qml/parser/qdeclarativejsnodepool_p.h new file mode 100644 index 00000000..f9160bd4 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsnodepool_p.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEJSNODEPOOL_P_H +#define QDECLARATIVEJSNODEPOOL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativejsglobal_p.h" +#include "private/qdeclarativejsmemorypool_p.h" + +#include <QtCore/QHash> +#include <QtCore/QString> + +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { + +namespace AST { +class Node; +} // namespace AST + +class Code; +class CompilationUnit; +class Engine; + +template <typename NodeType> +inline NodeType *makeAstNode(MemoryPool *storage) +{ + NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(); + return node; +} + +template <typename NodeType, typename Arg1> +inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1) +{ + NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1); + return node; +} + +template <typename NodeType, typename Arg1, typename Arg2> +inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2) +{ + NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2); + return node; +} + +template <typename NodeType, typename Arg1, typename Arg2, typename Arg3> +inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2, Arg3 arg3) +{ + NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2, arg3); + return node; +} + +template <typename NodeType, typename Arg1, typename Arg2, typename Arg3, typename Arg4> +inline NodeType *makeAstNode(MemoryPool *storage, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) +{ + NodeType *node = new (storage->allocate(sizeof(NodeType))) NodeType(arg1, arg2, arg3, arg4); + return node; +} + +class QML_PARSER_EXPORT NodePool : public MemoryPool +{ +public: + NodePool(const QString &fileName, Engine *engine); + virtual ~NodePool(); + + Code *createCompiledCode(AST::Node *node, CompilationUnit &compilation); + + inline QString fileName() const { return m_fileName; } + inline Engine *engine() const { return m_engine; } +#ifndef J_SCRIPT_NO_EVENT_NOTIFY + inline qint64 id() const { return m_id; } +#endif + +private: + QHash<AST::Node*, Code*> m_codeCache; + QString m_fileName; + Engine *m_engine; +#ifndef J_SCRIPT_NO_EVENT_NOTIFY + qint64 m_id; +#endif + +private: + Q_DISABLE_COPY(NodePool) +}; + +} // namespace QDeclarativeJS + +QT_QML_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/parser/qdeclarativejsparser.cpp b/src/declarative/qml/parser/qdeclarativejsparser.cpp new file mode 100644 index 00000000..da2dd7e5 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsparser.cpp @@ -0,0 +1,1904 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QtDebug> +#include <QtGui/QApplication> + +#include <string.h> + +#include "private/qdeclarativejsengine_p.h" +#include "private/qdeclarativejslexer_p.h" +#include "private/qdeclarativejsast_p.h" +#include "private/qdeclarativejsnodepool_p.h" + + + +#include "private/qdeclarativejsparser_p.h" +#include <QVarLengthArray> + +// +// This file is automatically generated from qmljs.g. +// Changes will be lost. +// + +using namespace QDeclarativeJS; + +QT_QML_BEGIN_NAMESPACE + +void Parser::reallocateStack() +{ + if (! stack_size) + stack_size = 128; + else + stack_size <<= 1; + + sym_stack = reinterpret_cast<Value*> (qRealloc(sym_stack, stack_size * sizeof(Value))); + state_stack = reinterpret_cast<int*> (qRealloc(state_stack, stack_size * sizeof(int))); + location_stack = reinterpret_cast<AST::SourceLocation*> (qRealloc(location_stack, stack_size * sizeof(AST::SourceLocation))); +} + +inline static bool automatic(Engine *driver, int token) +{ + return token == QDeclarativeJSGrammar::T_RBRACE + || token == 0 + || driver->lexer()->prevTerminator(); +} + + +Parser::Parser(Engine *engine): + driver(engine), + tos(0), + stack_size(0), + sym_stack(0), + state_stack(0), + location_stack(0), + first_token(0), + last_token(0) +{ +} + +Parser::~Parser() +{ + if (stack_size) { + qFree(sym_stack); + qFree(state_stack); + qFree(location_stack); + } +} + +static inline AST::SourceLocation location(Lexer *lexer) +{ + AST::SourceLocation loc; + loc.offset = lexer->tokenOffset(); + loc.length = lexer->tokenLength(); + loc.startLine = lexer->startLineNo(); + loc.startColumn = lexer->startColumnNo(); + return loc; +} + +AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) +{ + QVarLengthArray<NameId *, 4> nameIds; + QVarLengthArray<AST::SourceLocation, 4> locations; + + AST::ExpressionNode *it = expr; + while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) { + nameIds.append(m->name); + locations.append(m->identifierToken); + it = m->base; + } + + if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) { + AST::UiQualifiedId *q = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), idExpr->name); + q->identifierToken = idExpr->identifierToken; + + AST::UiQualifiedId *currentId = q; + for (int i = nameIds.size() - 1; i != -1; --i) { + currentId = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), currentId, nameIds[i]); + currentId->identifierToken = locations[i]; + } + + return currentId->finish(); + } + + return 0; +} + +bool Parser::parse(int startToken) +{ + Lexer *lexer = driver->lexer(); + bool hadErrors = false; + int yytoken = -1; + int action = 0; + + token_buffer[0].token = startToken; + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; + + tos = -1; + program = 0; + + do { + if (++tos == stack_size) + reallocateStack(); + + state_stack[tos] = action; + + _Lcheck_token: + if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) { + yyprevlloc = yylloc; + + if (first_token == last_token) { + yytoken = lexer->lex(); + yylval = lexer->dval(); + yylloc = location(lexer); + } else { + yytoken = first_token->token; + yylval = first_token->dval; + yylloc = first_token->loc; + ++first_token; + } + } + + action = t_action(action, yytoken); + if (action > 0) { + if (action != ACCEPT_STATE) { + yytoken = -1; + sym(1).dval = yylval; + loc(1) = yylloc; + } else { + --tos; + return ! hadErrors; + } + } else if (action < 0) { + const int r = -action - 1; + tos -= rhs[r]; + + switch (r) { + +case 0: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 1: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 2: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 3: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 4: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 5: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; + +case 6: { + sym(1).UiProgram = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList, + sym(2).UiObjectMemberList->finish()); +} break; + +case 8: { + sym(1).Node = sym(1).UiImportList->finish(); +} break; + +case 9: { + sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImport); +} break; + +case 10: { + sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), + sym(1).UiImportList, sym(2).UiImport); +} break; + +case 13: { + sym(1).UiImport->semicolonToken = loc(2); +} break; + +case 15: { + sym(1).UiImport->versionToken = loc(2); + sym(1).UiImport->semicolonToken = loc(3); +} break; + +case 17: { + sym(1).UiImport->versionToken = loc(2); + sym(1).UiImport->asToken = loc(3); + sym(1).UiImport->importIdToken = loc(4); + sym(1).UiImport->importId = sym(4).sval; + sym(1).UiImport->semicolonToken = loc(5); +} break; + +case 19: { + sym(1).UiImport->asToken = loc(2); + sym(1).UiImport->importIdToken = loc(3); + sym(1).UiImport->importId = sym(3).sval; + sym(1).UiImport->semicolonToken = loc(4); +} break; + +case 20: { + AST::UiImport *node = 0; + + if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) { + node = makeAstNode<AST::UiImport>(driver->nodePool(), importIdLiteral->value); + node->fileNameToken = loc(2); + } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) { + node = makeAstNode<AST::UiImport>(driver->nodePool(), qualifiedId); + node->fileNameToken = loc(2); + } + + sym(1).Node = node; + + if (node) { + node->importToken = loc(1); + } else { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), + QLatin1String("Expected a qualified name id or a string literal"))); + + return false; // ### remove me + } +} break; + +case 21: { + sym(1).Node = 0; +} break; + +case 22: { + sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; + +case 23: { + sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; + +case 24: { + AST::UiObjectMemberList *node = makeAstNode<AST:: UiObjectMemberList> (driver->nodePool(), + sym(1).UiObjectMemberList, sym(2).UiObjectMember); + sym(1).Node = node; +} break; + +case 25: { + sym(1).Node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), sym(1).UiObjectMember); +} break; + +case 26: { + AST::UiArrayMemberList *node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), + sym(1).UiArrayMemberList, sym(3).UiObjectMember); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 27: { + AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), (AST::UiObjectMemberList*)0); + node->lbraceToken = loc(1); + node->rbraceToken = loc(2); + sym(1).Node = node; +} break; + +case 28: { + AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), sym(2).UiObjectMemberList->finish()); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 29: { + AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId, + sym(2).UiObjectInitializer); + sym(1).Node = node; +} break; + +case 31: { + AST::UiArrayBinding *node = makeAstNode<AST::UiArrayBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish()); + node->colonToken = loc(2); + node->lbracketToken = loc(3); + node->rbracketToken = loc(5); + sym(1).Node = node; +} break; + +case 32: { + AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 33: { + AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), + sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer); + node->colonToken = loc(2); + node->hasOnToken = true; + sym(1).Node = node; +} break; +case 34:case 35:case 36:case 37: +{ + AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(), + sym(1).UiQualifiedId, sym(3).Statement); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 38: + +case 39: { + sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); + break; +} + +case 41: { + sym(1).Node = 0; +} break; + +case 42: { + sym(1).Node = sym(1).UiParameterList->finish (); +} break; + +case 43: { + AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).sval, sym(2).sval); + node->identifierToken = loc(2); + sym(1).Node = node; +} break; + +case 44: { + AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).UiParameterList, sym(3).sval, sym(4).sval); + node->commaToken = loc(2); + node->identifierToken = loc(4); + sym(1).Node = node; +} break; + +case 46: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); + node->type = AST::UiPublicMember::Signal; + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(2); + node->parameters = sym(4).UiParameterList; + node->semicolonToken = loc(6); + sym(1).Node = node; +} break; + +case 48: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); + node->type = AST::UiPublicMember::Signal; + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 50: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval); + node->typeModifier = sym(2).sval; + node->propertyToken = loc(1); + node->typeModifierToken = loc(2); + node->typeToken = loc(4); + node->identifierToken = loc(6); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; + +case 52: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->semicolonToken = loc(4); + sym(1).Node = node; +} break; + +case 54: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval); + node->isDefaultMember = true; + node->defaultToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->semicolonToken = loc(5); + sym(1).Node = node; +} break; + +case 56: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval, + sym(5).Expression); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->colonToken = loc(4); + node->semicolonToken = loc(6); + sym(1).Node = node; +} break; + +case 58: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval, + sym(6).Expression); + node->isReadonlyMember = true; + node->readonlyToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->colonToken = loc(5); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; + +case 60: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval, + sym(6).Expression); + node->isDefaultMember = true; + node->defaultToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->colonToken = loc(5); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; + +case 61: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(4).sval, sym(6).sval); + node->typeModifier = sym(2).sval; + node->propertyToken = loc(1); + node->typeModifierToken = loc(2); + node->typeToken = loc(4); + node->identifierToken = loc(6); + node->semicolonToken = loc(7); // insert a fake ';' before ':' + + AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(6).sval); + propertyName->identifierToken = loc(6); + propertyName->next = 0; + + AST::UiArrayBinding *binding = makeAstNode<AST::UiArrayBinding> (driver->nodePool(), + propertyName, sym(9).UiArrayMemberList->finish()); + binding->colonToken = loc(7); + binding->lbracketToken = loc(8); + binding->rbracketToken = loc(10); + + node->binding = binding; + + sym(1).Node = node; +} break; + +case 62: { + AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval); + node->propertyToken = loc(1); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->semicolonToken = loc(4); // insert a fake ';' before ':' + + AST::UiQualifiedId *propertyName = makeAstNode<AST::UiQualifiedId>(driver->nodePool(), sym(3).sval); + propertyName->identifierToken = loc(3); + propertyName->next = 0; + + AST::UiObjectBinding *binding = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), + propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer); + binding->colonToken = loc(4); + + node->binding = binding; + + sym(1).Node = node; +} break; + +case 63: { + sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); +} break; + +case 64: { + sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); +} break; + +case 66: { + QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_PROPERTY]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} + +case 67: { + QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_SIGNAL]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} + +case 68: { + QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_READONLY]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} + +case 69: { + QString s = QLatin1String(QDeclarativeJSGrammar::spell[T_ON]); + sym(1).sval = driver->intern(s.constData(), s.length()); + break; +} + +case 70: { + AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool()); + node->thisToken = loc(1); + sym(1).Node = node; +} break; + +case 71: { + AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 72: { + AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool()); + node->nullToken = loc(1); + sym(1).Node = node; +} break; + +case 73: { + AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool()); + node->trueToken = loc(1); + sym(1).Node = node; +} break; + +case 74: { + AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool()); + node->falseToken = loc(1); + sym(1).Node = node; +} break; + +case 75: { + AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval); + node->literalToken = loc(1); + sym(1).Node = node; +} break; +case 76: +case 77: { + AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval); + node->literalToken = loc(1); + sym(1).Node = node; +} break; + +case 78: { + bool rx = lexer->scanRegExp(Lexer::NoPrefix); + if (!rx) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); + return false; // ### remove me + } + + loc(1).length = lexer->tokenLength(); + + AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + node->literalToken = loc(1); + sym(1).Node = node; +} break; + +case 79: { + bool rx = lexer->scanRegExp(Lexer::EqualPrefix); + if (!rx) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); + return false; + } + + loc(1).length = lexer->tokenLength(); + + AST::RegExpLiteral *node = makeAstNode<AST::RegExpLiteral> (driver->nodePool(), lexer->pattern, lexer->flags); + node->literalToken = loc(1); + sym(1).Node = node; +} break; + +case 80: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->rbracketToken = loc(2); + sym(1).Node = node; +} break; + +case 81: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish()); + node->lbracketToken = loc(1); + node->rbracketToken = loc(3); + sym(1).Node = node; +} break; + +case 82: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ()); + node->lbracketToken = loc(1); + node->rbracketToken = loc(3); + sym(1).Node = node; +} break; + +case 83: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + (AST::Elision *) 0); + node->lbracketToken = loc(1); + node->commaToken = loc(3); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; + +case 84: { + AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), + sym(4).Elision->finish()); + node->lbracketToken = loc(1); + node->commaToken = loc(3); + node->rbracketToken = loc(5); + sym(1).Node = node; +} break; + +case 85: { + AST::ObjectLiteral *node = 0; + if (sym(2).Node) + node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), + sym(2).PropertyNameAndValueList->finish ()); + else + node = makeAstNode<AST::ObjectLiteral> (driver->nodePool()); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 86: { + AST::ObjectLiteral *node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), + sym(2).PropertyNameAndValueList->finish ()); + node->lbraceToken = loc(1); + node->rbraceToken = loc(4); + sym(1).Node = node; +} break; + +case 87: { + AST::NestedExpression *node = makeAstNode<AST::NestedExpression>(driver->nodePool(), sym(2).Expression); + node->lparenToken = loc(1); + node->rparenToken = loc(3); + sym(1).Node = node; +} break; + +case 88: { + if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) { + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken, + QLatin1String("Ignored annotation"))); + + sym(1).Expression = mem->base; + } + + if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) { + sym(1).UiQualifiedId = qualifiedId; + } else { + sym(1).UiQualifiedId = 0; + + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), + QLatin1String("Expected a qualified name id"))); + + return false; // ### recover + } +} break; + +case 89: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression); +} break; + +case 90: { + sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression); +} break; + +case 91: { + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, + (AST::Elision *) 0, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 92: { + AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(), + sym(4).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 93: { + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool()); + node->commaToken = loc(1); + sym(1).Node = node; +} break; + +case 94: { + AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 95: { + AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), + sym(1).PropertyName, sym(3).Expression); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 96: { + AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), + sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); + node->commaToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; + +case 97: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; +case 98: +case 99: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 100: { + AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 101: { + AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 102: { + AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 103: + +case 104: + +case 105: + +case 106: + +case 107: + +case 108: + +case 109: + +case 110: + +case 111: + +case 112: + +case 113: + +case 114: + +case 115: + +case 116: + +case 117: + +case 118: + +case 119: + +case 120: + +case 121: + +case 122: + +case 123: + +case 124: + +case 125: + +case 126: + +case 127: + +case 128: + +case 129: + +case 130: + +case 131: + +case 132: + +case 133: +{ + sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); +} break; + +case 138: { + AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->lbracketToken = loc(2); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; + +case 139: { + AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + node->dotToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; + +case 140: { + AST::NewMemberExpression *node = makeAstNode<AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList); + node->newToken = loc(1); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + sym(1).Node = node; +} break; + +case 142: { + AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression); + node->newToken = loc(1); + sym(1).Node = node; +} break; + +case 143: { + AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 144: { + AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 145: { + AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->lbracketToken = loc(2); + node->rbracketToken = loc(4); + sym(1).Node = node; +} break; + +case 146: { + AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); + node->dotToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; + +case 147: { + sym(1).Node = 0; +} break; + +case 148: { + sym(1).Node = sym(1).ArgumentList->finish(); +} break; + +case 149: { + sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression); +} break; + +case 150: { + AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 154: { + AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression); + node->incrementToken = loc(2); + sym(1).Node = node; +} break; + +case 155: { + AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression); + node->decrementToken = loc(2); + sym(1).Node = node; +} break; + +case 157: { + AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression); + node->deleteToken = loc(1); + sym(1).Node = node; +} break; + +case 158: { + AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression); + node->voidToken = loc(1); + sym(1).Node = node; +} break; + +case 159: { + AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression); + node->typeofToken = loc(1); + sym(1).Node = node; +} break; + +case 160: { + AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression); + node->incrementToken = loc(1); + sym(1).Node = node; +} break; + +case 161: { + AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression); + node->decrementToken = loc(1); + sym(1).Node = node; +} break; + +case 162: { + AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression); + node->plusToken = loc(1); + sym(1).Node = node; +} break; + +case 163: { + AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression); + node->minusToken = loc(1); + sym(1).Node = node; +} break; + +case 164: { + AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression); + node->tildeToken = loc(1); + sym(1).Node = node; +} break; + +case 165: { + AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression); + node->notToken = loc(1); + sym(1).Node = node; +} break; + +case 167: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Mul, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 168: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Div, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 169: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Mod, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 171: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Add, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 172: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Sub, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 174: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::LShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 175: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::RShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 176: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::URShift, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 178: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Lt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 179: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Gt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 180: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Le, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 181: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Ge, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 182: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::InstanceOf, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 183: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::In, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 185: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Lt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 186: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Gt, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 187: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Le, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 188: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Ge, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 189: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::InstanceOf, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 191: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Equal, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 192: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::NotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 193: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 194: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictNotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 196: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Equal, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 197: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::NotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 198: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 199: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::StrictNotEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 201: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitAnd, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 203: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitAnd, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 205: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitXor, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 207: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitXor, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 209: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitOr, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 211: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::BitOr, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 213: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::And, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 215: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::And, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 217: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Or, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 219: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + QSOperator::Or, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 221: { + AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, + sym(3).Expression, sym(5).Expression); + node->questionToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; + +case 223: { + AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, + sym(3).Expression, sym(5).Expression); + node->questionToken = loc(2); + node->colonToken = loc(4); + sym(1).Node = node; +} break; + +case 225: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + sym(2).ival, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 227: { + AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, + sym(2).ival, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 228: { + sym(1).ival = QSOperator::Assign; +} break; + +case 229: { + sym(1).ival = QSOperator::InplaceMul; +} break; + +case 230: { + sym(1).ival = QSOperator::InplaceDiv; +} break; + +case 231: { + sym(1).ival = QSOperator::InplaceMod; +} break; + +case 232: { + sym(1).ival = QSOperator::InplaceAdd; +} break; + +case 233: { + sym(1).ival = QSOperator::InplaceSub; +} break; + +case 234: { + sym(1).ival = QSOperator::InplaceLeftShift; +} break; + +case 235: { + sym(1).ival = QSOperator::InplaceRightShift; +} break; + +case 236: { + sym(1).ival = QSOperator::InplaceURightShift; +} break; + +case 237: { + sym(1).ival = QSOperator::InplaceAnd; +} break; + +case 238: { + sym(1).ival = QSOperator::InplaceXor; +} break; + +case 239: { + sym(1).ival = QSOperator::InplaceOr; +} break; + +case 241: { + AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 242: { + sym(1).Node = 0; +} break; + +case 245: { + AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 246: { + sym(1).Node = 0; +} break; + +case 263: { + AST::Block *node = makeAstNode<AST::Block> (driver->nodePool(), sym(2).StatementList); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 264: { + sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement); +} break; + +case 265: { + sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement); +} break; + +case 266: { + sym(1).Node = 0; +} break; + +case 267: { + sym(1).Node = sym(1).StatementList->finish (); +} break; + +case 269: { + AST::VariableStatement *node = makeAstNode<AST::VariableStatement> (driver->nodePool(), + sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); + node->declarationKindToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 270: { + sym(1).ival = T_CONST; +} break; + +case 271: { + sym(1).ival = T_VAR; +} break; + +case 272: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); +} break; + +case 273: { + AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), + sym(1).VariableDeclarationList, sym(3).VariableDeclaration); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 274: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); +} break; + +case 275: { + sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); +} break; + +case 276: { + AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 277: { + AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 278: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; + +case 279: { + sym(1).Node = 0; +} break; + +case 281: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; + +case 282: { + sym(1).Node = 0; +} break; + +case 284: { + AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool()); + node->semicolonToken = loc(1); + sym(1).Node = node; +} break; + +case 286: { + AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 287: { + AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement); + node->ifToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + node->elseToken = loc(5); + sym(1).Node = node; +} break; + +case 288: { + AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->ifToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 290: { + AST::DoWhileStatement *node = makeAstNode<AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression); + node->doToken = loc(1); + node->whileToken = loc(3); + node->lparenToken = loc(4); + node->rparenToken = loc(6); + node->semicolonToken = loc(7); + sym(1).Node = node; +} break; + +case 291: { + AST::WhileStatement *node = makeAstNode<AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->whileToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 292: { + AST::ForStatement *node = makeAstNode<AST::ForStatement> (driver->nodePool(), sym(3).Expression, + sym(5).Expression, sym(7).Expression, sym(9).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->firstSemicolonToken = loc(4); + node->secondSemicolonToken = loc(6); + node->rparenToken = loc(8); + sym(1).Node = node; +} break; + +case 293: { + AST::LocalForStatement *node = makeAstNode<AST::LocalForStatement> (driver->nodePool(), + sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, + sym(8).Expression, sym(10).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->varToken = loc(3); + node->firstSemicolonToken = loc(5); + node->secondSemicolonToken = loc(7); + node->rparenToken = loc(9); + sym(1).Node = node; +} break; + +case 294: { + AST:: ForEachStatement *node = makeAstNode<AST::ForEachStatement> (driver->nodePool(), sym(3).Expression, + sym(5).Expression, sym(7).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->inToken = loc(4); + node->rparenToken = loc(6); + sym(1).Node = node; +} break; + +case 295: { + AST::LocalForEachStatement *node = makeAstNode<AST::LocalForEachStatement> (driver->nodePool(), + sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); + node->forToken = loc(1); + node->lparenToken = loc(2); + node->varToken = loc(3); + node->inToken = loc(5); + node->rparenToken = loc(7); + sym(1).Node = node; +} break; + +case 297: { + AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool()); + node->continueToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 299: { + AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool(), sym(2).sval); + node->continueToken = loc(1); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 301: { + AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool()); + node->breakToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 303: { + AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool(), sym(2).sval); + node->breakToken = loc(1); + node->identifierToken = loc(2); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 305: { + AST::ReturnStatement *node = makeAstNode<AST::ReturnStatement> (driver->nodePool(), sym(2).Expression); + node->returnToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 306: { + AST::WithStatement *node = makeAstNode<AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); + node->withToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 307: { + AST::SwitchStatement *node = makeAstNode<AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock); + node->switchToken = loc(1); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 308: { + AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses); + node->lbraceToken = loc(1); + node->rbraceToken = loc(3); + sym(1).Node = node; +} break; + +case 309: { + AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); + node->lbraceToken = loc(1); + node->rbraceToken = loc(5); + sym(1).Node = node; +} break; + +case 310: { + sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause); +} break; + +case 311: { + sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause); +} break; + +case 312: { + sym(1).Node = 0; +} break; + +case 313: { + sym(1).Node = sym(1).CaseClauses->finish (); +} break; + +case 314: { + AST::CaseClause *node = makeAstNode<AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList); + node->caseToken = loc(1); + node->colonToken = loc(3); + sym(1).Node = node; +} break; + +case 315: { + AST::DefaultClause *node = makeAstNode<AST::DefaultClause> (driver->nodePool(), sym(3).StatementList); + node->defaultToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; +case 316: +case 317: { + AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement); + node->identifierToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 318: { + AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement); + node->identifierToken = loc(1); + node->colonToken = loc(2); + sym(1).Node = node; +} break; + +case 320: { + AST::ThrowStatement *node = makeAstNode<AST::ThrowStatement> (driver->nodePool(), sym(2).Expression); + node->throwToken = loc(1); + node->semicolonToken = loc(3); + sym(1).Node = node; +} break; + +case 321: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch); + node->tryToken = loc(1); + sym(1).Node = node; +} break; + +case 322: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally); + node->tryToken = loc(1); + sym(1).Node = node; +} break; + +case 323: { + AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally); + node->tryToken = loc(1); + sym(1).Node = node; +} break; + +case 324: { + AST::Catch *node = makeAstNode<AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Block); + node->catchToken = loc(1); + node->lparenToken = loc(2); + node->identifierToken = loc(3); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 325: { + AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block); + node->finallyToken = loc(1); + sym(1).Node = node; +} break; + +case 327: { + AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool()); + node->debuggerToken = loc(1); + node->semicolonToken = loc(2); + sym(1).Node = node; +} break; + +case 328: { + AST::FunctionDeclaration *node = makeAstNode<AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + node->functionToken = loc(1); + node->identifierToken = loc(2); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + node->lbraceToken = loc(6); + node->rbraceToken = loc(8); + sym(1).Node = node; +} break; + +case 329: { + AST::FunctionExpression *node = makeAstNode<AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); + node->functionToken = loc(1); + if (sym(2).sval) + node->identifierToken = loc(2); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + node->lbraceToken = loc(6); + node->rbraceToken = loc(8); + sym(1).Node = node; +} break; + +case 330: { + AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval); + node->identifierToken = loc(1); + sym(1).Node = node; +} break; + +case 331: { + AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval); + node->commaToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; +} break; + +case 332: { + sym(1).Node = 0; +} break; + +case 333: { + sym(1).Node = sym(1).FormalParameterList->finish (); +} break; + +case 334: { + sym(1).Node = 0; +} break; + +case 336: { + sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ()); +} break; + +case 337: { + sym(1).Node = makeAstNode<AST::Program> (driver->nodePool(), sym(1).SourceElements->finish ()); +} break; + +case 338: { + sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement); +} break; + +case 339: { + sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement); +} break; + +case 340: { + sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement); +} break; + +case 341: { + sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration); +} break; + +case 342: { + sym(1).sval = 0; +} break; + +case 344: { + sym(1).Node = 0; +} break; + + } // switch + action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT); + } // if + } while (action != 0); + + if (first_token == last_token) { + const int errorState = state_stack[tos]; + + // automatic insertion of `;' + if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && automatic(driver, yytoken)) { + SavedToken &tk = token_buffer[0]; + tk.token = yytoken; + tk.dval = yylval; + tk.loc = yylloc; + + yylloc = yyprevlloc; + yylloc.offset += yylloc.length; + yylloc.startColumn += yylloc.length; + yylloc.length = 0; + + //const QString msg = qApp->translate("QDeclarativeParser", "Missing `;'"); + //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg)); + + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; + + yytoken = T_SEMICOLON; + yylval = 0; + + action = errorState; + + goto _Lcheck_token; + } + + hadErrors = true; + + token_buffer[0].token = yytoken; + token_buffer[0].dval = yylval; + token_buffer[0].loc = yylloc; + + token_buffer[1].token = yytoken = lexer->lex(); + token_buffer[1].dval = yylval = lexer->dval(); + token_buffer[1].loc = yylloc = location(lexer); + + if (t_action(errorState, yytoken)) { + QString msg; + int token = token_buffer[0].token; + if (token < 0 || token >= TERMINAL_COUNT) + msg = qApp->translate("QDeclarativeParser", "Syntax error"); + else + msg = qApp->translate("QDeclarativeParser", "Unexpected token `%1'").arg(QLatin1String(spell[token])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + action = errorState; + goto _Lcheck_token; + } + + static int tokens[] = { + T_PLUS, + T_EQ, + + T_COMMA, + T_COLON, + T_SEMICOLON, + + T_RPAREN, T_RBRACKET, T_RBRACE, + + T_NUMERIC_LITERAL, + T_IDENTIFIER, + + T_LPAREN, T_LBRACKET, T_LBRACE, + + EOF_SYMBOL + }; + + for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) { + int a = t_action(errorState, *tk); + if (a > 0 && t_action(a, yytoken)) { + const QString msg = qApp->translate("QDeclarativeParser", "Expected token `%1'").arg(QLatin1String(spell[*tk])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + yytoken = *tk; + yylval = 0; + yylloc = token_buffer[0].loc; + yylloc.length = 0; + + first_token = &token_buffer[0]; + last_token = &token_buffer[2]; + + action = errorState; + goto _Lcheck_token; + } + } + + for (int tk = 1; tk < TERMINAL_COUNT; ++tk) { + if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM || + tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION || + tk == T_FEED_JS_SOURCE_ELEMENT) + continue; + + int a = t_action(errorState, tk); + if (a > 0 && t_action(a, yytoken)) { + const QString msg = qApp->translate("QDeclarativeParser", "Expected token `%1'").arg(QLatin1String(spell[tk])); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + + yytoken = tk; + yylval = 0; + yylloc = token_buffer[0].loc; + yylloc.length = 0; + + action = errorState; + goto _Lcheck_token; + } + } + + const QString msg = qApp->translate("QDeclarativeParser", "Syntax error"); + diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + } + + return false; +} + +QT_QML_END_NAMESPACE + + diff --git a/src/declarative/qml/parser/qdeclarativejsparser_p.h b/src/declarative/qml/parser/qdeclarativejsparser_p.h new file mode 100644 index 00000000..c390bcd5 --- /dev/null +++ b/src/declarative/qml/parser/qdeclarativejsparser_p.h @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// +// This file is automatically generated from qmljs.g. +// Changes will be lost. +// + +#ifndef QDECLARATIVEJSPARSER_P_H +#define QDECLARATIVEJSPARSER_P_H + +#include "private/qdeclarativejsglobal_p.h" +#include "private/qdeclarativejsgrammar_p.h" +#include "private/qdeclarativejsast_p.h" +#include "private/qdeclarativejsengine_p.h" + +#include <QtCore/QList> +#include <QtCore/QString> + +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { + +class Engine; +class NameId; + +class QML_PARSER_EXPORT Parser: protected QDeclarativeJSGrammar +{ +public: + union Value { + int ival; + double dval; + NameId *sval; + AST::ArgumentList *ArgumentList; + AST::CaseBlock *CaseBlock; + AST::CaseClause *CaseClause; + AST::CaseClauses *CaseClauses; + AST::Catch *Catch; + AST::DefaultClause *DefaultClause; + AST::ElementList *ElementList; + AST::Elision *Elision; + AST::ExpressionNode *Expression; + AST::Finally *Finally; + AST::FormalParameterList *FormalParameterList; + AST::FunctionBody *FunctionBody; + AST::FunctionDeclaration *FunctionDeclaration; + AST::Node *Node; + AST::PropertyName *PropertyName; + AST::PropertyNameAndValueList *PropertyNameAndValueList; + AST::SourceElement *SourceElement; + AST::SourceElements *SourceElements; + AST::Statement *Statement; + AST::StatementList *StatementList; + AST::Block *Block; + AST::VariableDeclaration *VariableDeclaration; + AST::VariableDeclarationList *VariableDeclarationList; + + AST::UiProgram *UiProgram; + AST::UiImportList *UiImportList; + AST::UiImport *UiImport; + AST::UiParameterList *UiParameterList; + AST::UiPublicMember *UiPublicMember; + AST::UiObjectDefinition *UiObjectDefinition; + AST::UiObjectInitializer *UiObjectInitializer; + AST::UiObjectBinding *UiObjectBinding; + AST::UiScriptBinding *UiScriptBinding; + AST::UiArrayBinding *UiArrayBinding; + AST::UiObjectMember *UiObjectMember; + AST::UiObjectMemberList *UiObjectMemberList; + AST::UiArrayMemberList *UiArrayMemberList; + AST::UiQualifiedId *UiQualifiedId; + AST::UiSignature *UiSignature; + AST::UiFormalList *UiFormalList; + AST::UiFormal *UiFormal; + }; + +public: + Parser(Engine *engine); + ~Parser(); + + // parse a UI program + bool parse() { return parse(T_FEED_UI_PROGRAM); } + bool parseStatement() { return parse(T_FEED_JS_STATEMENT); } + bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); } + bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); } + bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); } + bool parseProgram() { return parse(T_FEED_JS_PROGRAM); } + + AST::UiProgram *ast() const + { return AST::cast<AST::UiProgram *>(program); } + + AST::Statement *statement() const + { + if (! program) + return 0; + + return program->statementCast(); + } + + AST::ExpressionNode *expression() const + { + if (! program) + return 0; + + return program->expressionCast(); + } + + AST::UiObjectMember *uiObjectMember() const + { + if (! program) + return 0; + + return program->uiObjectMemberCast(); + } + + AST::Node *rootNode() const + { return program; } + + QList<DiagnosticMessage> diagnosticMessages() const + { return diagnostic_messages; } + + inline DiagnosticMessage diagnosticMessage() const + { + foreach (const DiagnosticMessage &d, diagnostic_messages) { + if (! d.kind == DiagnosticMessage::Warning) + return d; + } + + return DiagnosticMessage(); + } + + inline QString errorMessage() const + { return diagnosticMessage().message; } + + inline int errorLineNumber() const + { return diagnosticMessage().loc.startLine; } + + inline int errorColumnNumber() const + { return diagnosticMessage().loc.startColumn; } + +protected: + bool parse(int startToken); + + void reallocateStack(); + + inline Value &sym(int index) + { return sym_stack [tos + index - 1]; } + + inline AST::SourceLocation &loc(int index) + { return location_stack [tos + index - 1]; } + + AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr); + +protected: + Engine *driver; + int tos; + int stack_size; + Value *sym_stack; + int *state_stack; + AST::SourceLocation *location_stack; + + AST::Node *program; + + // error recovery + enum { TOKEN_BUFFER_SIZE = 3 }; + + struct SavedToken { + int token; + double dval; + AST::SourceLocation loc; + }; + + double yylval; + AST::SourceLocation yylloc; + AST::SourceLocation yyprevlloc; + + SavedToken token_buffer[TOKEN_BUFFER_SIZE]; + SavedToken *first_token; + SavedToken *last_token; + + QList<DiagnosticMessage> diagnostic_messages; +}; + +} // end of namespace QDeclarativeJS + + + +#define J_SCRIPT_REGEXPLITERAL_RULE1 78 + +#define J_SCRIPT_REGEXPLITERAL_RULE2 79 + +QT_QML_END_NAMESPACE + + + +#endif // QDECLARATIVEJSPARSER_P_H diff --git a/src/declarative/qml/qbitfield_p.h b/src/declarative/qml/qbitfield_p.h new file mode 100644 index 00000000..fb5efe0e --- /dev/null +++ b/src/declarative/qml/qbitfield_p.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBITFIELD_P_H +#define QBITFIELD_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QBitField +{ +public: + inline QBitField(); + inline QBitField(const quint32 *, int bits); + inline QBitField(const QBitField &); + inline ~QBitField(); + + inline QBitField &operator=(const QBitField &); + + inline quint32 size() const; + inline QBitField united(const QBitField &); + inline bool testBit(int) const; + +private: + quint32 bits:31; + quint32 *ownData; + const quint32 *data; +}; + +QBitField::QBitField() +: bits(0), ownData(0), data(0) +{ +} + +QBitField::QBitField(const quint32 *bitData, int bitCount) +: bits((quint32)bitCount), ownData(0), data(bitData) +{ +} + +QBitField::QBitField(const QBitField &other) +: bits(other.bits), ownData(other.ownData), data(other.data) +{ + if (ownData) + ++(*ownData); +} + +QBitField::~QBitField() +{ + if (ownData) + if(0 == --(*ownData)) delete [] ownData; +} + +QBitField &QBitField::operator=(const QBitField &other) +{ + if (other.data == data) + return *this; + + if (ownData) + if(0 == --(*ownData)) delete [] ownData; + + bits = other.bits; + ownData = other.ownData; + data = other.data; + + if (ownData) + ++(*ownData); + + return *this; +} + +inline quint32 QBitField::size() const +{ + return bits; +} + +QBitField QBitField::united(const QBitField &o) +{ + if (o.bits == 0) { + return *this; + } else if (bits == 0) { + return o; + } else { + int max = (bits > o.bits)?bits:o.bits; + int length = (max + 31) / 32; + QBitField rv; + rv.bits = max; + rv.ownData = new quint32[length + 1]; + *(rv.ownData) = 1; + rv.data = rv.ownData + 1; + if (bits > o.bits) { + ::memcpy((quint32 *)rv.data, data, length * sizeof(quint32)); + for (quint32 ii = 0; ii < (o.bits + quint32(31)) / 32; ++ii) + ((quint32 *)rv.data)[ii] |= o.data[ii]; + } else { + ::memcpy((quint32 *)rv.data, o.data, length * sizeof(quint32)); + for (quint32 ii = 0; ii < (bits + quint32(31)) / 32; ++ii) + ((quint32 *)rv.data)[ii] |= data[ii]; + } + return rv; + } +} + +bool QBitField::testBit(int b) const +{ + Q_ASSERT(b >= 0); + if ((quint32)b < bits) { + return data[b / 32] & (1 << (b % 32)); + } else { + return false; + } +} + +QT_END_NAMESPACE + +#endif // QBITFIELD_P_H diff --git a/src/declarative/qml/qdeclarative.h b/src/declarative/qml/qdeclarative.h new file mode 100644 index 00000000..f0893b2e --- /dev/null +++ b/src/declarative/qml/qdeclarative.h @@ -0,0 +1,415 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVE_H +#define QDECLARATIVE_H + +#include <QtDeclarative/qdeclarativeprivate.h> +#include <QtDeclarative/qdeclarativeparserstatus.h> +#include <QtDeclarative/qdeclarativepropertyvaluesource.h> +#include <QtDeclarative/qdeclarativepropertyvalueinterceptor.h> +#include <QtDeclarative/qdeclarativelist.h> + +#include <QtCore/qbytearray.h> +#include <QtCore/qmetaobject.h> + +QT_BEGIN_HEADER + +#define QML_DECLARE_TYPE(TYPE) \ + Q_DECLARE_METATYPE(TYPE *) \ + Q_DECLARE_METATYPE(QDeclarativeListProperty<TYPE>) + +#define QML_DECLARE_TYPE_HASMETATYPE(TYPE) \ + Q_DECLARE_METATYPE(QDeclarativeListProperty<TYPE>) + +#define QML_DECLARE_INTERFACE(INTERFACE) \ + QML_DECLARE_TYPE(INTERFACE) + +#define QML_DECLARE_INTERFACE_HASMETATYPE(INTERFACE) \ + QML_DECLARE_TYPE_HASMETATYPE(INTERFACE) + +enum { /* TYPEINFO flags */ + QML_HAS_ATTACHED_PROPERTIES = 0x01 +}; + +#define QML_DECLARE_TYPEINFO(TYPE, FLAGS) \ +QT_BEGIN_NAMESPACE \ +template <> \ +class QDeclarativeTypeInfo<TYPE > \ +{ \ +public: \ + enum { \ + hasAttachedProperties = (((FLAGS) & QML_HAS_ATTACHED_PROPERTIES) == QML_HAS_ATTACHED_PROPERTIES) \ + }; \ +}; \ +QT_END_NAMESPACE + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +template<typename T> +int qmlRegisterType() +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QDeclarativeListProperty<" + name + ">"); + + QDeclarativePrivate::RegisterType type = { + 0, + + qRegisterMetaType<T *>(pointerName.constData()), + qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), + 0, 0, + QString(), + + 0, 0, 0, 0, &T::staticMetaObject, + + QDeclarativePrivate::attachedPropertiesFunc<T>(), + QDeclarativePrivate::attachedPropertiesMetaObject<T>(), + + QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(), + + 0, 0, + + 0, + 0 + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); +} + +int Q_AUTOTEST_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message); + +template<typename T> +int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QDeclarativeListProperty<" + name + ">"); + + QDeclarativePrivate::RegisterType type = { + 0, + + qRegisterMetaType<T *>(pointerName.constData()), + qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), + 0, 0, + reason, + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + QDeclarativePrivate::attachedPropertiesFunc<T>(), + QDeclarativePrivate::attachedPropertiesMetaObject<T>(), + + QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(), + + 0, 0, + + 0, + 0 + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); +} + +template<typename T> +int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QDeclarativeListProperty<" + name + ">"); + + QDeclarativePrivate::RegisterType type = { + 0, + + qRegisterMetaType<T *>(pointerName.constData()), + qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), + sizeof(T), QDeclarativePrivate::createInto<T>, + QString(), + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + QDeclarativePrivate::attachedPropertiesFunc<T>(), + QDeclarativePrivate::attachedPropertiesMetaObject<T>(), + + QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(), + + 0, 0, + + 0, + 0 + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); +} + +template<typename T, int metaObjectRevision> +int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QDeclarativeListProperty<" + name + ">"); + + QDeclarativePrivate::RegisterType type = { + 1, + + qRegisterMetaType<T *>(pointerName.constData()), + qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), + sizeof(T), QDeclarativePrivate::createInto<T>, + QString(), + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + QDeclarativePrivate::attachedPropertiesFunc<T>(), + QDeclarativePrivate::attachedPropertiesMetaObject<T>(), + + QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(), + + 0, 0, + + 0, + metaObjectRevision + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); +} + +template<typename T, int metaObjectRevision> +int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QDeclarativeListProperty<" + name + ">"); + + QDeclarativePrivate::RegisterType type = { + 1, + + qRegisterMetaType<T *>(pointerName.constData()), + qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), + sizeof(T), QDeclarativePrivate::createInto<T>, + QString(), + + uri, versionMajor, versionMinor, 0, &T::staticMetaObject, + + QDeclarativePrivate::attachedPropertiesFunc<T>(), + QDeclarativePrivate::attachedPropertiesMetaObject<T>(), + + QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(), + + 0, 0, + + 0, + metaObjectRevision + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); +} + + +template<typename T, typename E> +int qmlRegisterExtendedType() +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QDeclarativeListProperty<" + name + ">"); + + QDeclarativePrivate::RegisterType type = { + 0, + + qRegisterMetaType<T *>(pointerName.constData()), + qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), + 0, 0, + QString(), + + 0, 0, 0, 0, &T::staticMetaObject, + + QDeclarativePrivate::attachedPropertiesFunc<T>(), + QDeclarativePrivate::attachedPropertiesMetaObject<T>(), + + QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(), + + QDeclarativePrivate::createParent<E>, &E::staticMetaObject, + + 0, + 0 + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); +} + +template<typename T, typename E> +int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, + const char *qmlName) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QDeclarativeListProperty<" + name + ">"); + + QDeclarativeAttachedPropertiesFunc attached = QDeclarativePrivate::attachedPropertiesFunc<E>(); + const QMetaObject * attachedMetaObject = QDeclarativePrivate::attachedPropertiesMetaObject<E>(); + if (!attached) { + attached = QDeclarativePrivate::attachedPropertiesFunc<T>(); + attachedMetaObject = QDeclarativePrivate::attachedPropertiesMetaObject<T>(); + } + + QDeclarativePrivate::RegisterType type = { + 0, + + qRegisterMetaType<T *>(pointerName.constData()), + qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), + sizeof(T), QDeclarativePrivate::createInto<T>, + QString(), + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + attached, + attachedMetaObject, + + QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(), + + QDeclarativePrivate::createParent<E>, &E::staticMetaObject, + + 0, + 0 + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); +} + +template<typename T> +int qmlRegisterInterface(const char *typeName) +{ + QByteArray name(typeName); + + QByteArray pointerName(name + '*'); + QByteArray listName("QDeclarativeListProperty<" + name + ">"); + + QDeclarativePrivate::RegisterInterface qmlInterface = { + 0, + + qRegisterMetaType<T *>(pointerName.constData()), + qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), + + qobject_interface_iid<T *>() + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::InterfaceRegistration, &qmlInterface); +} + +template<typename T> +int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, + const char *qmlName, QDeclarativeCustomParser *parser) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QDeclarativeListProperty<" + name + ">"); + + QDeclarativePrivate::RegisterType type = { + 0, + + qRegisterMetaType<T *>(pointerName.constData()), + qRegisterMetaType<QDeclarativeListProperty<T> >(listName.constData()), + sizeof(T), QDeclarativePrivate::createInto<T>, + QString(), + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + QDeclarativePrivate::attachedPropertiesFunc<T>(), + QDeclarativePrivate::attachedPropertiesMetaObject<T>(), + + QDeclarativePrivate::StaticCastSelector<T,QDeclarativeParserStatus>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueSource>::cast(), + QDeclarativePrivate::StaticCastSelector<T,QDeclarativePropertyValueInterceptor>::cast(), + + 0, 0, + + parser, + 0 + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); +} + +class QDeclarativeContext; +class QDeclarativeEngine; +Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *); +Q_DECLARATIVE_EXPORT QDeclarativeContext *qmlContext(const QObject *); +Q_DECLARATIVE_EXPORT QDeclarativeEngine *qmlEngine(const QObject *); +Q_DECLARATIVE_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true); +Q_DECLARATIVE_EXPORT QObject *qmlAttachedPropertiesObject(int *, const QObject *, const QMetaObject *, bool create); + +template<typename T> +QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) +{ + static int idx = -1; + return qmlAttachedPropertiesObject(&idx, obj, &T::staticMetaObject, create); +} + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QObject) +Q_DECLARE_METATYPE(QVariant) + +QT_END_HEADER + +#endif // QDECLARATIVE_H diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp new file mode 100644 index 00000000..31bc436e --- /dev/null +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -0,0 +1,573 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativebinding_p.h" +#include "private/qdeclarativebinding_p_p.h" + +#include "qdeclarative.h" +#include "qdeclarativecontext.h" +#include "qdeclarativeinfo.h" +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativecompiler_p.h" +#include "private/qdeclarativedata_p.h" +#include "private/qdeclarativestringconverters_p.h" +#include "private/qdeclarativestate_p_p.h" +#include "private/qdeclarativedebugtrace_p.h" + +#include <QVariant> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +QDeclarativeAbstractBinding::QDeclarativeAbstractBinding() +: m_object(0), m_propertyIndex(-1), m_mePtr(0), m_prevBinding(0), m_nextBinding(0) +{ +} + +QDeclarativeAbstractBinding::~QDeclarativeAbstractBinding() +{ + Q_ASSERT(m_prevBinding == 0); + Q_ASSERT(m_mePtr == 0); +} + +/*! +Destroy the binding. Use this instead of calling delete. + +Bindings are free to implement their own memory management, so the delete operator is not +necessarily safe. The default implementation clears the binding, removes it from the object +and calls delete. +*/ +void QDeclarativeAbstractBinding::destroy() +{ + removeFromObject(); + clear(); + + delete this; +} + +/*! +Add this binding to \a object. + +This transfers ownership of the binding to the object, marks the object's property as +being bound. + +However, it does not enable the binding itself or call update() on it. +*/ +void QDeclarativeAbstractBinding::addToObject(QObject *object, int index) +{ + Q_ASSERT(object); + + if (m_object == object && m_propertyIndex == index) + return; + + removeFromObject(); + + Q_ASSERT(!m_prevBinding); + + m_object = object; + m_propertyIndex = index; + + QDeclarativeData *data = QDeclarativeData::get(object, true); + + if (index & 0xFF000000) { + // Value type + + int coreIndex = index & 0xFFFFFF; + + // Find the value type proxy (if there is one) + QDeclarativeValueTypeProxyBinding *proxy = 0; + if (data->hasBindingBit(coreIndex)) { + QDeclarativeAbstractBinding *b = data->bindings; + while (b && b->propertyIndex() != coreIndex) + b = b->m_nextBinding; + Q_ASSERT(b && b->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy); + proxy = static_cast<QDeclarativeValueTypeProxyBinding *>(b); + } + + if (!proxy) { + proxy = new QDeclarativeValueTypeProxyBinding(object, coreIndex); + proxy->addToObject(object, coreIndex); + } + + m_nextBinding = proxy->m_bindings; + if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding; + m_prevBinding = &proxy->m_bindings; + proxy->m_bindings = this; + + } else { + m_nextBinding = data->bindings; + if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding; + m_prevBinding = &data->bindings; + data->bindings = this; + + data->setBindingBit(m_object, index); + } +} + +/*! +Remove the binding from the object. +*/ +void QDeclarativeAbstractBinding::removeFromObject() +{ + if (m_prevBinding) { + int index = propertyIndex(); + + *m_prevBinding = m_nextBinding; + if (m_nextBinding) m_nextBinding->m_prevBinding = m_prevBinding; + m_prevBinding = 0; + m_nextBinding = 0; + + if (index & 0xFF000000) { + // Value type - we don't remove the proxy from the object. It will sit their happily + // doing nothing until it is removed by a write, a binding change or it is reused + // to hold more sub-bindings. + } else if (m_object) { + QDeclarativeData *data = QDeclarativeData::get(m_object, false); + if (data) data->clearBindingBit(index); + } + + m_object = 0; + m_propertyIndex = -1; + } +} + +static void bindingDummyDeleter(QDeclarativeAbstractBinding *) +{ +} + +QDeclarativeAbstractBinding::Pointer QDeclarativeAbstractBinding::weakPointer() +{ + if (m_selfPointer.isNull()) + m_selfPointer = QSharedPointer<QDeclarativeAbstractBinding>(this, bindingDummyDeleter); + + return m_selfPointer.toWeakRef(); +} + +void QDeclarativeAbstractBinding::clear() +{ + if (m_mePtr) { + *m_mePtr = 0; + m_mePtr = 0; + } +} + +QString QDeclarativeAbstractBinding::expression() const +{ + return QLatin1String("<Unknown>"); +} + +QObject *QDeclarativeAbstractBinding::object() const +{ + return m_object; +} + +int QDeclarativeAbstractBinding::propertyIndex() const +{ + return m_propertyIndex; +} + +void QDeclarativeAbstractBinding::setEnabled(bool enabled, QDeclarativePropertyPrivate::WriteFlags flags) +{ + if (enabled) update(flags); +} + +QDeclarativeBinding::Identifier QDeclarativeBinding::Invalid = -1; + +void QDeclarativeBindingPrivate::refresh() +{ + Q_Q(QDeclarativeBinding); + q->update(); +} + +QDeclarativeBindingPrivate::QDeclarativeBindingPrivate() +: updating(false), enabled(false), deleted(0) +{ +} + +QDeclarativeBindingPrivate::~QDeclarativeBindingPrivate() +{ + if (deleted) *deleted = true; +} + +QDeclarativeBinding::QDeclarativeBinding(void *data, QDeclarativeRefCount *rc, QObject *obj, + QDeclarativeContextData *ctxt, const QString &url, int lineNumber, + QObject *parent) +: QDeclarativeExpression(ctxt, data, rc, obj, url, lineNumber, *new QDeclarativeBindingPrivate) +{ + setParent(parent); + setNotifyOnValueChanged(true); +} + +QDeclarativeBinding * +QDeclarativeBinding::createBinding(Identifier id, QObject *obj, QDeclarativeContext *ctxt, + const QString &url, int lineNumber, QObject *parent) +{ + if (id < 0) + return 0; + + Q_ASSERT(ctxt); + QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(ctxt); + + QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(ctxtdata->engine); + QDeclarativeCompiledData *cdata = 0; + QDeclarativeTypeData *typeData = 0; + if (!ctxtdata->url.isEmpty()) { + typeData = engine->typeLoader.get(ctxtdata->url); + cdata = typeData->compiledData(); + } + QDeclarativeBinding *rv = cdata ? new QDeclarativeBinding((void*)cdata->datas.at(id).constData(), cdata, obj, ctxtdata, url, lineNumber, parent) : 0; + if (cdata) + cdata->release(); + if (typeData) + typeData->release(); + return rv; +} + +QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDeclarativeContext *ctxt, + QObject *parent) +: QDeclarativeExpression(QDeclarativeContextData::get(ctxt), obj, str, *new QDeclarativeBindingPrivate) +{ + setParent(parent); + setNotifyOnValueChanged(true); +} + +QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDeclarativeContextData *ctxt, + QObject *parent) +: QDeclarativeExpression(ctxt, obj, str, *new QDeclarativeBindingPrivate) +{ + setParent(parent); + setNotifyOnValueChanged(true); +} + +QDeclarativeBinding::QDeclarativeBinding(const QScriptValue &func, QObject *obj, QDeclarativeContextData *ctxt, QObject *parent) +: QDeclarativeExpression(ctxt, obj, func, *new QDeclarativeBindingPrivate) +{ + setParent(parent); + setNotifyOnValueChanged(true); +} + +QDeclarativeBinding::~QDeclarativeBinding() +{ +} + +void QDeclarativeBinding::setTarget(const QDeclarativeProperty &prop) +{ + Q_D(QDeclarativeBinding); + d->property = prop; + + update(); +} + +QDeclarativeProperty QDeclarativeBinding::property() const +{ + Q_D(const QDeclarativeBinding); + return d->property; +} + +void QDeclarativeBinding::setEvaluateFlags(EvaluateFlags flags) +{ + Q_D(QDeclarativeBinding); + d->setEvaluateFlags(QDeclarativeQtScriptExpression::EvaluateFlags(static_cast<int>(flags))); +} + +QDeclarativeBinding::EvaluateFlags QDeclarativeBinding::evaluateFlags() const +{ + Q_D(const QDeclarativeBinding); + return QDeclarativeBinding::EvaluateFlags(static_cast<int>(d->evaluateFlags())); +} + + +class QDeclarativeBindingProfiler { +public: + QDeclarativeBindingProfiler(QDeclarativeBinding *bind) + { + QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding); + QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Binding, bind->expression()); + QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Binding, bind->sourceFile(), bind->lineNumber()); + } + + ~QDeclarativeBindingProfiler() + { + QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding); + } +}; + +void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) +{ + Q_D(QDeclarativeBinding); + + if (!d->enabled || !d->context() || !d->context()->isValid()) + return; + + if (!d->updating) { + QDeclarativeBindingProfiler prof(this); + d->updating = true; + bool wasDeleted = false; + d->deleted = &wasDeleted; + + if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) { + + int idx = d->property.index(); + Q_ASSERT(idx != -1); + + QDeclarativeBinding *t = this; + int status = -1; + void *a[] = { &t, 0, &status, &flags }; + QMetaObject::metacall(d->property.object(), + QMetaObject::WriteProperty, + idx, a); + + if (wasDeleted) + return; + + } else { + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine); + + bool isUndefined = false; + QVariant value; + + QScriptValue scriptValue = d->scriptValue(0, &isUndefined); + if (wasDeleted) + return; + + if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) { + value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >()); + } else if (scriptValue.isNull() && + d->property.propertyTypeCategory() == QDeclarativeProperty::Object) { + value = QVariant::fromValue((QObject *)0); + } else { + value = ep->scriptValueToVariant(scriptValue, d->property.propertyType()); + if (value.userType() == QMetaType::QObjectStar && !qvariant_cast<QObject*>(value)) { + // If the object is null, we extract the predicted type. While this isn't + // 100% reliable, in many cases it gives us better error messages if we + // assign this null-object to an incompatible property + int type = ep->objectClass->objectType(scriptValue); + QObject *o = 0; + value = QVariant(type, (void *)&o); + } + } + + + if (d->error.isValid()) { + + } else if (isUndefined && d->property.isResettable()) { + + d->property.reset(); + + } else if (isUndefined && d->property.propertyType() == qMetaTypeId<QVariant>()) { + + QDeclarativePropertyPrivate::write(d->property, QVariant(), flags); + + } else if (isUndefined) { + + QUrl url = QUrl(d->url); + int line = d->line; + if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>")); + + d->error.setUrl(url); + d->error.setLine(line); + d->error.setColumn(-1); + d->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + + QLatin1String(QMetaType::typeName(d->property.propertyType())) + + QLatin1String(" ") + d->property.name()); + + } else if (!scriptValue.isRegExp() && scriptValue.isFunction()) { + + QUrl url = QUrl(d->url); + int line = d->line; + if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>")); + + d->error.setUrl(url); + d->error.setLine(line); + d->error.setColumn(-1); + d->error.setDescription(QLatin1String("Unable to assign a function to a property.")); + + } else if (d->property.object() && + !QDeclarativePropertyPrivate::write(d->property, value, flags)) { + + if (wasDeleted) + return; + + QUrl url = QUrl(d->url); + int line = d->line; + if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>")); + + const char *valueType = 0; + if (value.userType() == QVariant::Invalid) valueType = "null"; + else valueType = QMetaType::typeName(value.userType()); + + d->error.setUrl(url); + d->error.setLine(line); + d->error.setColumn(-1); + d->error.setDescription(QLatin1String("Unable to assign ") + + QLatin1String(valueType) + + QLatin1String(" to ") + + QLatin1String(QMetaType::typeName(d->property.propertyType()))); + } + + if (wasDeleted) + return; + + if (d->error.isValid()) { + if (!d->addError(ep)) ep->warning(this->error()); + } else { + d->removeError(); + } + } + + d->updating = false; + d->deleted = 0; + } else { + qmlInfo(d->property.object()) << tr("Binding loop detected for property \"%1\"").arg(d->property.name()); + } +} + +void QDeclarativeBindingPrivate::emitValueChanged() +{ + Q_Q(QDeclarativeBinding); + q->update(); +} + +void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags) +{ + Q_D(QDeclarativeBinding); + d->enabled = e; + setNotifyOnValueChanged(e); + + if (e) + update(flags); +} + +bool QDeclarativeBinding::enabled() const +{ + Q_D(const QDeclarativeBinding); + + return d->enabled; +} + +QString QDeclarativeBinding::expression() const +{ + return QDeclarativeExpression::expression(); +} + +QDeclarativeValueTypeProxyBinding::QDeclarativeValueTypeProxyBinding(QObject *o, int index) +: m_object(o), m_index(index), m_bindings(0) +{ +} + +QDeclarativeValueTypeProxyBinding::~QDeclarativeValueTypeProxyBinding() +{ + while (m_bindings) { + QDeclarativeAbstractBinding *binding = m_bindings; + binding->setEnabled(false, 0); + binding->destroy(); + } +} + +void QDeclarativeValueTypeProxyBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags) +{ + if (e) { + QDeclarativeAbstractBinding *bindings = m_bindings; + recursiveEnable(bindings, flags); + } else { + QDeclarativeAbstractBinding *bindings = m_bindings; + recursiveDisable(bindings); + } +} + +void QDeclarativeValueTypeProxyBinding::recursiveEnable(QDeclarativeAbstractBinding *b, QDeclarativePropertyPrivate::WriteFlags flags) +{ + if (!b) + return; + + recursiveEnable(b->m_nextBinding, flags); + + if (b) + b->setEnabled(true, flags); +} + +void QDeclarativeValueTypeProxyBinding::recursiveDisable(QDeclarativeAbstractBinding *b) +{ + if (!b) + return; + + recursiveDisable(b->m_nextBinding); + + if (b) + b->setEnabled(false, 0); +} + +void QDeclarativeValueTypeProxyBinding::update(QDeclarativePropertyPrivate::WriteFlags) +{ +} + +QDeclarativeAbstractBinding *QDeclarativeValueTypeProxyBinding::binding(int propertyIndex) +{ + QDeclarativeAbstractBinding *binding = m_bindings; + + while (binding && binding->propertyIndex() != propertyIndex) + binding = binding->m_nextBinding; + + return binding; +} + +/*! +Removes a collection of bindings, corresponding to the set bits in \a mask. +*/ +void QDeclarativeValueTypeProxyBinding::removeBindings(quint32 mask) +{ + QDeclarativeAbstractBinding *binding = m_bindings; + while (binding) { + if (mask & (1 << (binding->propertyIndex() >> 24))) { + QDeclarativeAbstractBinding *remove = binding; + binding = remove->m_nextBinding; + *remove->m_prevBinding = remove->m_nextBinding; + if (remove->m_nextBinding) remove->m_nextBinding->m_prevBinding = remove->m_prevBinding; + remove->m_prevBinding = 0; + remove->m_nextBinding = 0; + remove->destroy(); + } else { + binding = binding->m_nextBinding; + } + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativebinding_p.h b/src/declarative/qml/qdeclarativebinding_p.h new file mode 100644 index 00000000..042b45d0 --- /dev/null +++ b/src/declarative/qml/qdeclarativebinding_p.h @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEBINDING_P_H +#define QDECLARATIVEBINDING_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarative.h" +#include "qdeclarativepropertyvaluesource.h" +#include "qdeclarativeexpression.h" +#include "qdeclarativeproperty.h" +#include "private/qdeclarativeproperty_p.h" + +#include <QtCore/QObject> +#include <QtCore/QMetaProperty> + +QT_BEGIN_NAMESPACE + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeAbstractBinding +{ +public: + typedef QWeakPointer<QDeclarativeAbstractBinding> Pointer; + + QDeclarativeAbstractBinding(); + + virtual void destroy(); + + virtual QString expression() const; + + enum Type { PropertyBinding, ValueTypeProxy }; + virtual Type bindingType() const { return PropertyBinding; } + + QObject *object() const; + int propertyIndex() const; + + void setEnabled(bool e) { setEnabled(e, QDeclarativePropertyPrivate::DontRemoveBinding); } + virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags) = 0; + + void update() { update(QDeclarativePropertyPrivate::DontRemoveBinding); } + virtual void update(QDeclarativePropertyPrivate::WriteFlags) = 0; + + void addToObject(QObject *, int); + void removeFromObject(); + + static Pointer getPointer(QDeclarativeAbstractBinding *p) { return p ? p->weakPointer() : Pointer(); } + +protected: + virtual ~QDeclarativeAbstractBinding(); + void clear(); + +private: + Pointer weakPointer(); + + friend class QDeclarativeData; + friend class QDeclarativeComponentPrivate; + friend class QDeclarativeValueTypeProxyBinding; + friend class QDeclarativePropertyPrivate; + friend class QDeclarativeVME; + friend class QtSharedPointer::ExternalRefCount<QDeclarativeAbstractBinding>; + + QObject *m_object; + int m_propertyIndex; + QDeclarativeAbstractBinding **m_mePtr; + QDeclarativeAbstractBinding **m_prevBinding; + QDeclarativeAbstractBinding *m_nextBinding; + QSharedPointer<QDeclarativeAbstractBinding> m_selfPointer; +}; + +class QDeclarativeValueTypeProxyBinding : public QDeclarativeAbstractBinding +{ +public: + QDeclarativeValueTypeProxyBinding(QObject *o, int coreIndex); + + virtual Type bindingType() const { return ValueTypeProxy; } + + virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags); + virtual void update(QDeclarativePropertyPrivate::WriteFlags); + + QDeclarativeAbstractBinding *binding(int propertyIndex); + + void removeBindings(quint32 mask); + +protected: + ~QDeclarativeValueTypeProxyBinding(); + +private: + void recursiveEnable(QDeclarativeAbstractBinding *, QDeclarativePropertyPrivate::WriteFlags); + void recursiveDisable(QDeclarativeAbstractBinding *); + + friend class QDeclarativeAbstractBinding; + QObject *m_object; + int m_index; + QDeclarativeAbstractBinding *m_bindings; +}; + +class QDeclarativeContext; +class QDeclarativeBindingPrivate; +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeBinding : public QDeclarativeExpression, public QDeclarativeAbstractBinding +{ +Q_OBJECT +public: + enum EvaluateFlag { RequiresThisObject = 0x01 }; + Q_DECLARE_FLAGS(EvaluateFlags, EvaluateFlag) + + QDeclarativeBinding(const QString &, QObject *, QDeclarativeContext *, QObject *parent=0); + QDeclarativeBinding(const QString &, QObject *, QDeclarativeContextData *, QObject *parent=0); + QDeclarativeBinding(void *, QDeclarativeRefCount *, QObject *, QDeclarativeContextData *, + const QString &, int, QObject *parent); + QDeclarativeBinding(const QScriptValue &, QObject *, QDeclarativeContextData *, QObject *parent=0); + + void setTarget(const QDeclarativeProperty &); + QDeclarativeProperty property() const; + + void setEvaluateFlags(EvaluateFlags flags); + EvaluateFlags evaluateFlags() const; + + bool enabled() const; + + // Inherited from QDeclarativeAbstractBinding + virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags); + virtual void update(QDeclarativePropertyPrivate::WriteFlags flags); + virtual QString expression() const; + + typedef int Identifier; + static Identifier Invalid; + static QDeclarativeBinding *createBinding(Identifier, QObject *, QDeclarativeContext *, const QString &, int, QObject *parent=0); + +public Q_SLOTS: + void update() { update(QDeclarativePropertyPrivate::DontRemoveBinding); } + +protected: + ~QDeclarativeBinding(); + void emitValueChanged(); + +private: + Q_DECLARE_PRIVATE(QDeclarativeBinding) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeBinding::EvaluateFlags) + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDeclarativeBinding*) + +#endif // QDECLARATIVEBINDING_P_H diff --git a/src/declarative/qml/qdeclarativebinding_p_p.h b/src/declarative/qml/qdeclarativebinding_p_p.h new file mode 100644 index 00000000..0c99d013 --- /dev/null +++ b/src/declarative/qml/qdeclarativebinding_p_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEBINDING_P_P_H +#define QDECLARATIVEBINDING_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativebinding_p.h" + +#include "qdeclarativeproperty.h" +#include "private/qdeclarativeexpression_p.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativeBindingPrivate : public QDeclarativeExpressionPrivate +{ + Q_DECLARE_PUBLIC(QDeclarativeBinding) +public: + QDeclarativeBindingPrivate(); + ~QDeclarativeBindingPrivate(); + + virtual void emitValueChanged(); + +protected: + virtual void refresh(); + +private: + bool updating:1; + bool enabled:1; + QDeclarativeProperty property; + + bool *deleted; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEBINDING_P_P_H diff --git a/src/declarative/qml/qdeclarativeboundsignal.cpp b/src/declarative/qml/qdeclarativeboundsignal.cpp new file mode 100644 index 00000000..a8aece9f --- /dev/null +++ b/src/declarative/qml/qdeclarativeboundsignal.cpp @@ -0,0 +1,306 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativeboundsignal_p.h" + +#include "private/qmetaobjectbuilder_p.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativeexpression_p.h" +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativemetatype_p.h" +#include "qdeclarative.h" +#include "qdeclarativecontext.h" +#include "private/qdeclarativeglobal_p.h" +#include "private/qdeclarativedebugtrace_p.h" + +#include <QtCore/qstringbuilder.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeBoundSignalParameters : public QObject +{ +Q_OBJECT +public: + QDeclarativeBoundSignalParameters(const QMetaMethod &, QObject * = 0); + ~QDeclarativeBoundSignalParameters(); + + void setValues(void **); + void clearValues(); + +private: + friend class MetaObject; + int metaCall(QMetaObject::Call, int _id, void **); + struct MetaObject : public QAbstractDynamicMetaObject { + MetaObject(QDeclarativeBoundSignalParameters *b) + : parent(b) {} + + int metaCall(QMetaObject::Call c, int id, void **a) { + return parent->metaCall(c, id, a); + } + QDeclarativeBoundSignalParameters *parent; + }; + + int *types; + void **values; + QMetaObject *myMetaObject; +}; + +static int evaluateIdx = -1; + +QDeclarativeAbstractBoundSignal::QDeclarativeAbstractBoundSignal(QObject *parent) +: QObject(parent) +{ +} + +QDeclarativeAbstractBoundSignal::~QDeclarativeAbstractBoundSignal() +{ +} + +QDeclarativeBoundSignal::QDeclarativeBoundSignal(QObject *scope, const QMetaMethod &signal, + QObject *parent) +: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0) +{ + // This is thread safe. Although it may be updated by two threads, they + // will both set it to the same value - so the worst thing that can happen + // is that they both do the work to figure it out. Boo hoo. + if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount(); + + QDeclarative_setParent_noEvent(this, parent); + QDeclarativePropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx); +} + +QDeclarativeBoundSignal::QDeclarativeBoundSignal(QDeclarativeContext *ctxt, const QString &val, + QObject *scope, const QMetaMethod &signal, + QObject *parent) +: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0) +{ + // This is thread safe. Although it may be updated by two threads, they + // will both set it to the same value - so the worst thing that can happen + // is that they both do the work to figure it out. Boo hoo. + if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount(); + + QDeclarative_setParent_noEvent(this, parent); + QDeclarativePropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx); + + m_expression = new QDeclarativeExpression(ctxt, scope, val); +} + +QDeclarativeBoundSignal::~QDeclarativeBoundSignal() +{ + delete m_expression; + m_expression = 0; +} + +int QDeclarativeBoundSignal::index() const +{ + return m_signal.methodIndex(); +} + +/*! + Returns the signal expression. +*/ +QDeclarativeExpression *QDeclarativeBoundSignal::expression() const +{ + return m_expression; +} + +/*! + Sets the signal expression to \a e. Returns the current signal expression, + or null if there is no signal expression. + + The QDeclarativeBoundSignal instance takes ownership of \a e. The caller is + assumes ownership of the returned QDeclarativeExpression. +*/ +QDeclarativeExpression *QDeclarativeBoundSignal::setExpression(QDeclarativeExpression *e) +{ + QDeclarativeExpression *rv = m_expression; + m_expression = e; + if (m_expression) m_expression->setNotifyOnValueChanged(false); + return rv; +} + +QDeclarativeBoundSignal *QDeclarativeBoundSignal::cast(QObject *o) +{ + QDeclarativeAbstractBoundSignal *s = qobject_cast<QDeclarativeAbstractBoundSignal*>(o); + return static_cast<QDeclarativeBoundSignal *>(s); +} + +int QDeclarativeBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) +{ + if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) { + if (!m_expression) + return -1; + if (QDeclarativeDebugService::isDebuggingEnabled()) { + QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::HandlingSignal); + QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::HandlingSignal, QLatin1String(m_signal.signature()) % QLatin1String(": ") % m_expression->expression()); + QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::HandlingSignal, m_expression->sourceFile(), m_expression->lineNumber()); + } + m_isEvaluating = true; + if (!m_paramsValid) { + if (!m_signal.parameterTypes().isEmpty()) + m_params = new QDeclarativeBoundSignalParameters(m_signal, this); + m_paramsValid = true; + } + + if (m_params) m_params->setValues(a); + if (m_expression && m_expression->engine()) { + QDeclarativeExpressionPrivate::get(m_expression)->value(m_params); + if (m_expression && m_expression->hasError()) + QDeclarativeEnginePrivate::warning(m_expression->engine(), m_expression->error()); + } + if (m_params) m_params->clearValues(); + m_isEvaluating = false; + QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::HandlingSignal); + return -1; + } else { + return QObject::qt_metacall(c, id, a); + } +} + +QDeclarativeBoundSignalParameters::QDeclarativeBoundSignalParameters(const QMetaMethod &method, + QObject *parent) +: QObject(parent), types(0), values(0) +{ + MetaObject *mo = new MetaObject(this); + + // ### Optimize! + QMetaObjectBuilder mob; + mob.setSuperClass(&QDeclarativeBoundSignalParameters::staticMetaObject); + mob.setClassName("QDeclarativeBoundSignalParameters"); + + QList<QByteArray> paramTypes = method.parameterTypes(); + QList<QByteArray> paramNames = method.parameterNames(); + types = new int[paramTypes.count()]; + for (int ii = 0; ii < paramTypes.count(); ++ii) { + const QByteArray &type = paramTypes.at(ii); + const QByteArray &name = paramNames.at(ii); + + if (name.isEmpty() || type.isEmpty()) { + types[ii] = 0; + continue; + } + + QVariant::Type t = (QVariant::Type)QMetaType::type(type.constData()); + if (QDeclarativeMetaType::isQObject(t)) { + types[ii] = QMetaType::QObjectStar; + QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*"); + prop.setWritable(false); + } else { + QByteArray propType = type; + if (t >= QVariant::UserType || t == QVariant::Invalid) { + //copy of QDeclarativeObjectScriptClass::enumType() + QByteArray scope; + QByteArray name; + int scopeIdx = propType.lastIndexOf("::"); + if (scopeIdx != -1) { + scope = propType.left(scopeIdx); + name = propType.mid(scopeIdx + 2); + } else { + name = propType; + } + const QMetaObject *meta; + if (scope == "Qt") + meta = &QObject::staticQtMetaObject; + else + meta = parent->parent()->metaObject(); //### assumes parent->parent() + for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { + QMetaEnum m = meta->enumerator(i); + if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) { + t = QVariant::Int; + propType = "int"; + break; + } + } + } + if (QDeclarativeMetaType::canCopy(t)) { + types[ii] = t; + QMetaPropertyBuilder prop = mob.addProperty(name, propType); + prop.setWritable(false); + } else { + types[ii] = 0x80000000 | t; + QMetaPropertyBuilder prop = mob.addProperty(name, "QVariant"); + prop.setWritable(false); + } + } + } + myMetaObject = mob.toMetaObject(); + *static_cast<QMetaObject *>(mo) = *myMetaObject; + + d_ptr->metaObject = mo; +} + +QDeclarativeBoundSignalParameters::~QDeclarativeBoundSignalParameters() +{ + delete [] types; + qFree(myMetaObject); +} + +void QDeclarativeBoundSignalParameters::setValues(void **v) +{ + values = v; +} + +void QDeclarativeBoundSignalParameters::clearValues() +{ + values = 0; +} + +int QDeclarativeBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a) +{ + if (!values) + return -1; + + if (c == QMetaObject::ReadProperty && id >= 1) { + if (types[id - 1] & 0x80000000) { + *((QVariant *)a[0]) = QVariant(types[id - 1] & 0x7FFFFFFF, values[id]); + } else { + QDeclarativeMetaType::copy(types[id - 1], a[0], values[id]); + } + return -1; + } else { + return qt_metacall(c, id, a); + } +} + +QT_END_NAMESPACE + +#include <qdeclarativeboundsignal.moc> diff --git a/src/declarative/qml/qdeclarativeboundsignal_p.h b/src/declarative/qml/qdeclarativeboundsignal_p.h new file mode 100644 index 00000000..8a46179e --- /dev/null +++ b/src/declarative/qml/qdeclarativeboundsignal_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEBOUNDSIGNAL_P_H +#define QDECLARATIVEBOUNDSIGNAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativeexpression.h" + +#include <QtCore/qmetaobject.h> + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeAbstractBoundSignal : public QObject +{ + Q_OBJECT +public: + QDeclarativeAbstractBoundSignal(QObject *parent = 0); + virtual ~QDeclarativeAbstractBoundSignal() = 0; +}; + +class QDeclarativeBoundSignalParameters; +class QDeclarativeBoundSignal : public QDeclarativeAbstractBoundSignal +{ +public: + QDeclarativeBoundSignal(QObject *scope, const QMetaMethod &signal, QObject *parent); + QDeclarativeBoundSignal(QDeclarativeContext *ctxt, const QString &val, QObject *scope, + const QMetaMethod &signal, QObject *parent); + virtual ~QDeclarativeBoundSignal(); + + int index() const; + + QDeclarativeExpression *expression() const; + QDeclarativeExpression *setExpression(QDeclarativeExpression *); + + bool isEvaluating() const { return m_isEvaluating; } + + static QDeclarativeBoundSignal *cast(QObject *); + +protected: + virtual int qt_metacall(QMetaObject::Call c, int id, void **a); + +private: + QDeclarativeExpression *m_expression; + QMetaMethod m_signal; + bool m_paramsValid : 1; + bool m_isEvaluating : 1; + QDeclarativeBoundSignalParameters *m_params; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEBOUNDSIGNAL_P_H diff --git a/src/declarative/qml/qdeclarativecleanup.cpp b/src/declarative/qml/qdeclarativecleanup.cpp new file mode 100644 index 00000000..0af72694 --- /dev/null +++ b/src/declarative/qml/qdeclarativecleanup.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativecleanup_p.h" + +#include "private/qdeclarativeengine_p.h" + +QT_BEGIN_NAMESPACE + +/*! +\internal +\class QDeclarativeCleanup +\brief The QDeclarativeCleanup provides a callback when a QDeclarativeEngine is deleted. + +Any object that needs cleanup to occur before the QDeclarativeEngine's QScriptEngine is +destroyed should inherit from QDeclarativeCleanup. The clear() virtual method will be +called by QDeclarativeEngine just before it deletes the QScriptEngine. +*/ + +/*! +\internal + +Create a QDeclarativeCleanup for \a engine +*/ +QDeclarativeCleanup::QDeclarativeCleanup(QDeclarativeEngine *engine) +: prev(0), next(0) +{ + if (!engine) + return; + + QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine); + + if (p->cleanup) next = p->cleanup; + p->cleanup = this; + prev = &p->cleanup; + if (next) next->prev = &next; +} + +/*! +\internal +*/ +QDeclarativeCleanup::~QDeclarativeCleanup() +{ + if (prev) *prev = next; + if (next) next->prev = prev; + prev = 0; + next = 0; +} +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecleanup_p.h b/src/declarative/qml/qdeclarativecleanup_p.h new file mode 100644 index 00000000..65688c81 --- /dev/null +++ b/src/declarative/qml/qdeclarativecleanup_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECLEANUP_P_H +#define QDECLARATIVECLEANUP_P_H + +#include <QtCore/qglobal.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QDeclarativeEngine; +class QDeclarativeCleanup +{ +public: + QDeclarativeCleanup(QDeclarativeEngine *); + virtual ~QDeclarativeCleanup(); + +protected: + virtual void clear() = 0; + +private: + friend class QDeclarativeEnginePrivate; + QDeclarativeCleanup **prev; + QDeclarativeCleanup *next; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVECLEANUP_P_H + diff --git a/src/declarative/qml/qdeclarativecompiledbindings.cpp b/src/declarative/qml/qdeclarativecompiledbindings.cpp new file mode 100644 index 00000000..798c97f2 --- /dev/null +++ b/src/declarative/qml/qdeclarativecompiledbindings.cpp @@ -0,0 +1,2921 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// #define COMPILEDBINDINGS_DEBUG +// #define REGISTER_CLEANUP_DEBUG + +#include "private/qdeclarativecompiledbindings_p.h" + +#include <QtDeclarative/qdeclarativeinfo.h> +#include <private/qdeclarativecontext_p.h> +#include <private/qdeclarativejsast_p.h> +#include <private/qdeclarativejsengine_p.h> +#include <private/qdeclarativeexpression_p.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdebug.h> +#include <QtCore/qnumeric.h> +#include <private/qdeclarativeanchors_p_p.h> +#include <private/qdeclarativeglobal_p.h> +#include <private/qdeclarativefastproperties_p.h> +#include <private/qdeclarativedebugtrace_p.h> + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL); +DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER); +DEFINE_BOOL_CONFIG_OPTION(qmlDisableFastProperties, QML_DISABLE_FAST_PROPERTIES); +DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP); + +Q_GLOBAL_STATIC(QDeclarativeFastProperties, fastProperties); + +#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200) +# define QML_THREADED_INTERPRETER +#endif + +#define FOR_EACH_QML_INSTR(F) \ + F(Noop) /* Nop */ \ + F(BindingId) /* id */ \ + F(Subscribe) /* subscribe */ \ + F(SubscribeId) /* subscribe */ \ + F(FetchAndSubscribe) /* fetchAndSubscribe */ \ + F(LoadId) /* load */ \ + F(LoadScope) /* load */ \ + F(LoadRoot) /* load */ \ + F(LoadAttached) /* attached */ \ + F(ConvertIntToReal) /* unaryop */ \ + F(ConvertRealToInt) /* unaryop */ \ + F(Real) /* real_value */ \ + F(Int) /* int_value */ \ + F(Bool) /* bool_value */ \ + F(String) /* string_value */ \ + F(AddReal) /* binaryop */ \ + F(AddInt) /* binaryop */ \ + F(AddString) /* binaryop */ \ + F(MinusReal) /* binaryop */ \ + F(MinusInt) /* binaryop */ \ + F(CompareReal) /* binaryop */ \ + F(CompareString) /* binaryop */ \ + F(NotCompareReal) /* binaryop */ \ + F(NotCompareString) /* binaryop */ \ + F(GreaterThanReal) /* binaryop */ \ + F(MaxReal) /* binaryop */ \ + F(MinReal) /* binaryop */ \ + F(NewString) /* construct */ \ + F(NewUrl) /* construct */ \ + F(CleanupUrl) /* cleanup */ \ + F(CleanupString) /* cleanup */ \ + F(Copy) /* copy */ \ + F(Fetch) /* fetch */ \ + F(Store) /* store */ \ + F(Skip) /* skip */ \ + F(Done) /* done */ \ + /* Speculative property resolution */ \ + F(InitString) /* initstring */ \ + F(FindGeneric) /* find */ \ + F(FindGenericTerminal) /* find */ \ + F(FindProperty) /* find */ \ + F(FindPropertyTerminal) /* find */ \ + F(CleanupGeneric) /* cleanup */ \ + F(ConvertGenericToReal) /* unaryop */ \ + F(ConvertGenericToBool) /* unaryop */ \ + F(ConvertGenericToString) /* unaryop */ \ + F(ConvertGenericToUrl) /* unaryop */ + +#define QML_INSTR_ENUM(I) I, +#define QML_INSTR_ADDR(I) &&op_##I, + +#ifdef QML_THREADED_INTERPRETER +# define QML_BEGIN_INSTR(I) op_##I: +# define QML_END_INSTR(I) ++instr; goto *instr->common.code; +# define QML_INSTR_HEADER void *code; +#else +# define QML_BEGIN_INSTR(I) case Instr::I: +# define QML_END_INSTR(I) break; +# define QML_INSTR_HEADER +#endif + + +using namespace QDeclarativeJS; + +namespace { +// Supported types: int, qreal, QString (needs constr/destr), QObject*, bool +struct Register { + void setUndefined() { type = 0; } + void setUnknownButDefined() { type = -1; } + void setNaN() { setqreal(qSNaN()); } + bool isUndefined() const { return type == 0; } + + void setQObject(QObject *o) { qobjectValue = o; type = QMetaType::QObjectStar; } + QObject *getQObject() const { return qobjectValue; } + + void setqreal(qreal v) { qrealValue = v; type = QMetaType::QReal; } + qreal getqreal() const { return qrealValue; } + + void setint(int v) { intValue = v; type = QMetaType::Int; } + int getint() const { return intValue; } + + void setbool(bool v) { boolValue = v; type = QMetaType::Bool; } + bool getbool() const { return boolValue; } + + QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); } + QString *getstringptr() { return (QString *)typeDataPtr(); } + QUrl *geturlptr() { return (QUrl *)typeDataPtr(); } + const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); } + const QString *getstringptr() const { return (QString *)typeDataPtr(); } + const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); } + + void *typeDataPtr() { return (void *)&data; } + void *typeMemory() { return (void *)data; } + const void *typeDataPtr() const { return (void *)&data; } + const void *typeMemory() const { return (void *)data; } + + int gettype() const { return type; } + void settype(int t) { type = t; } + + int type; // Optional type + union { + QObject *qobjectValue; + qreal qrealValue; + int intValue; + bool boolValue; + char data[sizeof(QVariant)]; + qint64 q_for_alignment_1; + double q_for_alignment_2; + }; + +#ifdef REGISTER_CLEANUP_DEBUG + Register() { + type = 0; + } + + ~Register() { + int allowedTypes[] = { QMetaType::QObjectStar, QMetaType::QReal, QMetaType::Int, QMetaType::Bool, 0 }; + bool found = (type == 0); + int *ctype = allowedTypes; + while (!found && *ctype) { + found = (*ctype == type); + ++ctype; + } + if (!found) + qWarning("Register leaked of type %d", type); + } +#endif +}; +} + +class QDeclarativeCompiledBindingsPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QDeclarativeCompiledBindings) + +public: + QDeclarativeCompiledBindingsPrivate(); + virtual ~QDeclarativeCompiledBindingsPrivate(); + + struct Binding : public QDeclarativeAbstractBinding, public QDeclarativeDelayedError { + Binding() : enabled(false), updating(0), property(0), + scope(0), target(0), parent(0) {} + + // Inherited from QDeclarativeAbstractBinding + virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags); + virtual void update(QDeclarativePropertyPrivate::WriteFlags flags); + virtual void destroy(); + + int index:30; + bool enabled:1; + bool updating:1; + int property; + QObject *scope; + QObject *target; + + QDeclarativeCompiledBindingsPrivate *parent; + }; + + typedef QDeclarativeNotifierEndpoint Subscription; + Subscription *subscriptions; + QScriptDeclarativeClass::PersistentIdentifier *identifiers; + + void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags); + + const char *programData; + QDeclarativeRefCount *dataRef; + Binding *m_bindings; + quint32 *m_signalTable; + + static int methodCount; + + void init(); + void run(int instr, QDeclarativeContextData *context, + QDeclarativeDelayedError *error, QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags); + + + inline void unsubscribe(int subIndex); + inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex); + inline void subscribe(QObject *o, int notifyIndex, int subIndex); + + QDeclarativePropertyCache::Data *findproperty(QObject *obj, + const QScriptDeclarativeClass::Identifier &name, + QDeclarativeEnginePrivate *enginePriv, + QDeclarativePropertyCache::Data &local); + bool findproperty(QObject *obj, + Register *output, + QDeclarativeEnginePrivate *enginePriv, + int subIdx, + const QScriptDeclarativeClass::Identifier &name, + bool isTerminal); + void findgeneric(Register *output, // value output + int subIdx, // Subscription index in config + QDeclarativeContextData *context, // Context to search in + const QScriptDeclarativeClass::Identifier &name, + bool isTerminal); +}; + +QDeclarativeCompiledBindingsPrivate::QDeclarativeCompiledBindingsPrivate() +: subscriptions(0), identifiers(0), programData(0), dataRef(0), m_bindings(0), m_signalTable(0) +{ +} + +QDeclarativeCompiledBindingsPrivate::~QDeclarativeCompiledBindingsPrivate() +{ + delete [] subscriptions; subscriptions = 0; + delete [] identifiers; identifiers = 0; + if (dataRef) { + dataRef->release(); + dataRef = 0; + } +} + +int QDeclarativeCompiledBindingsPrivate::methodCount = -1; + +QDeclarativeCompiledBindings::QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context, + QDeclarativeRefCount *dataRef) +: QObject(*(new QDeclarativeCompiledBindingsPrivate)) +{ + Q_D(QDeclarativeCompiledBindings); + + if (d->methodCount == -1) + d->methodCount = QDeclarativeCompiledBindings::staticMetaObject.methodCount(); + + d->programData = program; + d->dataRef = dataRef; + if (d->dataRef) d->dataRef->addref(); + + d->init(); + + QDeclarativeAbstractExpression::setContext(context); +} + +QDeclarativeCompiledBindings::~QDeclarativeCompiledBindings() +{ + Q_D(QDeclarativeCompiledBindings); + + delete [] d->m_bindings; +} + +QDeclarativeAbstractBinding *QDeclarativeCompiledBindings::configBinding(int index, QObject *target, + QObject *scope, int property) +{ + Q_D(QDeclarativeCompiledBindings); + + QDeclarativeCompiledBindingsPrivate::Binding *rv = d->m_bindings + index; + + rv->index = index; + rv->property = property; + rv->target = target; + rv->scope = scope; + rv->parent = d; + + addref(); // This is decremented in Binding::destroy() + + return rv; +} + +void QDeclarativeCompiledBindingsPrivate::Binding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags) +{ + if (enabled != e) { + enabled = e; + + if (e) update(flags); + } +} + +void QDeclarativeCompiledBindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags) +{ + QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding); + parent->run(this, flags); + QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding); +} + +void QDeclarativeCompiledBindingsPrivate::Binding::destroy() +{ + enabled = false; + removeFromObject(); + clear(); + parent->q_func()->release(); +} + +int QDeclarativeCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **) +{ + Q_D(QDeclarativeCompiledBindings); + + if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) { + id -= d->methodCount; + + quint32 *reeval = d->m_signalTable + d->m_signalTable[id]; + quint32 count = *reeval; + ++reeval; + for (quint32 ii = 0; ii < count; ++ii) { + d->run(d->m_bindings + reeval[ii], QDeclarativePropertyPrivate::DontRemoveBinding); + } + } + return -1; +} + +void QDeclarativeCompiledBindingsPrivate::run(Binding *binding, QDeclarativePropertyPrivate::WriteFlags flags) +{ + Q_Q(QDeclarativeCompiledBindings); + + if (!binding->enabled) + return; + + QDeclarativeContextData *context = q->QDeclarativeAbstractExpression::context(); + if (!context || !context->isValid()) + return; + + if (binding->updating) { + QString name; + if (binding->property & 0xFFFF0000) { + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine); + + QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF]; + Q_ASSERT(vt); + + name = QLatin1String(binding->target->metaObject()->property(binding->property & 0xFFFF).name()); + name.append(QLatin1String(".")); + name.append(QLatin1String(vt->metaObject()->property(binding->property >> 24).name())); + } else { + name = QLatin1String(binding->target->metaObject()->property(binding->property).name()); + } + qmlInfo(binding->target) << QCoreApplication::translate("QDeclarativeCompiledBindings", "Binding loop detected for property \"%1\"").arg(name); + return; + } + + binding->updating = true; + if (binding->property & 0xFFFF0000) { + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine); + + QDeclarativeValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF]; + Q_ASSERT(vt); + vt->read(binding->target, binding->property & 0xFFFF); + + QObject *target = vt; + run(binding->index, context, binding, binding->scope, target, flags); + + vt->write(binding->target, binding->property & 0xFFFF, flags); + } else { + run(binding->index, context, binding, binding->scope, binding->target, flags); + } + binding->updating = false; +} + +namespace { +// This structure is exactly 8-bytes in size +struct Instr { + enum { + FOR_EACH_QML_INSTR(QML_INSTR_ENUM) + }; + + union { + struct { + QML_INSTR_HEADER + quint8 type; + quint8 packing[7]; + } common; + struct { + QML_INSTR_HEADER + quint8 type; + quint8 packing; + quint16 column; + quint32 line; + } id; + struct { + QML_INSTR_HEADER + quint8 type; + quint8 packing[3]; + quint16 subscriptions; + quint16 identifiers; + } init; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 reg; + quint16 offset; + quint32 index; + } subscribe; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 reg; + quint8 packing[2]; + quint32 index; + } load; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 output; + qint8 reg; + quint8 exceptionId; + quint32 id; + } attached; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 output; + qint8 reg; + quint8 exceptionId; + quint32 index; + } store; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 output; + qint8 objectReg; + quint8 exceptionId; + quint16 subscription; + quint16 function; + } fetchAndSubscribe; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 output; + qint8 objectReg; + quint8 exceptionId; + quint32 index; + } fetch; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 reg; + qint8 src; + quint8 packing[5]; + } copy; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 reg; + quint8 packing[6]; + } construct; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 reg; + quint8 packing[2]; + float value; + } real_value; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 reg; + quint8 packing[2]; + int value; + } int_value; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 reg; + bool value; + quint8 packing[5]; + } bool_value; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 reg; + quint16 length; + quint32 offset; + } string_value; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 output; + qint8 src1; + qint8 src2; + quint8 packing[4]; + } binaryop; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 output; + qint8 src; + quint8 packing[5]; + } unaryop; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 reg; + quint8 packing[2]; + quint32 count; + } skip; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 reg; + qint8 src; + quint8 exceptionId; + quint16 name; + quint16 subscribeIndex; + } find; + struct { + QML_INSTR_HEADER + quint8 type; + qint8 reg; + quint8 packing[6]; + } cleanup; + struct { + QML_INSTR_HEADER + quint8 type; + quint8 packing[1]; + quint16 offset; + quint32 dataIdx; + } initstring; + }; +}; + +struct Program { + quint32 bindings; + quint32 dataLength; + quint32 signalTableOffset; + quint32 exceptionDataOffset; + quint16 subscriptions; + quint16 identifiers; + quint16 instructionCount; + quint16 compiled; + + const char *data() const { return ((const char *)this) + sizeof(Program); } + const Instr *instructions() const { return (const Instr *)(data() + dataLength); } +}; +} + +struct QDeclarativeBindingCompilerPrivate +{ + struct Result { + Result() : unknownType(false), metaObject(0), type(-1), reg(-1) {} + bool operator==(const Result &o) const { + return unknownType == o.unknownType && + metaObject == o.metaObject && + type == o.type && + reg == o.reg; + } + bool operator!=(const Result &o) const { + return !(*this == o); + } + bool unknownType; + const QMetaObject *metaObject; + int type; + int reg; + + QSet<QString> subscriptionSet; + }; + + QDeclarativeBindingCompilerPrivate() : registers(0) {} + + void resetInstanceState(); + int commitCompile(); + + QDeclarativeParser::Object *context; + QDeclarativeParser::Object *component; + QDeclarativeParser::Property *destination; + QHash<QString, QDeclarativeParser::Object *> ids; + QDeclarativeImports imports; + QDeclarativeEnginePrivate *engine; + + QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)context, 16); } + + bool compile(QDeclarativeJS::AST::Node *); + + bool parseExpression(QDeclarativeJS::AST::Node *, Result &); + + bool tryName(QDeclarativeJS::AST::Node *); + bool parseName(QDeclarativeJS::AST::Node *, Result &); + + bool tryArith(QDeclarativeJS::AST::Node *); + bool parseArith(QDeclarativeJS::AST::Node *, Result &); + bool numberArith(Result &, const Result &, const Result &, QSOperator::Op op); + bool stringArith(Result &, const Result &, const Result &, QSOperator::Op op); + + bool tryLogic(QDeclarativeJS::AST::Node *); + bool parseLogic(QDeclarativeJS::AST::Node *, Result &); + + bool tryConditional(QDeclarativeJS::AST::Node *); + bool parseConditional(QDeclarativeJS::AST::Node *, Result &); + + bool tryConstant(QDeclarativeJS::AST::Node *); + bool parseConstant(QDeclarativeJS::AST::Node *, Result &); + + bool tryMethod(QDeclarativeJS::AST::Node *); + bool parseMethod(QDeclarativeJS::AST::Node *, Result &); + + bool buildName(QStringList &, QDeclarativeJS::AST::Node *, QList<QDeclarativeJS::AST::ExpressionNode *> *nodes = 0); + bool fetch(Result &type, const QMetaObject *, int reg, int idx, const QStringList &, QDeclarativeJS::AST::ExpressionNode *); + + quint32 registers; + QHash<int, QPair<int, int> > registerCleanups; + int acquireReg(int cleanup = Instr::Noop, int cleanupType = 0); + void registerCleanup(int reg, int cleanup, int cleanupType = 0); + void releaseReg(int); + + int registerLiteralString(const QString &); + int registerString(const QString &); + QHash<QString, QPair<int, int> > registeredStrings; + QByteArray data; + + bool subscription(const QStringList &, Result *); + int subscriptionIndex(const QStringList &); + bool subscriptionNeutral(const QSet<QString> &base, const QSet<QString> &lhs, const QSet<QString> &rhs); + + quint8 exceptionId(QDeclarativeJS::AST::ExpressionNode *); + QVector<quint64> exceptions; + + QSet<int> usedSubscriptionIds; + QSet<QString> subscriptionSet; + QHash<QString, int> subscriptionIds; + QVector<Instr> bytecode; + + // Committed binding data + struct { + QList<int> offsets; + QList<QSet<int> > dependencies; + + QVector<Instr> bytecode; + QByteArray data; + QHash<QString, int> subscriptionIds; + QVector<quint64> exceptions; + + QHash<QString, QPair<int, int> > registeredStrings; + + int count() const { return offsets.count(); } + } committed; + + QByteArray buildSignalTable() const; + QByteArray buildExceptionData() const; +}; + +void QDeclarativeCompiledBindingsPrivate::unsubscribe(int subIndex) +{ + QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); + sub->disconnect(); +} + +void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex) +{ + Q_Q(QDeclarativeCompiledBindings); + + unsubscribe(subIndex); + + if (p->idValues[idIndex]) { + QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); + sub->target = q; + sub->targetMethod = methodCount + subIndex; + sub->connect(&p->idValues[idIndex].bindings); + } +} + +void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex) +{ + Q_Q(QDeclarativeCompiledBindings); + + QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); + sub->target = q; + sub->targetMethod = methodCount + subIndex; + if (o) + sub->connect(o, notifyIndex); + else + sub->disconnect(); +} + +// Conversion functions - these MUST match the QtScript expression path +inline static qreal toReal(Register *reg, int type, bool *ok = 0) +{ + if (ok) *ok = true; + + if (type == QMetaType::QReal) { + return reg->getqreal(); + } else if (type == qMetaTypeId<QVariant>()) { + return reg->getvariantptr()->toReal(); + } else { + if (ok) *ok = false; + return 0; + } +} + +inline static QString toString(Register *reg, int type, bool *ok = 0) +{ + if (ok) *ok = true; + + if (type == QMetaType::QReal) { + return QString::number(reg->getqreal()); + } else if (type == QMetaType::Int) { + return QString::number(reg->getint()); + } else if (type == qMetaTypeId<QVariant>()) { + return reg->getvariantptr()->toString(); + } else if (type == QMetaType::QString) { + return *reg->getstringptr(); + } else { + if (ok) *ok = false; + return QString(); + } +} + +inline static bool toBool(Register *reg, int type, bool *ok = 0) +{ + if (ok) *ok = true; + + if (type == QMetaType::Bool) { + return reg->getbool(); + } else if (type == qMetaTypeId<QVariant>()) { + return reg->getvariantptr()->toBool(); + } else { + if (ok) *ok = false; + return false; + } +} + +inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *context, bool *ok = 0) +{ + if (ok) *ok = true; + + QUrl base; + if (type == qMetaTypeId<QVariant>()) { + QVariant *var = reg->getvariantptr(); + int vt = var->type(); + if (vt == QVariant::Url) { + base = var->toUrl(); + } else if (vt == QVariant::ByteArray) { + base = QUrl(QString::fromUtf8(var->toByteArray())); + } else if (vt == QVariant::String) { + base = QUrl(var->toString()); + } else { + if (ok) *ok = false; + return QUrl(); + } + } else if (type == QMetaType::QString) { + base = QUrl(*reg->getstringptr()); + } else { + if (ok) *ok = false; + return QUrl(); + } + + if (!base.isEmpty() && base.isRelative()) + return context->url.resolved(base); + else + return base; +} + +static QObject *variantToQObject(const QVariant &value, bool *ok) +{ + if (ok) *ok = true; + + if (value.userType() == QMetaType::QObjectStar) { + return qvariant_cast<QObject*>(value); + } else { + if (ok) *ok = false; + return 0; + } +} + +bool QDeclarativeCompiledBindingsPrivate::findproperty(QObject *obj, Register *output, + QDeclarativeEnginePrivate *enginePriv, + int subIdx, const QScriptDeclarativeClass::Identifier &name, + bool isTerminal) +{ + if (!obj) { + output->setUndefined(); + return false; + } + + QDeclarativePropertyCache::Data local; + QDeclarativePropertyCache::Data *property = + QDeclarativePropertyCache::property(QDeclarativeEnginePrivate::get(enginePriv), obj, name, local); + + if (property) { + if (subIdx != -1) + subscribe(obj, property->notifyIndex, subIdx); + + if (property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) { + void *args[] = { output->typeDataPtr(), 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + output->settype(QMetaType::QObjectStar); + } else if (property->propType == qMetaTypeId<QVariant>()) { + QVariant v; + void *args[] = { &v, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + + if (isTerminal) { + new (output->typeDataPtr()) QVariant(v); + output->settype(qMetaTypeId<QVariant>()); + } else { + bool ok; + output->setQObject(variantToQObject(v, &ok)); + if (!ok) + output->setUndefined(); + else + output->settype(QMetaType::QObjectStar); + } + + } else { + if (!isTerminal) { + output->setUndefined(); + } else if (property->propType == QMetaType::QReal) { + void *args[] = { output->typeDataPtr(), 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + output->settype(QMetaType::QReal); + } else if (property->propType == QMetaType::Int) { + void *args[] = { output->typeDataPtr(), 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + output->settype(QMetaType::Int); + } else if (property->propType == QMetaType::Bool) { + void *args[] = { output->typeDataPtr(), 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + output->settype(QMetaType::Bool); + } else if (property->propType == QMetaType::QString) { + new (output->typeDataPtr()) QString(); + void *args[] = { output->typeDataPtr(), 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); + output->settype(QMetaType::QString); + } else { + new (output->typeDataPtr()) + QVariant(obj->metaObject()->property(property->coreIndex).read(obj)); + output->settype(qMetaTypeId<QVariant>()); + } + } + + return true; + } else { + output->setUndefined(); + return false; + } +} + +void QDeclarativeCompiledBindingsPrivate::findgeneric(Register *output, + int subIdx, + QDeclarativeContextData *context, + const QScriptDeclarativeClass::Identifier &name, + bool isTerminal) +{ + QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context->engine); + + while (context) { + + int contextPropertyIndex = context->propertyNames?context->propertyNames->value(name):-1; + + + if (contextPropertyIndex != -1) { + + if (contextPropertyIndex < context->idValueCount) { + output->setQObject(context->idValues[contextPropertyIndex]); + output->settype(QMetaType::QObjectStar); + + if (subIdx != -1) + subscribeId(context, contextPropertyIndex, subIdx); + + } else { + QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate(); + const QVariant &value = cp->propertyValues.at(contextPropertyIndex); + + if (isTerminal) { + new (output->typeDataPtr()) QVariant(value); + output->settype(qMetaTypeId<QVariant>()); + } else { + bool ok; + output->setQObject(variantToQObject(value, &ok)); + if (!ok) { output->setUndefined(); } + else { output->settype(QMetaType::QObjectStar); } + return; + } + + if (subIdx != -1) + subscribe(context->asQDeclarativeContext(), contextPropertyIndex + cp->notifyIndex, subIdx); + + + } + + return; + } + + if (QObject *root = context->contextObject) { + + if (findproperty(root, output, enginePriv, subIdx, name, isTerminal)) + return; + + } + + context = context->parent; + } + + output->setUndefined(); +} + +void QDeclarativeCompiledBindingsPrivate::init() +{ + Program *program = (Program *)programData; + if (program->subscriptions) + subscriptions = new QDeclarativeCompiledBindingsPrivate::Subscription[program->subscriptions]; + if (program->identifiers) + identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers]; + + m_signalTable = (quint32 *)(program->data() + program->signalTableOffset); + m_bindings = new QDeclarativeCompiledBindingsPrivate::Binding[program->bindings]; +} + +static void throwException(int id, QDeclarativeDelayedError *error, + Program *program, QDeclarativeContextData *context, + const QString &description = QString()) +{ + error->error.setUrl(context->url); + if (description.isEmpty()) + error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object")); + else + error->error.setDescription(description); + if (id != 0xFF) { + quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id); + error->error.setLine((e >> 32) & 0xFFFFFFFF); + error->error.setColumn(e & 0xFFFFFFFF); + } else { + error->error.setLine(-1); + error->error.setColumn(-1); + } + if (!context->engine || !error->addError(QDeclarativeEnginePrivate::get(context->engine))) + QDeclarativeEnginePrivate::warning(context->engine, error->error); +} + +static void dumpInstruction(const Instr *instr) +{ + switch (instr->common.type) { + case Instr::Noop: + qWarning().nospace() << "\t" << "Noop"; + break; + case Instr::BindingId: + qWarning().nospace() << instr->id.line << ":" << instr->id.column << ":"; + break; + case Instr::Subscribe: + qWarning().nospace() << "\t" << "Subscribe" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index; + break; + case Instr::SubscribeId: + qWarning().nospace() << "\t" << "SubscribeId" << "\t\t" << instr->subscribe.offset << "\t" << instr->subscribe.reg << "\t" << instr->subscribe.index; + break; + case Instr::FetchAndSubscribe: + qWarning().nospace() << "\t" << "FetchAndSubscribe" << "\t" << instr->fetchAndSubscribe.output << "\t" << instr->fetchAndSubscribe.objectReg << "\t" << instr->fetchAndSubscribe.subscription; + break; + case Instr::LoadId: + qWarning().nospace() << "\t" << "LoadId" << "\t\t\t" << instr->load.index << "\t" << instr->load.reg; + break; + case Instr::LoadScope: + qWarning().nospace() << "\t" << "LoadScope" << "\t\t" << instr->load.index << "\t" << instr->load.reg; + break; + case Instr::LoadRoot: + qWarning().nospace() << "\t" << "LoadRoot" << "\t\t" << instr->load.index << "\t" << instr->load.reg; + break; + case Instr::LoadAttached: + qWarning().nospace() << "\t" << "LoadAttached" << "\t\t" << instr->attached.output << "\t" << instr->attached.reg << "\t" << instr->attached.id; + break; + case Instr::ConvertIntToReal: + qWarning().nospace() << "\t" << "ConvertIntToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + case Instr::ConvertRealToInt: + qWarning().nospace() << "\t" << "ConvertRealToInt" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + case Instr::Real: + qWarning().nospace() << "\t" << "Real" << "\t\t\t" << instr->real_value.reg << "\t" << instr->real_value.value; + break; + case Instr::Int: + qWarning().nospace() << "\t" << "Int" << "\t\t\t" << instr->int_value.reg << "\t" << instr->int_value.value; + break; + case Instr::Bool: + qWarning().nospace() << "\t" << "Bool" << "\t\t\t" << instr->bool_value.reg << "\t" << instr->bool_value.value; + break; + case Instr::String: + qWarning().nospace() << "\t" << "String" << "\t\t\t" << instr->string_value.reg << "\t" << instr->string_value.offset << "\t" << instr->string_value.length; + break; + case Instr::AddReal: + qWarning().nospace() << "\t" << "AddReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::AddInt: + qWarning().nospace() << "\t" << "AddInt" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::AddString: + qWarning().nospace() << "\t" << "AddString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::MinusReal: + qWarning().nospace() << "\t" << "MinusReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::MinusInt: + qWarning().nospace() << "\t" << "MinusInt" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::CompareReal: + qWarning().nospace() << "\t" << "CompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::CompareString: + qWarning().nospace() << "\t" << "CompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::NotCompareReal: + qWarning().nospace() << "\t" << "NotCompareReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::NotCompareString: + qWarning().nospace() << "\t" << "NotCompareString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::GreaterThanReal: + qWarning().nospace() << "\t" << "GreaterThanReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::MaxReal: + qWarning().nospace() << "\t" << "MaxReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::MinReal: + qWarning().nospace() << "\t" << "MinReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; + case Instr::NewString: + qWarning().nospace() << "\t" << "NewString" << "\t\t" << instr->construct.reg; + break; + case Instr::NewUrl: + qWarning().nospace() << "\t" << "NewUrl" << "\t\t\t" << instr->construct.reg; + break; + case Instr::CleanupString: + qWarning().nospace() << "\t" << "CleanupString" << "\t\t" << instr->cleanup.reg; + break; + case Instr::CleanupUrl: + qWarning().nospace() << "\t" << "CleanupUrl" << "\t\t" << instr->cleanup.reg; + break; + case Instr::Fetch: + qWarning().nospace() << "\t" << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg; + break; + case Instr::Store: + qWarning().nospace() << "\t" << "Store" << "\t\t\t" << instr->store.output << "\t" << instr->store.index << "\t" << instr->store.reg; + break; + case Instr::Copy: + qWarning().nospace() << "\t" << "Copy" << "\t\t\t" << instr->copy.reg << "\t" << instr->copy.src; + break; + case Instr::Skip: + qWarning().nospace() << "\t" << "Skip" << "\t\t\t" << instr->skip.reg << "\t" << instr->skip.count; + break; + case Instr::Done: + qWarning().nospace() << "\t" << "Done"; + break; + case Instr::InitString: + qWarning().nospace() << "\t" << "InitString" << "\t\t" << instr->initstring.offset << "\t" << instr->initstring.dataIdx; + break; + case Instr::FindGeneric: + qWarning().nospace() << "\t" << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.name; + break; + case Instr::FindGenericTerminal: + qWarning().nospace() << "\t" << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" << instr->find.name; + break; + case Instr::FindProperty: + qWarning().nospace() << "\t" << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name; + break; + case Instr::FindPropertyTerminal: + qWarning().nospace() << "\t" << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name; + break; + case Instr::CleanupGeneric: + qWarning().nospace() << "\t" << "CleanupGeneric" << "\t\t" << instr->cleanup.reg; + break; + case Instr::ConvertGenericToReal: + qWarning().nospace() << "\t" << "ConvertGenericToReal" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + case Instr::ConvertGenericToBool: + qWarning().nospace() << "\t" << "ConvertGenericToBool" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + case Instr::ConvertGenericToString: + qWarning().nospace() << "\t" << "ConvertGenericToString" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + case Instr::ConvertGenericToUrl: + qWarning().nospace() << "\t" << "ConvertGenericToUrl" << "\t" << instr->unaryop.output << "\t" << instr->unaryop.src; + break; + default: + qWarning().nospace() << "\t" << "Unknown"; + break; + } +} + +void QDeclarativeCompiledBindingsPrivate::run(int instrIndex, + QDeclarativeContextData *context, QDeclarativeDelayedError *error, + QObject *scope, QObject *output, QDeclarativePropertyPrivate::WriteFlags storeFlags) +{ + Q_Q(QDeclarativeCompiledBindings); + + error->removeError(); + + Register registers[32]; + + QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(context->engine); + Program *program = (Program *)programData; + const Instr *instr = program->instructions(); + instr += instrIndex; + const char *data = program->data(); + +#ifdef QML_THREADED_INTERPRETER + static void *decode_instr[] = { + FOR_EACH_QML_INSTR(QML_INSTR_ADDR) + }; + + if (!program->compiled) { + program->compiled = true; + const Instr *inop = program->instructions(); + for (int i = 0; i < program->instructionCount; ++i) { + Instr *op = (Instr *) inop++; + op->common.code = decode_instr[op->common.type]; + } + } + + goto *instr->common.code; +#else + // return; + +#ifdef COMPILEDBINDINGS_DEBUG + qWarning().nospace() << "Begin binding run"; +#endif + + while (instr) { + switch (instr->common.type) { + +#ifdef COMPILEDBINDINGS_DEBUG + dumpInstruction(instr); +#endif + +#endif + + QML_BEGIN_INSTR(Noop) + QML_END_INSTR(Noop) + + QML_BEGIN_INSTR(BindingId) + QML_END_INSTR(BindingId) + + QML_BEGIN_INSTR(SubscribeId) + subscribeId(context, instr->subscribe.index, instr->subscribe.offset); + QML_END_INSTR(SubscribeId) + + QML_BEGIN_INSTR(Subscribe) + { + QObject *o = 0; + const Register &object = registers[instr->subscribe.reg]; + if (!object.isUndefined()) o = object.getQObject(); + subscribe(o, instr->subscribe.index, instr->subscribe.offset); + } + QML_END_INSTR(Subscribe) + + QML_BEGIN_INSTR(FetchAndSubscribe) + { + const Register &input = registers[instr->fetchAndSubscribe.objectReg]; + Register &output = registers[instr->fetchAndSubscribe.output]; + + if (input.isUndefined()) { + throwException(instr->fetchAndSubscribe.exceptionId, error, program, context); + return; + } + + QObject *object = input.getQObject(); + if (!object) { + output.setUndefined(); + } else { + int subIdx = instr->fetchAndSubscribe.subscription; + QDeclarativeCompiledBindingsPrivate::Subscription *sub = 0; + if (subIdx != -1) { + sub = (subscriptions + subIdx); + sub->target = q; + sub->targetMethod = methodCount + subIdx; + } + fastProperties()->accessor(instr->fetchAndSubscribe.function)(object, output.typeDataPtr(), sub); + } + } + QML_END_INSTR(FetchAndSubscribe) + + QML_BEGIN_INSTR(LoadId) + registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data()); + QML_END_INSTR(LoadId) + + QML_BEGIN_INSTR(LoadScope) + registers[instr->load.reg].setQObject(scope); + QML_END_INSTR(LoadScope) + + QML_BEGIN_INSTR(LoadRoot) + registers[instr->load.reg].setQObject(context->contextObject); + QML_END_INSTR(LoadRoot) + + QML_BEGIN_INSTR(LoadAttached) + { + const Register &input = registers[instr->attached.reg]; + Register &output = registers[instr->attached.output]; + if (input.isUndefined()) { + throwException(instr->attached.exceptionId, error, program, context); + return; + } + + QObject *object = registers[instr->attached.reg].getQObject(); + if (!object) { + output.setUndefined(); + } else { + QObject *attached = + qmlAttachedPropertiesObjectById(instr->attached.id, + registers[instr->attached.reg].getQObject(), + true); + Q_ASSERT(attached); + output.setQObject(attached); + } + } + QML_END_INSTR(LoadAttached) + + QML_BEGIN_INSTR(ConvertIntToReal) + { + const Register &input = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (input.isUndefined()) output.setUndefined(); + else output.setqreal(qreal(input.getint())); + } + QML_END_INSTR(ConvertIntToReal) + + QML_BEGIN_INSTR(ConvertRealToInt) + { + const Register &input = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (input.isUndefined()) output.setUndefined(); + else output.setint(qRound(input.getqreal())); + } + QML_END_INSTR(ConvertRealToInt) + + QML_BEGIN_INSTR(Real) + registers[instr->real_value.reg].setqreal(instr->real_value.value); + QML_END_INSTR(Real) + + QML_BEGIN_INSTR(Int) + registers[instr->int_value.reg].setint(instr->int_value.value); + QML_END_INSTR(Int) + + QML_BEGIN_INSTR(Bool) + registers[instr->bool_value.reg].setbool(instr->bool_value.value); + QML_END_INSTR(Bool) + + QML_BEGIN_INSTR(String) + { + Register &output = registers[instr->string_value.reg]; + new (output.getstringptr()) + QString((QChar *)(data + instr->string_value.offset), instr->string_value.length); + output.settype(QMetaType::QString); + } + QML_END_INSTR(String) + + QML_BEGIN_INSTR(AddReal) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setqreal(lhs.getqreal() + rhs.getqreal()); + } + QML_END_INSTR(AddReal) + + QML_BEGIN_INSTR(AddInt) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setint(lhs.getint() + rhs.getint()); + } + QML_END_INSTR(AddInt) + + QML_BEGIN_INSTR(AddString) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() && rhs.isUndefined()) { output.setNaN(); } + else { + if (lhs.isUndefined()) + new (output.getstringptr()) + QString(QLatin1String("undefined") + *registers[instr->binaryop.src2].getstringptr()); + else if (rhs.isUndefined()) + new (output.getstringptr()) + QString(*registers[instr->binaryop.src1].getstringptr() + QLatin1String("undefined")); + else + new (output.getstringptr()) + QString(*registers[instr->binaryop.src1].getstringptr() + + *registers[instr->binaryop.src2].getstringptr()); + output.settype(QMetaType::QString); + } + } + QML_END_INSTR(AddString) + + QML_BEGIN_INSTR(MinusReal) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setqreal(lhs.getqreal() - rhs.getqreal()); + } + QML_END_INSTR(MinusReal) + + QML_BEGIN_INSTR(MinusInt) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setint(lhs.getint() - rhs.getint()); + } + QML_END_INSTR(MinusInt) + + QML_BEGIN_INSTR(CompareReal) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined()); + else output.setbool(lhs.getqreal() == rhs.getqreal()); + } + QML_END_INSTR(CompareReal) + + QML_BEGIN_INSTR(CompareString) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() == rhs.isUndefined()); + else output.setbool(*lhs.getstringptr() == *rhs.getstringptr()); + } + QML_END_INSTR(CompareString) + + QML_BEGIN_INSTR(NotCompareReal) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined()); + else output.setbool(lhs.getqreal() != rhs.getqreal()); + } + QML_END_INSTR(NotCompareReal) + + QML_BEGIN_INSTR(NotCompareString) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(lhs.isUndefined() != rhs.isUndefined()); + else output.setbool(*lhs.getstringptr() != *rhs.getstringptr()); + } + QML_END_INSTR(NotCompareString) + + QML_BEGIN_INSTR(GreaterThanReal) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setbool(false); + else output.setbool(lhs.getqreal() > rhs.getqreal()); + } + QML_END_INSTR(GreaterThanReal) + + QML_BEGIN_INSTR(MaxReal) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setqreal(qMax(lhs.getqreal(), rhs.getqreal())); + } + QML_END_INSTR(MaxReal) + + QML_BEGIN_INSTR(MinReal) + { + const Register &lhs = registers[instr->binaryop.src1]; + const Register &rhs = registers[instr->binaryop.src2]; + Register &output = registers[instr->binaryop.output]; + if (lhs.isUndefined() || rhs.isUndefined()) output.setNaN(); + else output.setqreal(qMin(lhs.getqreal(), rhs.getqreal())); + } + QML_END_INSTR(MinReal) + + QML_BEGIN_INSTR(NewString) + { + Register &output = registers[instr->construct.reg]; + new (output.getstringptr()) QString; + output.settype(QMetaType::QString); + } + QML_END_INSTR(NewString) + + QML_BEGIN_INSTR(NewUrl) + { + Register &output = registers[instr->construct.reg]; + new (output.geturlptr()) QUrl; + output.settype(QMetaType::QUrl); + } + QML_END_INSTR(NewUrl) + + QML_BEGIN_INSTR(CleanupString) + registers[instr->cleanup.reg].getstringptr()->~QString(); +#ifdef REGISTER_CLEANUP_DEBUG + registers[instr->cleanup.reg].setUndefined(); +#endif + QML_END_INSTR(CleanupString) + + QML_BEGIN_INSTR(CleanupUrl) + registers[instr->cleanup.reg].geturlptr()->~QUrl(); +#ifdef REGISTER_CLEANUP_DEBUG + registers[instr->cleanup.reg].setUndefined(); +#endif + QML_END_INSTR(CleanupUrl) + + QML_BEGIN_INSTR(Fetch) + { + const Register &input = registers[instr->fetch.objectReg]; + Register &output = registers[instr->fetch.output]; + + if (input.isUndefined()) { + throwException(instr->fetch.exceptionId, error, program, context); + return; + } + + QObject *object = input.getQObject(); + if (!object) { + output.setUndefined(); + } else { + void *argv[] = { output.typeDataPtr(), 0 }; + QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv); + } + } + QML_END_INSTR(Fetch) + + QML_BEGIN_INSTR(Store) + { + Register &data = registers[instr->store.reg]; + if (data.isUndefined()) { + throwException(instr->store.exceptionId, error, program, context, + QLatin1String("Unable to assign undefined value")); + return; + } + + int status = -1; + void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags }; + QMetaObject::metacall(output, QMetaObject::WriteProperty, + instr->store.index, argv); + } + QML_END_INSTR(Store) + + QML_BEGIN_INSTR(Copy) + registers[instr->copy.reg] = registers[instr->copy.src]; + QML_END_INSTR(Copy) + + QML_BEGIN_INSTR(Skip) + if (instr->skip.reg == -1 || !registers[instr->skip.reg].getbool()) + instr += instr->skip.count; + QML_END_INSTR(Skip) + + QML_BEGIN_INSTR(Done) + return; + QML_END_INSTR(Done) + + QML_BEGIN_INSTR(InitString) + if (!identifiers[instr->initstring.offset].identifier) { + quint32 len = *(quint32 *)(data + instr->initstring.dataIdx); + QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32)); + + QString str = QString::fromRawData(strdata, len); + + identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str); + } + QML_END_INSTR(InitString) + + QML_BEGIN_INSTR(FindGenericTerminal) + // We start the search in the parent context, as we know that the + // name is not present in the current context or it would have been + // found during the static compile + findgeneric(registers + instr->find.reg, instr->find.subscribeIndex, + context->parent, + identifiers[instr->find.name].identifier, + instr->common.type == Instr::FindGenericTerminal); + QML_END_INSTR(FindGenericTerminal) + + QML_BEGIN_INSTR(FindGeneric) + // We start the search in the parent context, as we know that the + // name is not present in the current context or it would have been + // found during the static compile + findgeneric(registers + instr->find.reg, instr->find.subscribeIndex, + context->parent, + identifiers[instr->find.name].identifier, + instr->common.type == Instr::FindGenericTerminal); + QML_END_INSTR(FindGeneric) + + QML_BEGIN_INSTR(FindPropertyTerminal) + { + const Register &object = registers[instr->find.src]; + if (object.isUndefined()) { + throwException(instr->find.exceptionId, error, program, context); + return; + } + + findproperty(object.getQObject(), registers + instr->find.reg, + QDeclarativeEnginePrivate::get(context->engine), + instr->find.subscribeIndex, identifiers[instr->find.name].identifier, + instr->common.type == Instr::FindPropertyTerminal); + } + QML_END_INSTR(FindPropertyTerminal) + + QML_BEGIN_INSTR(FindProperty) + { + const Register &object = registers[instr->find.src]; + if (object.isUndefined()) { + throwException(instr->find.exceptionId, error, program, context); + return; + } + + findproperty(object.getQObject(), registers + instr->find.reg, + QDeclarativeEnginePrivate::get(context->engine), + instr->find.subscribeIndex, identifiers[instr->find.name].identifier, + instr->common.type == Instr::FindPropertyTerminal); + } + QML_END_INSTR(FindProperty) + + QML_BEGIN_INSTR(CleanupGeneric) + { + int type = registers[instr->cleanup.reg].gettype(); + if (type == qMetaTypeId<QVariant>()) { + registers[instr->cleanup.reg].getvariantptr()->~QVariant(); +#ifdef REGISTER_CLEANUP_DEBUG + registers[instr->cleanup.reg].setUndefined(); +#endif + } else if (type == QMetaType::QString) { + registers[instr->cleanup.reg].getstringptr()->~QString(); +#ifdef REGISTER_CLEANUP_DEBUG + registers[instr->cleanup.reg].setUndefined(); +#endif + } else if (type == QMetaType::QUrl) { + registers[instr->cleanup.reg].geturlptr()->~QUrl(); +#ifdef REGISTER_CLEANUP_DEBUG + registers[instr->cleanup.reg].setUndefined(); +#endif + } + } + QML_END_INSTR(CleanupGeneric) + + QML_BEGIN_INSTR(ConvertGenericToReal) + { + Register &output = registers[instr->unaryop.output]; + Register &input = registers[instr->unaryop.src]; + bool ok = true; + output.setqreal(toReal(&input, input.gettype(), &ok)); + if (!ok) output.setUndefined(); + } + QML_END_INSTR(ConvertGenericToReal) + + QML_BEGIN_INSTR(ConvertGenericToBool) + { + Register &output = registers[instr->unaryop.output]; + Register &input = registers[instr->unaryop.src]; + bool ok = true; + output.setbool(toBool(&input, input.gettype(), &ok)); + if (!ok) output.setUndefined(); + } + QML_END_INSTR(ConvertGenericToBool) + + QML_BEGIN_INSTR(ConvertGenericToString) + { + Register &output = registers[instr->unaryop.output]; + Register &input = registers[instr->unaryop.src]; + bool ok = true; + QString str = toString(&input, input.gettype(), &ok); + if (ok) { new (output.getstringptr()) QString(str); output.settype(QMetaType::QString); } + else { output.setUndefined(); } + } + QML_END_INSTR(ConvertGenericToString) + + QML_BEGIN_INSTR(ConvertGenericToUrl) + { + Register &output = registers[instr->unaryop.output]; + Register &input = registers[instr->unaryop.src]; + bool ok = true; + QUrl url = toUrl(&input, input.gettype(), context, &ok); + if (ok) { new (output.geturlptr()) QUrl(url); output.settype(QMetaType::QUrl); } + else { output.setUndefined(); } + } + QML_END_INSTR(ConvertGenericToUrl) + +#ifdef QML_THREADED_INTERPRETER + // nothing to do +#else + default: + qFatal("EEK"); + break; + } // switch + + ++instr; + } // while +#endif +} + +void QDeclarativeBindingCompiler::dump(const QByteArray &programData) +{ + const Program *program = (const Program *)programData.constData(); + + qWarning() << "Program.bindings:" << program->bindings; + qWarning() << "Program.dataLength:" << program->dataLength; + qWarning() << "Program.subscriptions:" << program->subscriptions; + qWarning() << "Program.indentifiers:" << program->identifiers; + + int count = program->instructionCount; + const Instr *instr = program->instructions(); + + while (count--) { + + dumpInstruction(instr); + ++instr; + } +} + +/*! +Clear the state associated with attempting to compile a specific binding. +This does not clear the global "committed binding" states. +*/ +void QDeclarativeBindingCompilerPrivate::resetInstanceState() +{ + registers = 0; + registerCleanups.clear(); + data = committed.data; + exceptions = committed.exceptions; + usedSubscriptionIds.clear(); + subscriptionSet.clear(); + subscriptionIds = committed.subscriptionIds; + registeredStrings = committed.registeredStrings; + bytecode.clear(); +} + +/*! +Mark the last compile as successful, and add it to the "committed data" +section. + +Returns the index for the committed binding. +*/ +int QDeclarativeBindingCompilerPrivate::commitCompile() +{ + int rv = committed.count(); + committed.offsets << committed.bytecode.count(); + committed.dependencies << usedSubscriptionIds; + committed.bytecode << bytecode; + committed.data = data; + committed.exceptions = exceptions; + committed.subscriptionIds = subscriptionIds; + committed.registeredStrings = registeredStrings; + return rv; +} + +bool QDeclarativeBindingCompilerPrivate::compile(QDeclarativeJS::AST::Node *node) +{ + resetInstanceState(); + + if (destination->type == -1) + return false; + + if (bindingsDump()) { + QDeclarativeJS::AST::ExpressionNode *n = node->expressionCast(); + if (n) { + Instr id; + id.common.type = Instr::BindingId; + id.id.column = n->firstSourceLocation().startColumn; + id.id.line = n->firstSourceLocation().startLine; + bytecode << id; + } + } + + Result type; + + if (!parseExpression(node, type)) + return false; + + if (subscriptionSet.count() > 0xFFFF || + registeredStrings.count() > 0xFFFF) + return false; + + if (type.unknownType) { + if (!qmlExperimental()) + return false; + + if (destination->type != QMetaType::QReal && + destination->type != QVariant::String && + destination->type != QMetaType::Bool && + destination->type != QVariant::Url) + return false; + + int convertReg = acquireReg(); + if (convertReg == -1) + return false; + + if (destination->type == QMetaType::QReal) { + Instr convert; + convert.common.type = Instr::ConvertGenericToReal; + convert.unaryop.output = convertReg; + convert.unaryop.src = type.reg; + bytecode << convert; + } else if (destination->type == QVariant::String) { + Instr convert; + convert.common.type = Instr::ConvertGenericToString; + convert.unaryop.output = convertReg; + convert.unaryop.src = type.reg; + bytecode << convert; + } else if (destination->type == QMetaType::Bool) { + Instr convert; + convert.common.type = Instr::ConvertGenericToBool; + convert.unaryop.output = convertReg; + convert.unaryop.src = type.reg; + bytecode << convert; + } else if (destination->type == QVariant::Url) { + Instr convert; + convert.common.type = Instr::ConvertGenericToUrl; + convert.unaryop.output = convertReg; + convert.unaryop.src = type.reg; + bytecode << convert; + } + + Instr cleanup; + cleanup.common.type = Instr::CleanupGeneric; + cleanup.cleanup.reg = type.reg; + bytecode << cleanup; + + Instr instr; + instr.common.type = Instr::Store; + instr.store.output = 0; + instr.store.index = destination->index; + instr.store.reg = convertReg; + instr.store.exceptionId = exceptionId(node->expressionCast()); + bytecode << instr; + + if (destination->type == QVariant::String) { + Instr cleanup; + cleanup.common.type = Instr::CleanupString; + cleanup.cleanup.reg = convertReg; + bytecode << cleanup; + } else if (destination->type == QVariant::Url) { + Instr cleanup; + cleanup.common.type = Instr::CleanupUrl; + cleanup.cleanup.reg = convertReg; + bytecode << cleanup; + } + + releaseReg(convertReg); + + Instr done; + done.common.type = Instr::Done; + bytecode << done; + + } else { + // Can we store the final value? + if (type.type == QVariant::Int && + destination->type == QMetaType::QReal) { + Instr instr; + instr.common.type = Instr::ConvertIntToReal; + instr.unaryop.output = type.reg; + instr.unaryop.src = type.reg; + bytecode << instr; + type.type = QMetaType::QReal; + } else if (type.type == QMetaType::QReal && + destination->type == QVariant::Int) { + Instr instr; + instr.common.type = Instr::ConvertRealToInt; + instr.unaryop.output = type.reg; + instr.unaryop.src = type.reg; + bytecode << instr; + type.type = QVariant::Int; + } else if (type.type == destination->type) { + } else { + const QMetaObject *from = type.metaObject; + const QMetaObject *to = engine->rawMetaObjectForType(destination->type); + + if (QDeclarativePropertyPrivate::canConvert(from, to)) + type.type = destination->type; + } + + if (type.type == destination->type) { + Instr instr; + instr.common.type = Instr::Store; + instr.store.output = 0; + instr.store.index = destination->index; + instr.store.reg = type.reg; + instr.store.exceptionId = exceptionId(node->expressionCast()); + bytecode << instr; + + releaseReg(type.reg); + + Instr done; + done.common.type = Instr::Done; + bytecode << done; + } else { + return false; + } + } + + return true; +} + +bool QDeclarativeBindingCompilerPrivate::parseExpression(QDeclarativeJS::AST::Node *node, Result &type) +{ + while (node->kind == AST::Node::Kind_NestedExpression) + node = static_cast<AST::NestedExpression *>(node)->expression; + + if (tryArith(node)) { + if (!parseArith(node, type)) return false; + } else if (tryLogic(node)) { + if (!parseLogic(node, type)) return false; + } else if (tryConditional(node)) { + if (!parseConditional(node, type)) return false; + } else if (tryName(node)) { + if (!parseName(node, type)) return false; + } else if (tryConstant(node)) { + if (!parseConstant(node, type)) return false; + } else if (tryMethod(node)) { + if (!parseMethod(node, type)) return false; + } else { + return false; + } + return true; +} + +bool QDeclarativeBindingCompilerPrivate::tryName(QDeclarativeJS::AST::Node *node) +{ + return node->kind == AST::Node::Kind_IdentifierExpression || + node->kind == AST::Node::Kind_FieldMemberExpression; +} + +bool QDeclarativeBindingCompilerPrivate::parseName(AST::Node *node, Result &type) +{ + QStringList nameParts; + QList<AST::ExpressionNode *> nameNodes; + if (!buildName(nameParts, node, &nameNodes)) + return false; + + int reg = acquireReg(); + if (reg == -1) + return false; + type.reg = reg; + + QDeclarativeParser::Object *absType = 0; + + QStringList subscribeName; + + bool wasAttachedObject = false; + + for (int ii = 0; ii < nameParts.count(); ++ii) { + const QString &name = nameParts.at(ii); + + // We don't handle signal properties or attached properties + if (name.length() > 2 && name.startsWith(QLatin1String("on")) && + name.at(2).isUpper()) + return false; + + QDeclarativeType *attachType = 0; + if (name.at(0).isUpper()) { + // Could be an attached property + if (ii == nameParts.count() - 1) + return false; + if (nameParts.at(ii + 1).at(0).isUpper()) + return false; + + QDeclarativeImportedNamespace *ns = 0; + if (!imports.resolveType(name.toUtf8(), &attachType, 0, 0, 0, &ns)) + return false; + if (ns || !attachType || !attachType->attachedPropertiesType()) + return false; + + wasAttachedObject = true; + } + + if (ii == 0) { + + if (attachType) { + Instr instr; + instr.common.type = Instr::LoadScope; + instr.load.index = 0; + instr.load.reg = reg; + bytecode << instr; + + Instr attach; + attach.common.type = Instr::LoadAttached; + attach.attached.output = reg; + attach.attached.reg = reg; + attach.attached.id = attachType->attachedPropertiesId(); + attach.attached.exceptionId = exceptionId(nameNodes.at(ii)); + bytecode << attach; + + subscribeName << contextName(); + subscribeName << QLatin1String("$$$ATTACH_") + name; + + absType = 0; + type.metaObject = attachType->attachedPropertiesType(); + + continue; + } else if (ids.contains(name)) { + QDeclarativeParser::Object *idObject = ids.value(name); + absType = idObject; + type.metaObject = absType->metaObject(); + + // We check if the id object is the root or + // scope object to avoid a subscription + if (idObject == component) { + Instr instr; + instr.common.type = Instr::LoadRoot; + instr.load.index = 0; + instr.load.reg = reg; + bytecode << instr; + } else if (idObject == context) { + Instr instr; + instr.common.type = Instr::LoadScope; + instr.load.index = 0; + instr.load.reg = reg; + bytecode << instr; + } else { + Instr instr; + instr.common.type = Instr::LoadId; + instr.load.index = idObject->idIndex; + instr.load.reg = reg; + bytecode << instr; + + subscribeName << QLatin1String("$$$ID_") + name; + + if (subscription(subscribeName, &type)) { + Instr sub; + sub.common.type = Instr::SubscribeId; + sub.subscribe.offset = subscriptionIndex(subscribeName); + sub.subscribe.reg = reg; + sub.subscribe.index = instr.load.index; + bytecode << sub; + } + } + + } else { + + QByteArray utf8Name = name.toUtf8(); + const char *cname = utf8Name.constData(); + + int d0Idx = (context == component)?-1:context->metaObject()->indexOfProperty(cname); + int d1Idx = -1; + if (d0Idx == -1) + d1Idx = component->metaObject()->indexOfProperty(cname); + + if (d0Idx != -1) { + Instr instr; + instr.common.type = Instr::LoadScope; + instr.load.index = 0; + instr.load.reg = reg; + bytecode << instr; + + subscribeName << contextName(); + subscribeName << name; + + if (!fetch(type, context->metaObject(), reg, d0Idx, subscribeName, nameNodes.at(ii))) + return false; + } else if(d1Idx != -1) { + Instr instr; + instr.common.type = Instr::LoadRoot; + instr.load.index = 0; + instr.load.reg = reg; + bytecode << instr; + + subscribeName << QLatin1String("$$$ROOT"); + subscribeName << name; + + if (!fetch(type, component->metaObject(), reg, d1Idx, subscribeName, nameNodes.at(ii))) + return false; + } else if (qmlExperimental()) { + Instr find; + if (nameParts.count() == 1) + find.common.type = Instr::FindGenericTerminal; + else + find.common.type = Instr::FindGeneric; + + find.find.reg = reg; + find.find.src = -1; + find.find.name = registerString(name); + find.find.exceptionId = exceptionId(nameNodes.at(ii)); + + subscribeName << QString(QLatin1String("$$$Generic_") + name); + if (subscription(subscribeName, &type)) + find.find.subscribeIndex = subscriptionIndex(subscribeName); + else + find.find.subscribeIndex = -1; + + bytecode << find; + type.unknownType = true; + } + + if (!type.unknownType && type.type == -1) + return false; // Couldn't fetch that type + } + + } else { + + if (attachType) { + Instr attach; + attach.common.type = Instr::LoadAttached; + attach.attached.output = reg; + attach.attached.reg = reg; + attach.attached.id = attachType->attachedPropertiesId(); + bytecode << attach; + + absType = 0; + type.metaObject = attachType->attachedPropertiesType(); + + subscribeName << QLatin1String("$$$ATTACH_") + name; + continue; + } + + const QMetaObject *mo = 0; + if (absType) + mo = absType->metaObject(); + else if (type.metaObject) + mo = type.metaObject; + + QByteArray utf8Name = name.toUtf8(); + const char *cname = utf8Name.constData(); + int idx = mo?mo->indexOfProperty(cname):-1; + if (absType && idx == -1) + return false; + + subscribeName << name; + + if (absType || (wasAttachedObject && idx != -1) || (mo && mo->property(idx).isFinal())) { + absType = 0; + if (!fetch(type, mo, reg, idx, subscribeName, nameNodes.at(ii))) + return false; + } else { + + Instr prop; + if (ii == nameParts.count() -1 ) + prop.common.type = Instr::FindPropertyTerminal; + else + prop.common.type = Instr::FindProperty; + + prop.find.reg = reg; + prop.find.src = reg; + prop.find.name = registerString(name); + prop.find.exceptionId = exceptionId(nameNodes.at(ii)); + + if (subscription(subscribeName, &type)) + prop.find.subscribeIndex = subscriptionIndex(subscribeName); + else + prop.find.subscribeIndex = -1; + + type.unknownType = true; + type.metaObject = 0; + type.type = -1; + type.reg = reg; + bytecode << prop; + } + } + + wasAttachedObject = false; + } + + return true; +} + +bool QDeclarativeBindingCompilerPrivate::tryArith(QDeclarativeJS::AST::Node *node) +{ + if (node->kind != AST::Node::Kind_BinaryExpression) + return false; + + AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node); + if (expression->op == QSOperator::Add || + expression->op == QSOperator::Sub) + return true; + else + return false; +} + +bool QDeclarativeBindingCompilerPrivate::parseArith(QDeclarativeJS::AST::Node *node, Result &type) +{ + AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node); + + type.reg = acquireReg(); + if (type.reg == -1) + return false; + + Result lhs; + Result rhs; + + if (!parseExpression(expression->left, lhs)) return false; + if (!parseExpression(expression->right, rhs)) return false; + + if ((lhs.type == QVariant::Int || lhs.type == QMetaType::QReal) && + (rhs.type == QVariant::Int || rhs.type == QMetaType::QReal)) + return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op); + else if(expression->op == QSOperator::Sub) + return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op); + else if ((lhs.type == QMetaType::QString || lhs.unknownType) && + (rhs.type == QMetaType::QString || rhs.unknownType) && + (lhs.type == QMetaType::QString || rhs.type == QMetaType::QString)) + return stringArith(type, lhs, rhs, (QSOperator::Op)expression->op); + else + return false; +} + +bool QDeclarativeBindingCompilerPrivate::numberArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op) +{ + bool nativeReal = rhs.type == QMetaType::QReal || + lhs.type == QMetaType::QReal || + lhs.unknownType || + rhs.unknownType; + + if (nativeReal && lhs.type == QMetaType::Int) { + Instr convert; + convert.common.type = Instr::ConvertIntToReal; + convert.unaryop.output = lhs.reg; + convert.unaryop.src = lhs.reg; + bytecode << convert; + } + + if (nativeReal && rhs.type == QMetaType::Int) { + Instr convert; + convert.common.type = Instr::ConvertIntToReal; + convert.unaryop.output = rhs.reg; + convert.unaryop.src = rhs.reg; + bytecode << convert; + } + + int lhsTmp = -1; + int rhsTmp = -1; + + if (lhs.unknownType) { + if (!qmlExperimental()) + return false; + + lhsTmp = acquireReg(); + if (lhsTmp == -1) + return false; + + Instr conv; + conv.common.type = Instr::ConvertGenericToReal; + conv.unaryop.output = lhsTmp; + conv.unaryop.src = lhs.reg; + bytecode << conv; + } + + if (rhs.unknownType) { + if (!qmlExperimental()) + return false; + + rhsTmp = acquireReg(); + if (rhsTmp == -1) + return false; + + Instr conv; + conv.common.type = Instr::ConvertGenericToReal; + conv.unaryop.output = rhsTmp; + conv.unaryop.src = rhs.reg; + bytecode << conv; + } + + Instr arith; + if (op == QSOperator::Add) { + arith.common.type = nativeReal?Instr::AddReal:Instr::AddInt; + } else if (op == QSOperator::Sub) { + arith.common.type = nativeReal?Instr::MinusReal:Instr::MinusInt; + } else { + qFatal("Unsupported arithmetic operator"); + } + + arith.binaryop.output = type.reg; + arith.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp; + arith.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp; + bytecode << arith; + + type.metaObject = 0; + type.type = nativeReal?QMetaType::QReal:QMetaType::Int; + type.subscriptionSet.unite(lhs.subscriptionSet); + type.subscriptionSet.unite(rhs.subscriptionSet); + + if (lhsTmp != -1) releaseReg(lhsTmp); + if (rhsTmp != -1) releaseReg(rhsTmp); + releaseReg(lhs.reg); + releaseReg(rhs.reg); + + return true; +} + +bool QDeclarativeBindingCompilerPrivate::stringArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op) +{ + if (op != QSOperator::Add) + return false; + + int lhsTmp = -1; + int rhsTmp = -1; + + if (lhs.unknownType) { + if (!qmlExperimental()) + return false; + + lhsTmp = acquireReg(Instr::CleanupString); + if (lhsTmp == -1) + return false; + + Instr convert; + convert.common.type = Instr::ConvertGenericToString; + convert.unaryop.output = lhsTmp; + convert.unaryop.src = lhs.reg; + bytecode << convert; + } + + if (rhs.unknownType) { + if (!qmlExperimental()) + return false; + + rhsTmp = acquireReg(Instr::CleanupString); + if (rhsTmp == -1) + return false; + + Instr convert; + convert.common.type = Instr::ConvertGenericToString; + convert.unaryop.output = rhsTmp; + convert.unaryop.src = rhs.reg; + bytecode << convert; + } + + type.reg = acquireReg(Instr::CleanupString); + if (type.reg == -1) + return false; + + type.type = QMetaType::QString; + + Instr add; + add.common.type = Instr::AddString; + add.binaryop.output = type.reg; + add.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp; + add.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp; + bytecode << add; + + if (lhsTmp != -1) releaseReg(lhsTmp); + if (rhsTmp != -1) releaseReg(rhsTmp); + releaseReg(lhs.reg); + releaseReg(rhs.reg); + + return true; +} + +bool QDeclarativeBindingCompilerPrivate::tryLogic(QDeclarativeJS::AST::Node *node) +{ + if (node->kind != AST::Node::Kind_BinaryExpression) + return false; + + AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node); + if (expression->op == QSOperator::Gt || + expression->op == QSOperator::Equal || + expression->op == QSOperator::NotEqual) + return true; + else + return false; +} + +bool QDeclarativeBindingCompilerPrivate::parseLogic(QDeclarativeJS::AST::Node *node, Result &type) +{ + AST::BinaryExpression *expression = static_cast<AST::BinaryExpression *>(node); + + Result lhs; + Result rhs; + + if (!parseExpression(expression->left, lhs)) return false; + if (!parseExpression(expression->right, rhs)) return false; + + type.reg = acquireReg(); + if (type.reg == -1) + return false; + + type.metaObject = 0; + type.type = QVariant::Bool; + + if (lhs.type == QMetaType::QReal && rhs.type == QMetaType::QReal) { + + Instr op; + if (expression->op == QSOperator::Gt) + op.common.type = Instr::GreaterThanReal; + else if (expression->op == QSOperator::Equal) + op.common.type = Instr::CompareReal; + else if (expression->op == QSOperator::NotEqual) + op.common.type = Instr::NotCompareReal; + else + return false; + op.binaryop.output = type.reg; + op.binaryop.src1 = lhs.reg; + op.binaryop.src2 = rhs.reg; + bytecode << op; + + + } else if (lhs.type == QMetaType::QString && rhs.type == QMetaType::QString) { + + Instr op; + if (expression->op == QSOperator::Equal) + op.common.type = Instr::CompareString; + else if (expression->op == QSOperator::NotEqual) + op.common.type = Instr::NotCompareString; + else + return false; + op.binaryop.output = type.reg; + op.binaryop.src1 = lhs.reg; + op.binaryop.src2 = rhs.reg; + bytecode << op; + + } else { + return false; + } + + releaseReg(lhs.reg); + releaseReg(rhs.reg); + + return true; +} + +bool QDeclarativeBindingCompilerPrivate::tryConditional(QDeclarativeJS::AST::Node *node) +{ + return (node->kind == AST::Node::Kind_ConditionalExpression); +} + +bool QDeclarativeBindingCompilerPrivate::parseConditional(QDeclarativeJS::AST::Node *node, Result &type) +{ + AST::ConditionalExpression *expression = static_cast<AST::ConditionalExpression *>(node); + + AST::Node *test = expression->expression; + if (test->kind == AST::Node::Kind_NestedExpression) + test = static_cast<AST::NestedExpression*>(test)->expression; + + Result etype; + if (!parseExpression(test, etype)) return false; + + if (etype.type != QVariant::Bool) + return false; + + Instr skip; + skip.common.type = Instr::Skip; + skip.skip.reg = etype.reg; + skip.skip.count = 0; + int skipIdx = bytecode.count(); + bytecode << skip; + + // Release to allow reuse of reg + releaseReg(etype.reg); + + QSet<QString> preSubSet = subscriptionSet; + + // int preConditionalSubscriptions = subscriptionSet.count(); + + Result ok; + if (!parseExpression(expression->ok, ok)) return false; + if (ok.unknownType) return false; + + int skipIdx2 = bytecode.count(); + skip.skip.reg = -1; + bytecode << skip; + + // Release to allow reuse of reg in else path + releaseReg(ok.reg); + bytecode[skipIdx].skip.count = bytecode.count() - skipIdx - 1; + + subscriptionSet = preSubSet; + + Result ko; + if (!parseExpression(expression->ko, ko)) return false; + if (ko.unknownType) return false; + + // Do not release reg here, so that its ownership passes to the caller + bytecode[skipIdx2].skip.count = bytecode.count() - skipIdx2 - 1; + + if (ok != ko) + return false; // Must be same type and in same register + + subscriptionSet = preSubSet; + + if (!subscriptionNeutral(subscriptionSet, ok.subscriptionSet, ko.subscriptionSet)) + return false; // Conditionals cannot introduce new subscriptions + + type = ok; + + return true; +} + +bool QDeclarativeBindingCompilerPrivate::tryConstant(QDeclarativeJS::AST::Node *node) +{ + return node->kind == AST::Node::Kind_TrueLiteral || + node->kind == AST::Node::Kind_FalseLiteral || + node->kind == AST::Node::Kind_NumericLiteral || + node->kind == AST::Node::Kind_StringLiteral; +} + +bool QDeclarativeBindingCompilerPrivate::parseConstant(QDeclarativeJS::AST::Node *node, Result &type) +{ + type.metaObject = 0; + type.type = -1; + type.reg = acquireReg(); + if (type.reg == -1) + return false; + + if (node->kind == AST::Node::Kind_TrueLiteral) { + type.type = QVariant::Bool; + Instr instr; + instr.common.type = Instr::Bool; + instr.bool_value.reg = type.reg; + instr.bool_value.value = true; + bytecode << instr; + return true; + } else if (node->kind == AST::Node::Kind_FalseLiteral) { + type.type = QVariant::Bool; + Instr instr; + instr.common.type = Instr::Bool; + instr.bool_value.reg = type.reg; + instr.bool_value.value = false; + bytecode << instr; + return true; + } else if (node->kind == AST::Node::Kind_NumericLiteral) { + qreal value = qreal(static_cast<AST::NumericLiteral *>(node)->value); + + if (qreal(float(value)) != value) + return false; + + type.type = QMetaType::QReal; + Instr instr; + instr.common.type = Instr::Real; + instr.real_value.reg = type.reg; + instr.real_value.value = float(value); + bytecode << instr; + return true; + } else if (node->kind == AST::Node::Kind_StringLiteral) { + QString str = static_cast<AST::StringLiteral *>(node)->value->asString(); + type.type = QMetaType::QString; + type.reg = registerLiteralString(str); + return true; + } else { + return false; + } +} + +bool QDeclarativeBindingCompilerPrivate::tryMethod(QDeclarativeJS::AST::Node *node) +{ + return node->kind == AST::Node::Kind_CallExpression; +} + +bool QDeclarativeBindingCompilerPrivate::parseMethod(QDeclarativeJS::AST::Node *node, Result &result) +{ + AST::CallExpression *expr = static_cast<AST::CallExpression *>(node); + + QStringList name; + if (!buildName(name, expr->base)) + return false; + + if (name.count() != 2 || name.at(0) != QLatin1String("Math")) + return false; + + QString method = name.at(1); + + AST::ArgumentList *args = expr->arguments; + if (!args) return false; + AST::ExpressionNode *arg0 = args->expression; + args = args->next; + if (!args) return false; + AST::ExpressionNode *arg1 = args->expression; + if (args->next != 0) return false; + if (!arg0 || !arg1) return false; + + Result r0; + if (!parseExpression(arg0, r0)) return false; + Result r1; + if (!parseExpression(arg1, r1)) return false; + + if (r0.type != QMetaType::QReal || r1.type != QMetaType::QReal) + return false; + + Instr op; + if (method == QLatin1String("max")) { + op.common.type = Instr::MaxReal; + } else if (method == QLatin1String("min")) { + op.common.type = Instr::MinReal; + } else { + return false; + } + // We release early to reuse registers + releaseReg(r0.reg); + releaseReg(r1.reg); + + op.binaryop.output = acquireReg(); + if (op.binaryop.output == -1) + return false; + + op.binaryop.src1 = r0.reg; + op.binaryop.src2 = r1.reg; + bytecode << op; + + result.type = QMetaType::QReal; + result.reg = op.binaryop.output; + + return true; +} + +bool QDeclarativeBindingCompilerPrivate::buildName(QStringList &name, + QDeclarativeJS::AST::Node *node, + QList<QDeclarativeJS::AST::ExpressionNode *> *nodes) +{ + if (node->kind == AST::Node::Kind_IdentifierExpression) { + name << static_cast<AST::IdentifierExpression*>(node)->name->asString(); + if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node); + } else if (node->kind == AST::Node::Kind_FieldMemberExpression) { + AST::FieldMemberExpression *expr = + static_cast<AST::FieldMemberExpression *>(node); + + if (!buildName(name, expr->base, nodes)) + return false; + + name << expr->name->asString(); + if (nodes) *nodes << expr; + } else { + return false; + } + + return true; +} + +bool QDeclarativeBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo, int reg, + int idx, const QStringList &subName, + QDeclarativeJS::AST::ExpressionNode *node) +{ + QMetaProperty prop = mo->property(idx); + rv.metaObject = 0; + rv.type = 0; + + //XXX binding optimizer doesn't handle properties with a revision + if (prop.revision() > 0) + return false; + + int fastFetchIndex = fastProperties()->accessorIndexForProperty(mo, idx); + + Instr fetch; + + if (!qmlDisableFastProperties() && fastFetchIndex != -1) { + fetch.common.type = Instr::FetchAndSubscribe; + fetch.fetchAndSubscribe.objectReg = reg; + fetch.fetchAndSubscribe.output = reg; + fetch.fetchAndSubscribe.function = fastFetchIndex; + fetch.fetchAndSubscribe.subscription = subscriptionIndex(subName); + fetch.fetchAndSubscribe.exceptionId = exceptionId(node); + } else { + if (subscription(subName, &rv) && prop.hasNotifySignal() && prop.notifySignalIndex() != -1) { + Instr sub; + sub.common.type = Instr::Subscribe; + sub.subscribe.offset = subscriptionIndex(subName); + sub.subscribe.reg = reg; + sub.subscribe.index = prop.notifySignalIndex(); + bytecode << sub; + } + + fetch.common.type = Instr::Fetch; + fetch.fetch.objectReg = reg; + fetch.fetch.index = idx; + fetch.fetch.output = reg; + fetch.fetch.exceptionId = exceptionId(node); + } + + rv.type = prop.userType(); + rv.metaObject = engine->metaObjectForType(rv.type); + rv.reg = reg; + + if (rv.type == QMetaType::QString) { + int tmp = acquireReg(); + if (tmp == -1) + return false; + Instr copy; + copy.common.type = Instr::Copy; + copy.copy.reg = tmp; + copy.copy.src = reg; + bytecode << copy; + releaseReg(tmp); + fetch.fetch.objectReg = tmp; + + Instr setup; + setup.common.type = Instr::NewString; + setup.construct.reg = reg; + bytecode << setup; + registerCleanup(reg, Instr::CleanupString); + } + + bytecode << fetch; + + if (!rv.metaObject && + rv.type != QMetaType::QReal && + rv.type != QMetaType::Int && + rv.type != QMetaType::Bool && + rv.type != qMetaTypeId<QDeclarativeAnchorLine>() && + rv.type != QMetaType::QString) { + rv.metaObject = 0; + rv.type = 0; + return false; // Unsupported type (string not supported yet); + } + + return true; +} + +void QDeclarativeBindingCompilerPrivate::registerCleanup(int reg, int cleanup, int cleanupType) +{ + registerCleanups.insert(reg, qMakePair(cleanup, cleanupType)); +} + +int QDeclarativeBindingCompilerPrivate::acquireReg(int cleanup, int cleanupType) +{ + for (int ii = 0; ii < 32; ++ii) { + if (!(registers & (1 << ii))) { + registers |= (1 << ii); + + if (cleanup != Instr::Noop) + registerCleanup(ii, cleanup, cleanupType); + + return ii; + } + } + return -1; +} + +void QDeclarativeBindingCompilerPrivate::releaseReg(int reg) +{ + Q_ASSERT(reg >= 0 && reg <= 31); + + if (registerCleanups.contains(reg)) { + QPair<int, int> c = registerCleanups[reg]; + registerCleanups.remove(reg); + Instr cleanup; + cleanup.common.type = (quint8)c.first; + cleanup.cleanup.reg = reg; + bytecode << cleanup; + } + + quint32 mask = 1 << reg; + registers &= ~mask; +} + +// Returns a reg +int QDeclarativeBindingCompilerPrivate::registerLiteralString(const QString &str) +{ + QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar)); + int offset = data.count(); + data += strdata; + + int reg = acquireReg(Instr::CleanupString); + if (reg == -1) + return false; + + Instr string; + string.common.type = Instr::String; + string.string_value.reg = reg; + string.string_value.offset = offset; + string.string_value.length = str.length(); + bytecode << string; + + return reg; +} + +// Returns an identifier offset +int QDeclarativeBindingCompilerPrivate::registerString(const QString &string) +{ + Q_ASSERT(!string.isEmpty()); + + QHash<QString, QPair<int, int> >::ConstIterator iter = registeredStrings.find(string); + + if (iter == registeredStrings.end()) { + quint32 len = string.length(); + QByteArray lendata((const char *)&len, sizeof(quint32)); + QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar)); + strdata.prepend(lendata); + int rv = data.count(); + data += strdata; + + iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv)); + } + + Instr reg; + reg.common.type = Instr::InitString; + reg.initstring.offset = iter->first; + reg.initstring.dataIdx = iter->second; + bytecode << reg; + return reg.initstring.offset; +} + +bool QDeclarativeBindingCompilerPrivate::subscription(const QStringList &sub, Result *result) +{ + QString str = sub.join(QLatin1String(".")); + result->subscriptionSet.insert(str); + + if (subscriptionSet.contains(str)) { + return false; + } else { + subscriptionSet.insert(str); + return true; + } +} + +int QDeclarativeBindingCompilerPrivate::subscriptionIndex(const QStringList &sub) +{ + QString str = sub.join(QLatin1String(".")); + QHash<QString, int>::ConstIterator iter = subscriptionIds.find(str); + if (iter == subscriptionIds.end()) + iter = subscriptionIds.insert(str, subscriptionIds.count()); + usedSubscriptionIds.insert(*iter); + return *iter; +} + +/* + Returns true if lhs contains no subscriptions that aren't also in base or rhs AND + rhs contains no subscriptions that aren't also in base or lhs. +*/ +bool QDeclarativeBindingCompilerPrivate::subscriptionNeutral(const QSet<QString> &base, + const QSet<QString> &lhs, + const QSet<QString> &rhs) +{ + QSet<QString> difflhs = lhs; + difflhs.subtract(rhs); + QSet<QString> diffrhs = rhs; + diffrhs.subtract(lhs); + + difflhs.unite(diffrhs); + difflhs.subtract(base); + + return difflhs.isEmpty(); +} + +quint8 QDeclarativeBindingCompilerPrivate::exceptionId(QDeclarativeJS::AST::ExpressionNode *n) +{ + quint8 rv = 0xFF; + if (n && exceptions.count() < 0xFF) { + rv = (quint8)exceptions.count(); + QDeclarativeJS::AST::SourceLocation l = n->firstSourceLocation(); + quint64 e = l.startLine; + e <<= 32; + e |= l.startColumn; + exceptions.append(e); + } + return rv; +} + +QDeclarativeBindingCompiler::QDeclarativeBindingCompiler() +: d(new QDeclarativeBindingCompilerPrivate) +{ +} + +QDeclarativeBindingCompiler::~QDeclarativeBindingCompiler() +{ + delete d; d = 0; +} + +/* +Returns true if any bindings were compiled. +*/ +bool QDeclarativeBindingCompiler::isValid() const +{ + return !d->committed.bytecode.isEmpty(); +} + +/* +-1 on failure, otherwise the binding index to use. +*/ +int QDeclarativeBindingCompiler::compile(const Expression &expression, QDeclarativeEnginePrivate *engine) +{ + if (!expression.expression.asAST()) return false; + + if (!qmlExperimental() && expression.property->isValueTypeSubProperty) + return -1; + + if (qmlDisableOptimizer()) + return -1; + + d->context = expression.context; + d->component = expression.component; + d->destination = expression.property; + d->ids = expression.ids; + d->imports = expression.imports; + d->engine = engine; + + if (d->compile(expression.expression.asAST())) { + return d->commitCompile(); + } else { + return -1; + } +} + + +QByteArray QDeclarativeBindingCompilerPrivate::buildSignalTable() const +{ + QHash<int, QList<int> > table; + + for (int ii = 0; ii < committed.count(); ++ii) { + const QSet<int> &deps = committed.dependencies.at(ii); + for (QSet<int>::ConstIterator iter = deps.begin(); iter != deps.end(); ++iter) + table[*iter].append(ii); + } + + QVector<quint32> header; + QVector<quint32> data; + for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) { + header.append(committed.subscriptionIds.count() + data.count()); + const QList<int> &bindings = table[ii]; + data.append(bindings.count()); + for (int jj = 0; jj < bindings.count(); ++jj) + data.append(bindings.at(jj)); + } + header << data; + + return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32)); +} + +QByteArray QDeclarativeBindingCompilerPrivate::buildExceptionData() const +{ + QByteArray rv; + rv.resize(committed.exceptions.count() * sizeof(quint64)); + ::memcpy(rv.data(), committed.exceptions.constData(), rv.size()); + return rv; +} + +/* +Returns the compiled program. +*/ +QByteArray QDeclarativeBindingCompiler::program() const +{ + QByteArray programData; + + if (isValid()) { + Program prog; + prog.bindings = d->committed.count(); + + QVector<Instr> bytecode; + Instr skip; + skip.common.type = Instr::Skip; + skip.skip.reg = -1; + for (int ii = 0; ii < d->committed.count(); ++ii) { + skip.skip.count = d->committed.count() - ii - 1; + skip.skip.count+= d->committed.offsets.at(ii); + bytecode << skip; + } + bytecode << d->committed.bytecode; + + QByteArray data = d->committed.data; + while (data.count() % 4) data.append('\0'); + prog.signalTableOffset = data.count(); + data += d->buildSignalTable(); + while (data.count() % 4) data.append('\0'); + prog.exceptionDataOffset = data.count(); + data += d->buildExceptionData(); + + prog.dataLength = 4 * ((data.size() + 3) / 4); + prog.subscriptions = d->committed.subscriptionIds.count(); + prog.identifiers = d->committed.registeredStrings.count(); + prog.instructionCount = bytecode.count(); + prog.compiled = false; + int size = sizeof(Program) + bytecode.count() * sizeof(Instr); + size += prog.dataLength; + + programData.resize(size); + memcpy(programData.data(), &prog, sizeof(Program)); + if (prog.dataLength) + memcpy((char *)((Program *)programData.data())->data(), data.constData(), + data.size()); + memcpy((char *)((Program *)programData.data())->instructions(), bytecode.constData(), + bytecode.count() * sizeof(Instr)); + } + + return programData; +} + + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecompiledbindings_p.h b/src/declarative/qml/qdeclarativecompiledbindings_p.h new file mode 100644 index 00000000..bc954c7c --- /dev/null +++ b/src/declarative/qml/qdeclarativecompiledbindings_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEBINDINGOPTIMIZATIONS_P_H +#define QDECLARATIVEBINDINGOPTIMIZATIONS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativeexpression_p.h" +#include "private/qdeclarativebinding_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +struct QDeclarativeBindingCompilerPrivate; +class QDeclarativeBindingCompiler +{ +public: + QDeclarativeBindingCompiler(); + ~QDeclarativeBindingCompiler(); + + // Returns true if bindings were compiled + bool isValid() const; + + struct Expression + { + QDeclarativeParser::Object *component; + QDeclarativeParser::Object *context; + QDeclarativeParser::Property *property; + QDeclarativeParser::Variant expression; + QHash<QString, QDeclarativeParser::Object *> ids; + QDeclarativeImports imports; + }; + + // -1 on failure, otherwise the binding index to use + int compile(const Expression &, QDeclarativeEnginePrivate *); + + // Returns the compiled program + QByteArray program() const; + + static void dump(const QByteArray &); +private: + QDeclarativeBindingCompilerPrivate *d; +}; + +class QDeclarativeCompiledBindingsPrivate; +class QDeclarativeCompiledBindings : public QObject, public QDeclarativeAbstractExpression, public QDeclarativeRefCount +{ +public: + QDeclarativeCompiledBindings(const char *program, QDeclarativeContextData *context, QDeclarativeRefCount *); + virtual ~QDeclarativeCompiledBindings(); + + QDeclarativeAbstractBinding *configBinding(int index, QObject *target, QObject *scope, int property); + +protected: + int qt_metacall(QMetaObject::Call, int, void **); + +private: + Q_DISABLE_COPY(QDeclarativeCompiledBindings) + Q_DECLARE_PRIVATE(QDeclarativeCompiledBindings) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEBINDINGOPTIMIZATIONS_P_H + diff --git a/src/declarative/qml/qdeclarativecompileddata.cpp b/src/declarative/qml/qdeclarativecompileddata.cpp new file mode 100644 index 00000000..81d809bf --- /dev/null +++ b/src/declarative/qml/qdeclarativecompileddata.cpp @@ -0,0 +1,255 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativecompiler_p.h" +#include "qdeclarativeengine.h" +#include "qdeclarativecomponent.h" +#include "private/qdeclarativecomponent_p.h" +#include "qdeclarativecontext.h" +#include "private/qdeclarativecontext_p.h" + +#include <QtCore/qdebug.h> + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +int QDeclarativeCompiledData::pack(const char *data, size_t size) +{ + const char *p = packData.constData(); + unsigned int ps = packData.size(); + + for (unsigned int ii = 0; (ii + size) <= ps; ii += sizeof(int)) { + if (0 == ::memcmp(p + ii, data, size)) + return ii; + } + + int rv = packData.size(); + packData.append(data, size); + return rv; +} + +int QDeclarativeCompiledData::indexForString(const QString &data) +{ + int idx = primitives.indexOf(data); + if (idx == -1) { + idx = primitives.count(); + primitives << data; + } + return idx; +} + +int QDeclarativeCompiledData::indexForByteArray(const QByteArray &data) +{ + int idx = datas.indexOf(data); + if (idx == -1) { + idx = datas.count(); + datas << data; + } + return idx; +} + +int QDeclarativeCompiledData::indexForUrl(const QUrl &data) +{ + int idx = urls.indexOf(data); + if (idx == -1) { + idx = urls.count(); + urls << data; + } + return idx; +} + +int QDeclarativeCompiledData::indexForFloat(float *data, int count) +{ + Q_ASSERT(count > 0); + + for (int ii = 0; ii <= floatData.count() - count; ++ii) { + bool found = true; + for (int jj = 0; jj < count; ++jj) { + if (floatData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if (found) + return ii; + } + + int idx = floatData.count(); + for (int ii = 0; ii < count; ++ii) + floatData << data[ii]; + + return idx; +} + +int QDeclarativeCompiledData::indexForInt(int *data, int count) +{ + Q_ASSERT(count > 0); + + for (int ii = 0; ii <= intData.count() - count; ++ii) { + bool found = true; + for (int jj = 0; jj < count; ++jj) { + if (intData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if (found) + return ii; + } + + int idx = intData.count(); + for (int ii = 0; ii < count; ++ii) + intData << data[ii]; + + return idx; +} + +int QDeclarativeCompiledData::indexForLocation(const QDeclarativeParser::Location &l) +{ + // ### FIXME + int rv = locations.count(); + locations << l; + return rv; +} + +int QDeclarativeCompiledData::indexForLocation(const QDeclarativeParser::LocationSpan &l) +{ + // ### FIXME + int rv = locations.count(); + locations << l.start << l.end; + return rv; +} + +QDeclarativeCompiledData::QDeclarativeCompiledData(QDeclarativeEngine *engine) +: QDeclarativeCleanup(engine), importCache(0), root(0), rootPropertyCache(0) +{ +} + +QDeclarativeCompiledData::~QDeclarativeCompiledData() +{ + for (int ii = 0; ii < types.count(); ++ii) { + if (types.at(ii).component) + types.at(ii).component->release(); + if (types.at(ii).typePropertyCache) + types.at(ii).typePropertyCache->release(); + } + + for (int ii = 0; ii < propertyCaches.count(); ++ii) + propertyCaches.at(ii)->release(); + + for (int ii = 0; ii < contextCaches.count(); ++ii) + contextCaches.at(ii)->release(); + + if (importCache) + importCache->release(); + + if (rootPropertyCache) + rootPropertyCache->release(); + + qDeleteAll(cachedPrograms); + qDeleteAll(cachedClosures); +} + +void QDeclarativeCompiledData::clear() +{ + qDeleteAll(cachedPrograms); + qDeleteAll(cachedClosures); + for (int ii = 0; ii < cachedClosures.count(); ++ii) + cachedClosures[ii] = 0; + for (int ii = 0; ii < cachedPrograms.count(); ++ii) + cachedPrograms[ii] = 0; +} + +const QMetaObject *QDeclarativeCompiledData::TypeReference::metaObject() const +{ + if (type) { + return type->metaObject(); + } else { + Q_ASSERT(component); + return component->root; + } +} + +/*! +Returns the property cache, if one alread exists. The cache is not referenced. +*/ +QDeclarativePropertyCache *QDeclarativeCompiledData::TypeReference::propertyCache() const +{ + if (type) + return typePropertyCache; + else + return component->rootPropertyCache; +} + +/*! +Returns the property cache, creating one if it doesn't already exist. The cache is not referenced. +*/ +QDeclarativePropertyCache *QDeclarativeCompiledData::TypeReference::createPropertyCache(QDeclarativeEngine *engine) +{ + if (typePropertyCache) { + return typePropertyCache; + } else if (type) { + typePropertyCache = QDeclarativeEnginePrivate::get(engine)->cache(type->metaObject()); + typePropertyCache->addref(); + return typePropertyCache; + } else { + return component->rootPropertyCache; + } +} + + +void QDeclarativeCompiledData::dumpInstructions() +{ + if (!name.isEmpty()) + qWarning() << name; + qWarning().nospace() << "Index\tLine\tOperation\t\tData1\tData2\tData3\tComments"; + qWarning().nospace() << "-------------------------------------------------------------------------------"; + for (int ii = 0; ii < bytecode.count(); ++ii) { + dump(&bytecode[ii], ii); + } + qWarning().nospace() << "-------------------------------------------------------------------------------"; +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp new file mode 100644 index 00000000..25e67ce5 --- /dev/null +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -0,0 +1,3129 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativecompiler_p.h" + +#include "private/qdeclarativeparser_p.h" +#include "private/qdeclarativescriptparser_p.h" +#include "qdeclarativepropertyvaluesource.h" +#include "qdeclarativecomponent.h" +#include "private/qmetaobjectbuilder_p.h" +#include "private/qdeclarativestringconverters_p.h" +#include "private/qdeclarativeengine_p.h" +#include "qdeclarativeengine.h" +#include "qdeclarativecontext.h" +#include "private/qdeclarativemetatype_p.h" +#include "private/qdeclarativecustomparser_p_p.h" +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativecomponent_p.h" +#include "parser/qdeclarativejsast_p.h" +#include "private/qdeclarativevmemetaobject_p.h" +#include "private/qdeclarativeexpression_p.h" +#include "private/qdeclarativeproperty_p.h" +#include "private/qdeclarativerewrite_p.h" +#include "qdeclarativescriptstring.h" +#include "private/qdeclarativeglobal_p.h" +#include "private/qdeclarativescriptparser_p.h" +#include "private/qdeclarativebinding_p.h" +#include "private/qdeclarativecompiledbindings_p.h" +#include "private/qdeclarativeglobalscriptclass_p.h" + +#include <QColor> +#include <QDebug> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <QAtomicInt> +#include <QtCore/qdebug.h> +#include <QtCore/qdatetime.h> + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); +DEFINE_BOOL_CONFIG_OPTION(compilerStatDump, QML_COMPILER_STATS); +DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP); + +using namespace QDeclarativeParser; + +/*! + Instantiate a new QDeclarativeCompiler. +*/ +QDeclarativeCompiler::QDeclarativeCompiler() +: output(0), engine(0), unitRoot(0), unit(0) +{ +} + +/*! + Returns true if the last call to compile() caused errors. + + \sa errors() +*/ +bool QDeclarativeCompiler::isError() const +{ + return !exceptions.isEmpty(); +} + +/*! + Return the list of errors from the last call to compile(), or an empty list + if there were no errors. +*/ +QList<QDeclarativeError> QDeclarativeCompiler::errors() const +{ + return exceptions; +} + +/*! + Returns true if \a name refers to an attached property, false otherwise. + + Attached property names are those that start with a capital letter. +*/ +bool QDeclarativeCompiler::isAttachedPropertyName(const QByteArray &name) +{ + return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z'; +} + +/*! + Returns true if \a name refers to a signal property, false otherwise. + + Signal property names are those that start with "on", followed by a capital + letter. +*/ +bool QDeclarativeCompiler::isSignalPropertyName(const QByteArray &name) +{ + return name.length() >= 3 && name.startsWith("on") && + 'A' <= name.at(2) && 'Z' >= name.at(2); +} + +/*! + \macro COMPILE_EXCEPTION + \internal + Inserts an error into the QDeclarativeCompiler error list, and returns false + (failure). + + \a token is used to source the error line and column, and \a desc is the + error itself. \a desc can be an expression that can be piped into QDebug. + + For example: + + \code + COMPILE_EXCEPTION(property, tr("Error for property \"%1\"").arg(QString::fromUtf8(property->name))); + \endcode +*/ +#define COMPILE_EXCEPTION(token, desc) \ + { \ + QString exceptionDescription; \ + QDeclarativeError error; \ + error.setUrl(output->url); \ + error.setLine((token)->location.start.line); \ + error.setColumn((token)->location.start.column); \ + error.setDescription(desc.trimmed()); \ + exceptions << error; \ + return false; \ + } + +/*! + \macro COMPILE_CHECK + \internal + Returns false if \a is false, otherwise does nothing. +*/ +#define COMPILE_CHECK(a) \ + { \ + if (!a) return false; \ + } + +/*! + Returns true if literal \a v can be assigned to property \a prop, otherwise + false. + + This test corresponds to action taken by genLiteralAssignment(). Any change + made here, must have a corresponding action in genLiteralAssigment(). +*/ +bool QDeclarativeCompiler::testLiteralAssignment(const QMetaProperty &prop, + QDeclarativeParser::Value *v) +{ + QString string = v->value.asString(); + + if (!prop.isWritable()) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name()))); + + if (prop.isEnumType()) { + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(string.toUtf8().constData()); + } else + value = prop.enumerator().keyToValue(string.toUtf8().constData()); + if (value == -1) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: unknown enumeration")); + return true; + } + int type = prop.userType(); + switch(type) { + case -1: + break; + case QVariant::String: + if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: string expected")); + break; + case QVariant::Url: + if (!v->value.isString()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: url expected")); + break; + case QVariant::UInt: + { + bool ok = v->value.isNumber(); + if (ok) { + double n = v->value.asNumber(); + if (double(uint(n)) != n) + ok = false; + } + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsigned int expected")); + } + break; + case QVariant::Int: + { + bool ok = v->value.isNumber(); + if (ok) { + double n = v->value.asNumber(); + if (double(int(n)) != n) + ok = false; + } + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: int expected")); + } + break; + case QMetaType::Float: + if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected")); + break; + case QVariant::Double: + if (!v->value.isNumber()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: number expected")); + break; + case QVariant::Color: + { + bool ok; + QDeclarativeStringConverters::colorFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: color expected")); + } + break; +#ifndef QT_NO_DATESTRING + case QVariant::Date: + { + bool ok; + QDeclarativeStringConverters::dateFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: date expected")); + } + break; + case QVariant::Time: + { + bool ok; + QDeclarativeStringConverters::timeFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: time expected")); + } + break; + case QVariant::DateTime: + { + bool ok; + QDeclarativeStringConverters::dateTimeFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: datetime expected")); + } + break; +#endif // QT_NO_DATESTRING + case QVariant::Point: + case QVariant::PointF: + { + bool ok; + QPointF point = QDeclarativeStringConverters::pointFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected")); + } + break; + case QVariant::Size: + case QVariant::SizeF: + { + bool ok; + QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected")); + } + break; + case QVariant::Rect: + case QVariant::RectF: + { + bool ok; + QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected")); + } + break; + case QVariant::Bool: + { + if (!v->value.isBoolean()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: boolean expected")); + } + break; + case QVariant::Vector3D: + { + bool ok; + QDeclarativeStringConverters::vector3DFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: 3D vector expected")); + } + break; + default: + { + int t = prop.userType(); + QDeclarativeMetaType::StringConverter converter = + QDeclarativeMetaType::customStringConverter(t); + if (!converter) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QVariant::typeToName(prop.type())))); + } + break; + } + return true; +} + +/*! + Generate a store instruction for assigning literal \a v to property \a prop. + + Any literal assignment that is approved in testLiteralAssignment() must have + a corresponding action in this method. +*/ +void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop, + QDeclarativeParser::Value *v) +{ + QString string = v->value.asString(); + + QDeclarativeInstruction instr; + instr.line = v->location.start.line; + if (prop.isEnumType()) { + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(string.toUtf8().constData()); + } else + value = prop.enumerator().keyToValue(string.toUtf8().constData()); + + instr.type = QDeclarativeInstruction::StoreInteger; + instr.storeInteger.propertyIndex = prop.propertyIndex(); + instr.storeInteger.value = value; + output->bytecode << instr; + return; + } + + int type = prop.userType(); + switch(type) { + case -1: + { + if (v->value.isNumber()) { + double n = v->value.asNumber(); + if (double(int(n)) == n) { + instr.type = QDeclarativeInstruction::StoreVariantInteger; + instr.storeInteger.propertyIndex = prop.propertyIndex(); + instr.storeInteger.value = int(n); + } else { + instr.type = QDeclarativeInstruction::StoreVariantDouble; + instr.storeDouble.propertyIndex = prop.propertyIndex(); + instr.storeDouble.value = n; + } + } else if(v->value.isBoolean()) { + instr.type = QDeclarativeInstruction::StoreVariantBool; + instr.storeBool.propertyIndex = prop.propertyIndex(); + instr.storeBool.value = v->value.asBoolean(); + } else { + instr.type = QDeclarativeInstruction::StoreVariant; + instr.storeString.propertyIndex = prop.propertyIndex(); + instr.storeString.value = output->indexForString(string); + } + } + break; + case QVariant::String: + { + instr.type = QDeclarativeInstruction::StoreString; + instr.storeString.propertyIndex = prop.propertyIndex(); + instr.storeString.value = output->indexForString(string); + } + break; + case QVariant::Url: + { + instr.type = QDeclarativeInstruction::StoreUrl; + QUrl u = string.isEmpty() ? QUrl() : output->url.resolved(QUrl(string)); + instr.storeUrl.propertyIndex = prop.propertyIndex(); + instr.storeUrl.value = output->indexForUrl(u); + } + break; + case QVariant::UInt: + { + instr.type = QDeclarativeInstruction::StoreInteger; + instr.storeInteger.propertyIndex = prop.propertyIndex(); + instr.storeInteger.value = uint(v->value.asNumber()); + } + break; + case QVariant::Int: + { + instr.type = QDeclarativeInstruction::StoreInteger; + instr.storeInteger.propertyIndex = prop.propertyIndex(); + instr.storeInteger.value = int(v->value.asNumber()); + } + break; + case QMetaType::Float: + { + instr.type = QDeclarativeInstruction::StoreFloat; + instr.storeFloat.propertyIndex = prop.propertyIndex(); + instr.storeFloat.value = float(v->value.asNumber()); + } + break; + case QVariant::Double: + { + instr.type = QDeclarativeInstruction::StoreDouble; + instr.storeDouble.propertyIndex = prop.propertyIndex(); + instr.storeDouble.value = v->value.asNumber(); + } + break; + case QVariant::Color: + { + QColor c = QDeclarativeStringConverters::colorFromString(string); + instr.type = QDeclarativeInstruction::StoreColor; + instr.storeColor.propertyIndex = prop.propertyIndex(); + instr.storeColor.value = c.rgba(); + } + break; +#ifndef QT_NO_DATESTRING + case QVariant::Date: + { + QDate d = QDeclarativeStringConverters::dateFromString(string); + instr.type = QDeclarativeInstruction::StoreDate; + instr.storeDate.propertyIndex = prop.propertyIndex(); + instr.storeDate.value = d.toJulianDay(); + } + break; + case QVariant::Time: + { + QTime time = QDeclarativeStringConverters::timeFromString(string); + int data[] = { time.hour(), time.minute(), + time.second(), time.msec() }; + int index = output->indexForInt(data, 4); + instr.type = QDeclarativeInstruction::StoreTime; + instr.storeTime.propertyIndex = prop.propertyIndex(); + instr.storeTime.valueIndex = index; + } + break; + case QVariant::DateTime: + { + QDateTime dateTime = QDeclarativeStringConverters::dateTimeFromString(string); + int data[] = { dateTime.date().toJulianDay(), + dateTime.time().hour(), + dateTime.time().minute(), + dateTime.time().second(), + dateTime.time().msec() }; + int index = output->indexForInt(data, 5); + instr.type = QDeclarativeInstruction::StoreDateTime; + instr.storeDateTime.propertyIndex = prop.propertyIndex(); + instr.storeDateTime.valueIndex = index; + } + break; +#endif // QT_NO_DATESTRING + case QVariant::Point: + case QVariant::PointF: + { + bool ok; + QPointF point = + QDeclarativeStringConverters::pointFFromString(string, &ok); + float data[] = { float(point.x()), float(point.y()) }; + int index = output->indexForFloat(data, 2); + if (type == QVariant::PointF) + instr.type = QDeclarativeInstruction::StorePointF; + else + instr.type = QDeclarativeInstruction::StorePoint; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; + } + break; + case QVariant::Size: + case QVariant::SizeF: + { + bool ok; + QSizeF size = QDeclarativeStringConverters::sizeFFromString(string, &ok); + float data[] = { float(size.width()), float(size.height()) }; + int index = output->indexForFloat(data, 2); + if (type == QVariant::SizeF) + instr.type = QDeclarativeInstruction::StoreSizeF; + else + instr.type = QDeclarativeInstruction::StoreSize; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; + } + break; + case QVariant::Rect: + case QVariant::RectF: + { + bool ok; + QRectF rect = QDeclarativeStringConverters::rectFFromString(string, &ok); + float data[] = { float(rect.x()), float(rect.y()), + float(rect.width()), float(rect.height()) }; + int index = output->indexForFloat(data, 4); + if (type == QVariant::RectF) + instr.type = QDeclarativeInstruction::StoreRectF; + else + instr.type = QDeclarativeInstruction::StoreRect; + instr.storeRect.propertyIndex = prop.propertyIndex(); + instr.storeRect.valueIndex = index; + } + break; + case QVariant::Bool: + { + bool b = v->value.asBoolean(); + instr.type = QDeclarativeInstruction::StoreBool; + instr.storeBool.propertyIndex = prop.propertyIndex(); + instr.storeBool.value = b; + } + break; + case QVariant::Vector3D: + { + bool ok; + QVector3D vector = + QDeclarativeStringConverters::vector3DFromString(string, &ok); + float data[] = { float(vector.x()), float(vector.y()), float(vector.z()) }; + int index = output->indexForFloat(data, 3); + instr.type = QDeclarativeInstruction::StoreVector3D; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; + } + break; + default: + { + int t = prop.userType(); + int index = output->customTypeData.count(); + instr.type = QDeclarativeInstruction::AssignCustomType; + instr.assignCustomType.propertyIndex = prop.propertyIndex(); + instr.assignCustomType.valueIndex = index; + + QDeclarativeCompiledData::CustomTypeData data; + data.index = output->indexForString(string); + data.type = t; + output->customTypeData << data; + } + break; + } + output->bytecode << instr; +} + +/*! + Resets data by clearing the lists that the QDeclarativeCompiler modifies. +*/ +void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data) +{ + data->types.clear(); + data->primitives.clear(); + data->floatData.clear(); + data->intData.clear(); + data->customTypeData.clear(); + data->datas.clear(); + data->bytecode.clear(); +} + +/*! + Compile \a unit, and store the output in \a out. \a engine is the QDeclarativeEngine + with which the QDeclarativeCompiledData will be associated. + + Returns true on success, false on failure. On failure, the compile errors + are available from errors(). + + If the environment variant QML_COMPILER_DUMP is set + (eg. QML_COMPILER_DUMP=1) the compiled instructions will be dumped to stderr + on a successful compiler. +*/ +bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine, + QDeclarativeTypeData *unit, + QDeclarativeCompiledData *out) +{ + exceptions.clear(); + + Q_ASSERT(out); + reset(out); + + output = out; + + // Compile types + const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes(); + QList<QDeclarativeScriptParser::TypeReference *> referencedTypes = unit->parser().referencedTypes(); + + for (int ii = 0; ii < resolvedTypes.count(); ++ii) { + QDeclarativeCompiledData::TypeReference ref; + + const QDeclarativeTypeData::TypeReference &tref = resolvedTypes.at(ii); + QDeclarativeScriptParser::TypeReference *parserRef = referencedTypes.at(ii); + + if (tref.type) { + ref.type = tref.type; + if (!ref.type->isCreatable()) { + QString err = ref.type->noCreationReason(); + if (err.isEmpty()) + err = tr( "Element is not creatable."); + COMPILE_EXCEPTION(parserRef->refObjects.first(), err); + } + + if (ref.type->containsRevisionedAttributes()) { + QDeclarativeError cacheError; + ref.typePropertyCache = + QDeclarativeEnginePrivate::get(engine)->cache(ref.type, resolvedTypes.at(ii).minorVersion, cacheError); + + if (!ref.typePropertyCache) { + COMPILE_EXCEPTION(parserRef->refObjects.first(), cacheError.description()); + } + ref.typePropertyCache->addref(); + } + + } else if (tref.typeData) { + ref.component = tref.typeData->compiledData(); + } + ref.className = parserRef->name.toUtf8(); + out->types << ref; + } + + QDeclarativeParser::Object *root = unit->parser().tree(); + Q_ASSERT(root); + + this->engine = engine; + this->enginePrivate = QDeclarativeEnginePrivate::get(engine); + this->unit = unit; + this->unitRoot = root; + compileTree(root); + + if (!isError()) { + if (compilerDump()) + out->dumpInstructions(); + if (compilerStatDump()) + dumpStats(); + Q_ASSERT(out->rootPropertyCache); + } else { + reset(out); + } + + compileState = ComponentCompileState(); + savedCompileStates.clear(); + output = 0; + this->engine = 0; + this->enginePrivate = 0; + this->unit = 0; + this->unitRoot = 0; + + return !isError(); +} + +void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree) +{ + compileState.root = tree; + componentStat.lineNumber = tree->location.start.line; + + if (!buildObject(tree, BindingContext()) || !completeComponentBuild()) + return; + + QDeclarativeInstruction init; + init.type = QDeclarativeInstruction::Init; + init.line = 0; + init.init.bindingsSize = compileState.bindings.count(); + init.init.parserStatusSize = compileState.parserStatusCount; + init.init.contextCache = genContextCache(); + if (compileState.compiledBindingData.isEmpty()) + init.init.compiledBinding = -1; + else + init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); + output->bytecode << init; + + // Build global import scripts + QHash<QString, Object::ScriptBlock> importedScripts; + QStringList importedScriptIndexes; + + foreach (const QDeclarativeTypeData::ScriptReference &script, unit->resolvedScripts()) { + QString scriptCode = script.script->scriptSource(); + Object::ScriptBlock::Pragmas pragmas = script.script->pragmas(); + + Q_ASSERT(!importedScripts.contains(script.qualifier)); + + if (!scriptCode.isEmpty()) { + Object::ScriptBlock &scriptBlock = importedScripts[script.qualifier]; + + scriptBlock.code = scriptCode; + scriptBlock.file = script.script->finalUrl().toString(); + scriptBlock.pragmas = pragmas; + } + } + + for (QHash<QString, Object::ScriptBlock>::Iterator iter = importedScripts.begin(); + iter != importedScripts.end(); ++iter) { + + importedScriptIndexes.append(iter.key()); + + QDeclarativeInstruction import; + import.type = QDeclarativeInstruction::StoreImportedScript; + import.line = 0; + import.storeScript.value = output->scripts.count(); + output->scripts << *iter; + output->bytecode << import; + } + + genObject(tree); + + QDeclarativeInstruction def; + init.line = 0; + def.type = QDeclarativeInstruction::SetDefault; + output->bytecode << def; + + output->importCache = new QDeclarativeTypeNameCache(engine); + + for (int ii = 0; ii < importedScriptIndexes.count(); ++ii) + output->importCache->add(importedScriptIndexes.at(ii), ii); + + unit->imports().populateCache(output->importCache, engine); + + Q_ASSERT(tree->metatype); + + if (tree->metadata.isEmpty()) { + output->root = tree->metatype; + } else { + static_cast<QMetaObject &>(output->rootData) = *tree->metaObject(); + output->root = &output->rootData; + } + if (!tree->metadata.isEmpty()) + enginePrivate->registerCompositeType(output); +} + +static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2) +{ + return t1->location.start.line < t2->location.start.line || + (t1->location.start.line == t2->location.start.line && + t1->location.start.column < t2->location.start.column); +} + +bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt) +{ + componentStat.objects++; + + Q_ASSERT (obj->type != -1); + const QDeclarativeCompiledData::TypeReference &tr = + output->types.at(obj->type); + obj->metatype = tr.metaObject(); + + if (tr.component) + obj->url = tr.component->url; + if (tr.type) + obj->typeName = tr.type->qmlTypeName(); + obj->className = tr.className; + + // This object is a "Component" element + if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) { + COMPILE_CHECK(buildComponent(obj, ctxt)); + return true; + } + + // Object instantiations reset the binding context + BindingContext objCtxt(obj); + + // Create the synthesized meta object, ignoring aliases + COMPILE_CHECK(checkDynamicMeta(obj)); + COMPILE_CHECK(mergeDynamicMetaProperties(obj)); + COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases)); + + // Find the native type and check for the QDeclarativeParserStatus interface + QDeclarativeType *type = toQmlType(obj); + Q_ASSERT(type); + obj->parserStatusCast = type->parserStatusCast(); + if (obj->parserStatusCast != -1) + compileState.parserStatusCount++; + + // Check if this is a custom parser type. Custom parser types allow + // assignments to non-existent properties. These assignments are then + // compiled by the type. + bool isCustomParser = output->types.at(obj->type).type && + output->types.at(obj->type).type->customParser() != 0; + QList<QDeclarativeCustomParserProperty> customProps; + + // Fetch the list of deferred properties + QStringList deferredList = deferredProperties(obj); + + // Must do id property first. This is to ensure that the id given to any + // id reference created matches the order in which the objects are + // instantiated + foreach(Property *prop, obj->properties) { + if (prop->name == "id") { + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + break; + } + } + + // Merge + Property *defaultProperty = 0; + Property *skipProperty = 0; + if (obj->defaultProperty) { + const QMetaObject *metaObject = obj->metaObject(); + Q_ASSERT(metaObject); + QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject); + if (p.name()) { + Property *explicitProperty = obj->getProperty(p.name(), false); + if (explicitProperty && !explicitProperty->value) { + skipProperty = explicitProperty; + + defaultProperty = new Property; + defaultProperty->parent = obj; + defaultProperty->isDefault = true; + defaultProperty->location = obj->defaultProperty->location; + defaultProperty->listValueRange = obj->defaultProperty->listValueRange; + defaultProperty->listCommaPositions = obj->defaultProperty->listCommaPositions; + + defaultProperty->values = obj->defaultProperty->values; + defaultProperty->values += explicitProperty->values; + foreach(QDeclarativeParser::Value *value, defaultProperty->values) + value->addref(); + qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan); + + } else { + defaultProperty = obj->defaultProperty; + defaultProperty->addref(); + } + } else { + defaultProperty = obj->defaultProperty; + defaultProperty->addref(); + } + } + + QDeclarativeCustomParser *cp = 0; + if (isCustomParser) + cp = output->types.at(obj->type).type->customParser(); + + // Build all explicit properties specified + foreach(Property *prop, obj->properties) { + + if (prop == skipProperty) + continue; + if (prop->name == "id") + continue; + + bool canDefer = false; + if (isCustomParser) { + if (doesPropertyExist(prop, obj) && + (!(cp->flags() & QDeclarativeCustomParser::AcceptsAttachedProperties) || + !isAttachedPropertyName(prop->name))) { + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); + } else { + customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop); + } + } else { + if (isSignalPropertyName(prop->name)) { + COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); + } else { + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); + } + } + + if (canDefer && !deferredList.isEmpty() && + deferredList.contains(QString::fromUtf8(prop->name))) + prop->isDeferred = true; + + } + + // Build the default property + if (defaultProperty) { + Property *prop = defaultProperty; + + bool canDefer = false; + if (isCustomParser) { + if (doesPropertyExist(prop, obj)) { + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); + } else { + customProps << QDeclarativeCustomParserNodePrivate::fromProperty(prop); + } + } else { + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); + } + + if (canDefer && !deferredList.isEmpty() && + deferredList.contains(QString::fromUtf8(prop->name))) + prop->isDeferred = true; + } + + if (defaultProperty) + defaultProperty->release(); + + // Compile custom parser parts + if (isCustomParser && !customProps.isEmpty()) { + cp->clearErrors(); + cp->compiler = this; + cp->object = obj; + obj->custom = cp->compile(customProps); + cp->compiler = 0; + cp->object = 0; + foreach (QDeclarativeError err, cp->errors()) { + err.setUrl(output->url); + exceptions << err; + } + } + + return true; +} + +void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) +{ + QDeclarativeCompiledData::TypeReference &tr = output->types[obj->type]; + if (tr.type && obj->metatype == &QDeclarativeComponent::staticMetaObject) { + genComponent(obj); + return; + } + + // Create the object + if (obj->custom.isEmpty() && output->types.at(obj->type).type && + !output->types.at(obj->type).type->isExtendedType() && obj != compileState.root) { + + QDeclarativeInstruction create; + create.type = QDeclarativeInstruction::CreateSimpleObject; + create.line = obj->location.start.line; + create.createSimple.create = output->types.at(obj->type).type->createFunction(); + create.createSimple.typeSize = output->types.at(obj->type).type->createSize(); + create.createSimple.type = obj->type; + create.createSimple.column = obj->location.start.column; + output->bytecode << create; + + } else { + + QDeclarativeInstruction create; + create.type = QDeclarativeInstruction::CreateObject; + create.line = obj->location.start.line; + create.create.column = obj->location.start.column; + create.create.data = -1; + if (!obj->custom.isEmpty()) + create.create.data = output->indexForByteArray(obj->custom); + create.create.type = obj->type; + if (!output->types.at(create.create.type).type && + !obj->bindingBitmask.isEmpty()) { + Q_ASSERT(obj->bindingBitmask.size() % 4 == 0); + create.create.bindingBits = + output->indexForByteArray(obj->bindingBitmask); + } else { + create.create.bindingBits = -1; + } + output->bytecode << create; + + } + + // Setup the synthesized meta object if necessary + if (!obj->metadata.isEmpty()) { + QDeclarativeInstruction meta; + meta.type = QDeclarativeInstruction::StoreMetaObject; + meta.line = 0; + meta.storeMeta.data = output->indexForByteArray(obj->metadata); + meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); + meta.storeMeta.propertyCache = output->propertyCaches.count(); + + QDeclarativePropertyCache *propertyCache = obj->synthCache; + Q_ASSERT(propertyCache); + propertyCache->addref(); + + // Add flag for alias properties + if (!obj->synthdata.isEmpty()) { + const QDeclarativeVMEMetaData *vmeMetaData = + reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData()); + for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) { + int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii; + propertyCache->property(index)->flags |= QDeclarativePropertyCache::Data::IsAlias; + } + } + + if (obj == unitRoot) { + propertyCache->addref(); + output->rootPropertyCache = propertyCache; + } + + output->propertyCaches << propertyCache; + output->bytecode << meta; + } else if (obj == unitRoot) { + output->rootPropertyCache = tr.createPropertyCache(engine); + output->rootPropertyCache->addref(); + } + + // Set the object id + if (!obj->id.isEmpty()) { + QDeclarativeInstruction id; + id.type = QDeclarativeInstruction::SetId; + id.line = 0; + id.setId.value = output->indexForString(obj->id); + id.setId.index = obj->idIndex; + output->bytecode << id; + } + + // Begin the class + if (tr.type && obj->parserStatusCast != -1) { + QDeclarativeInstruction begin; + begin.type = QDeclarativeInstruction::BeginObject; + begin.begin.castValue = obj->parserStatusCast; + begin.line = obj->location.start.line; + output->bytecode << begin; + } + + genObjectBody(obj); +} + +void QDeclarativeCompiler::genObjectBody(QDeclarativeParser::Object *obj) +{ + typedef QPair<Property *, int> PropPair; + foreach(const PropPair &prop, obj->scriptStringProperties) { + QDeclarativeInstruction ss; + ss.type = QDeclarativeInstruction::StoreScriptString; + ss.storeScriptString.propertyIndex = prop.first->index; + ss.storeScriptString.value = + output->indexForString(prop.first->values.at(0)->value.asScript()); + ss.storeScriptString.scope = prop.second; + output->bytecode << ss; + } + + bool seenDefer = false; + foreach(Property *prop, obj->valueProperties) { + if (prop->isDeferred) { + seenDefer = true; + continue; + } + if (!prop->isAlias) + genValueProperty(prop, obj); + } + if (seenDefer) { + QDeclarativeInstruction defer; + defer.type = QDeclarativeInstruction::Defer; + defer.line = 0; + defer.defer.deferCount = 0; + int deferIdx = output->bytecode.count(); + output->bytecode << defer; + + QDeclarativeInstruction init; + init.type = QDeclarativeInstruction::Init; + init.init.bindingsSize = compileState.bindings.count(); // XXX - bigger than necessary + init.init.parserStatusSize = compileState.parserStatusCount; // XXX - bigger than necessary + init.init.contextCache = -1; + init.init.compiledBinding = -1; + output->bytecode << init; + + foreach(Property *prop, obj->valueProperties) { + if (!prop->isDeferred) + continue; + genValueProperty(prop, obj); + } + + output->bytecode[deferIdx].defer.deferCount = + output->bytecode.count() - deferIdx - 1; + } + + foreach(Property *prop, obj->signalProperties) { + + QDeclarativeParser::Value *v = prop->values.at(0); + + if (v->type == Value::SignalObject) { + + genObject(v->object); + + QDeclarativeInstruction assign; + assign.type = QDeclarativeInstruction::AssignSignalObject; + assign.line = v->location.start.line; + assign.assignSignalObject.signal = + output->indexForByteArray(prop->name); + output->bytecode << assign; + + } else if (v->type == Value::SignalExpression) { + + BindingContext ctxt = compileState.signalExpressions.value(v); + + QDeclarativeInstruction store; + store.type = QDeclarativeInstruction::StoreSignal; + store.line = v->location.start.line; + store.storeSignal.signalIndex = prop->index; + store.storeSignal.value = + output->indexForString(v->value.asScript().trimmed()); + store.storeSignal.context = ctxt.stack; + store.storeSignal.name = output->indexForByteArray(prop->name); + output->bytecode << store; + + } + + } + + foreach(Property *prop, obj->attachedProperties) { + QDeclarativeInstruction fetch; + fetch.type = QDeclarativeInstruction::FetchAttached; + fetch.line = prop->location.start.line; + fetch.fetchAttached.id = prop->index; + output->bytecode << fetch; + + genObjectBody(prop->value); + + QDeclarativeInstruction pop; + pop.type = QDeclarativeInstruction::PopFetchedObject; + pop.line = prop->location.start.line; + output->bytecode << pop; + } + + foreach(Property *prop, obj->groupedProperties) { + QDeclarativeInstruction fetch; + fetch.type = QDeclarativeInstruction::FetchObject; + fetch.fetch.property = prop->index; + fetch.line = prop->location.start.line; + output->bytecode << fetch; + + if (!prop->value->metadata.isEmpty()) { + QDeclarativeInstruction meta; + meta.type = QDeclarativeInstruction::StoreMetaObject; + meta.line = 0; + meta.storeMeta.data = output->indexForByteArray(prop->value->metadata); + meta.storeMeta.aliasData = output->indexForByteArray(prop->value->synthdata); + meta.storeMeta.propertyCache = -1; + output->bytecode << meta; + } + + genObjectBody(prop->value); + + QDeclarativeInstruction pop; + pop.type = QDeclarativeInstruction::PopFetchedObject; + pop.line = prop->location.start.line; + output->bytecode << pop; + } + + foreach(Property *prop, obj->valueTypeProperties) { + if (!prop->isAlias) + genValueTypeProperty(obj, prop); + } + + foreach(Property *prop, obj->valueProperties) { + if (prop->isDeferred) + continue; + if (prop->isAlias) + genValueProperty(prop, obj); + } + + foreach(Property *prop, obj->valueTypeProperties) { + if (prop->isAlias) + genValueTypeProperty(obj, prop); + } +} + +void QDeclarativeCompiler::genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *prop) +{ + QDeclarativeInstruction fetch; + fetch.type = QDeclarativeInstruction::FetchValueType; + fetch.fetchValue.property = prop->index; + fetch.fetchValue.type = prop->type; + fetch.fetchValue.bindingSkipList = 0; + fetch.line = prop->location.start.line; + + if (obj->type == -1 || output->types.at(obj->type).component) { + // We only have to do this if this is a composite type. If it is a builtin + // type it can't possibly already have bindings that need to be cleared. + foreach(Property *vprop, prop->value->valueProperties) { + if (!vprop->values.isEmpty()) { + Q_ASSERT(vprop->index >= 0 && vprop->index < 32); + fetch.fetchValue.bindingSkipList |= (1 << vprop->index); + } + } + } + + output->bytecode << fetch; + + foreach(Property *vprop, prop->value->valueProperties) { + genPropertyAssignment(vprop, prop->value, prop); + } + + QDeclarativeInstruction pop; + pop.type = QDeclarativeInstruction::PopValueType; + pop.fetchValue.property = prop->index; + pop.fetchValue.type = prop->type; + pop.fetchValue.bindingSkipList = 0; + pop.line = prop->location.start.line; + output->bytecode << pop; +} + +void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj) +{ + QDeclarativeParser::Object *root = obj->defaultProperty->values.at(0)->object; + Q_ASSERT(root); + + QDeclarativeInstruction create; + create.type = QDeclarativeInstruction::CreateComponent; + create.line = root->location.start.line; + create.createComponent.column = root->location.start.column; + create.createComponent.endLine = root->location.end.line; + output->bytecode << create; + int count = output->bytecode.count(); + + ComponentCompileState oldCompileState = compileState; + compileState = componentState(root); + + QDeclarativeInstruction init; + init.type = QDeclarativeInstruction::Init; + init.init.bindingsSize = compileState.bindings.count(); + init.init.parserStatusSize = compileState.parserStatusCount; + init.init.contextCache = genContextCache(); + if (compileState.compiledBindingData.isEmpty()) + init.init.compiledBinding = -1; + else + init.init.compiledBinding = output->indexForByteArray(compileState.compiledBindingData); + init.line = obj->location.start.line; + output->bytecode << init; + + genObject(root); + + QDeclarativeInstruction def; + init.line = 0; + def.type = QDeclarativeInstruction::SetDefault; + output->bytecode << def; + + output->bytecode[count - 1].createComponent.count = + output->bytecode.count() - count; + + compileState = oldCompileState; + + if (!obj->id.isEmpty()) { + QDeclarativeInstruction id; + id.type = QDeclarativeInstruction::SetId; + id.line = 0; + id.setId.value = output->indexForString(obj->id); + id.setId.index = obj->idIndex; + output->bytecode << id; + } + + if (obj == unitRoot) { + output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine); + output->rootPropertyCache->addref(); + } +} + +bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj, + const BindingContext &ctxt) +{ + // The special "Component" element can only have the id property and a + // default property, that actually defines the component's tree + + // Find, check and set the "id" property (if any) + Property *idProp = 0; + if (obj->properties.count() > 1 || + (obj->properties.count() == 1 && obj->properties.begin().key() != "id")) + COMPILE_EXCEPTION(*obj->properties.begin(), tr("Component elements may not contain properties other than id")); + + if (obj->properties.count()) + idProp = *obj->properties.begin(); + + if (idProp) { + if (idProp->value || idProp->values.count() > 1 || idProp->values.at(0)->object) + COMPILE_EXCEPTION(idProp, tr("Invalid component id specification")); + COMPILE_CHECK(checkValidId(idProp->values.first(), idProp->values.first()->primitive())) + + QString idVal = idProp->values.first()->primitive(); + + if (compileState.ids.contains(idVal)) + COMPILE_EXCEPTION(idProp, tr("id is not unique")); + + obj->id = idVal; + addId(idVal, obj); + } + + // Check the Component tree is well formed + if (obj->defaultProperty && + (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 || + (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object))) + COMPILE_EXCEPTION(obj, tr("Invalid component body specification")); + + if (!obj->dynamicProperties.isEmpty()) + COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties.")); + if (!obj->dynamicSignals.isEmpty()) + COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals.")); + if (!obj->dynamicSlots.isEmpty()) + COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions.")); + + QDeclarativeParser::Object *root = 0; + if (obj->defaultProperty && obj->defaultProperty->values.count()) + root = obj->defaultProperty->values.first()->object; + + if (!root) + COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification")); + + // Build the component tree + COMPILE_CHECK(buildComponentFromRoot(root, ctxt)); + + return true; +} + +bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *obj, + const BindingContext &ctxt) +{ + ComponentCompileState oldComponentCompileState = compileState; + ComponentStat oldComponentStat = componentStat; + + compileState = ComponentCompileState(); + compileState.root = obj; + + componentStat = ComponentStat(); + componentStat.lineNumber = obj->location.start.line; + + if (obj) + COMPILE_CHECK(buildObject(obj, ctxt)); + + COMPILE_CHECK(completeComponentBuild()); + + compileState = oldComponentCompileState; + componentStat = oldComponentStat; + + return true; +} + + +// Build a sub-object. A sub-object is one that was not created directly by +// QML - such as a grouped property object, or an attached object. Sub-object's +// can't have an id, involve a custom parser, have attached properties etc. +bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt) +{ + Q_ASSERT(obj->metatype); + Q_ASSERT(!obj->defaultProperty); + Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding + // sub-context + + foreach(Property *prop, obj->properties) { + if (isSignalPropertyName(prop->name)) { + COMPILE_CHECK(buildSignal(prop, obj, ctxt)); + } else { + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); + } + } + + return true; +} + +int QDeclarativeCompiler::componentTypeRef() +{ + QDeclarativeType *t = QDeclarativeMetaType::qmlType("QtQuick/Component",1,0); + for (int ii = output->types.count() - 1; ii >= 0; --ii) { + if (output->types.at(ii).type == t) + return ii; + } + QDeclarativeCompiledData::TypeReference ref; + ref.className = "Component"; + ref.type = t; + output->types << ref; + return output->types.count() - 1; +} + +bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(obj->metaObject()); + + QByteArray name = prop->name; + Q_ASSERT(name.startsWith("on")); + name = name.mid(2); + if(name[0] >= 'A' && name[0] <= 'Z') + name[0] = name[0] - 'A' + 'a'; + + bool notInRevision = false; + int sigIdx = indexOfSignal(obj, name, ¬InRevision); + + if (sigIdx == -1) { + + if (notInRevision && -1 == indexOfProperty(obj, prop->name, 0)) { + Q_ASSERT(obj->type != -1); + const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes(); + const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type); + if (type.type) { + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion)); + } else { + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name))); + } + } + + // If the "on<Signal>" name doesn't resolve into a signal, try it as a + // property. + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); + + } else { + + if (prop->value || prop->values.count() != 1) + COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment")); + + prop->index = sigIdx; + obj->addSignalProperty(prop); + + if (prop->values.at(0)->object) { + COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt)); + prop->values.at(0)->type = Value::SignalObject; + } else { + prop->values.at(0)->type = Value::SignalExpression; + + if (!prop->values.at(0)->value.isScript()) + COMPILE_EXCEPTION(prop, tr("Cannot assign a value to a signal (expecting a script to be run)")); + + QString script = prop->values.at(0)->value.asScript().trimmed(); + if (script.isEmpty()) + COMPILE_EXCEPTION(prop, tr("Empty signal assignment")); + + compileState.signalExpressions.insert(prop->values.at(0), ctxt); + } + } + + return true; +} + + +/*! + Returns true if (value) property \a prop exists on obj, false otherwise. +*/ +bool QDeclarativeCompiler::doesPropertyExist(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj) +{ + if(isAttachedPropertyName(prop->name) || prop->name == "id") + return true; + + const QMetaObject *mo = obj->metaObject(); + if (mo) { + if (prop->isDefault) { + QMetaProperty p = QDeclarativeMetaType::defaultProperty(mo); + return p.name() != 0; + } else { + int idx = indexOfProperty(obj, prop->name); + return idx != -1 && mo->property(idx).isScriptable(); + } + } + + return false; +} + +bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt) +{ + if (prop->isEmpty()) + COMPILE_EXCEPTION(prop, tr("Empty property assignment")); + + const QMetaObject *metaObject = obj->metaObject(); + Q_ASSERT(metaObject); + + if (isAttachedPropertyName(prop->name)) { + // Setup attached property data + + if (ctxt.isSubContext()) { + // Attached properties cannot be used on sub-objects. Sub-objects + // always exist in a binding sub-context, which is what we test + // for here. + COMPILE_EXCEPTION(prop, tr("Attached properties cannot be used here")); + } + + QDeclarativeType *type = 0; + QDeclarativeImportedNamespace *typeNamespace = 0; + unit->imports().resolveType(prop->name, &type, 0, 0, 0, &typeNamespace); + + if (typeNamespace) { + // ### We might need to indicate that this property is a namespace + // for the DOM API + COMPILE_CHECK(buildPropertyInNamespace(typeNamespace, prop, obj, + ctxt)); + return true; + } else if (!type || !type->attachedPropertiesType()) { + COMPILE_EXCEPTION(prop, tr("Non-existent attached object")); + } + + if (!prop->value) + COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment")); + + Q_ASSERT(type->attachedPropertiesFunction()); + prop->index = type->attachedPropertiesId(); + prop->value->metatype = type->attachedPropertiesType(); + } else { + // Setup regular property data + QMetaProperty p; + + if (prop->isDefault) { + p = QDeclarativeMetaType::defaultProperty(metaObject); + + if (p.name()) { + prop->index = p.propertyIndex(); + prop->name = p.name(); + } + + } else { + bool notInRevision = false; + prop->index = indexOfProperty(obj, prop->name, ¬InRevision); + if (prop->index == -1 && notInRevision) { + const QList<QDeclarativeTypeData::TypeReference> &resolvedTypes = unit->resolvedTypes(); + const QDeclarativeTypeData::TypeReference &type = resolvedTypes.at(obj->type); + if (type.type) { + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type.type->module())).arg(type.majorVersion).arg(type.minorVersion)); + } else { + COMPILE_EXCEPTION(prop, tr("\"%1.%2\" is not available due to component versioning.").arg(QString::fromUtf8(obj->className)).arg(QString::fromUtf8(prop->name))); + } + } + + if (prop->index != -1) { + p = metaObject->property(prop->index); + Q_ASSERT(p.name()); + + if (!p.isScriptable()) { + prop->index = -1; + p = QMetaProperty(); + } + } + } + + // We can't error here as the "id" property does not require a + // successful index resolution + if (p.name()) + prop->type = p.userType(); + + // Check if this is an alias + if (prop->index != -1 && + prop->parent && + prop->parent->type != -1 && + output->types.at(prop->parent->type).component) { + + QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache; + if (cache && cache->property(prop->index) && + cache->property(prop->index)->flags & QDeclarativePropertyCache::Data::IsAlias) + prop->isAlias = true; + } + + if (prop->index != -1 && !prop->values.isEmpty()) + prop->parent->setBindingBit(prop->index); + } + + if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) { + + // The magic "id" behavior doesn't apply when "id" is resolved as a + // default property or to sub-objects (which are always in binding + // sub-contexts) + COMPILE_CHECK(buildIdProperty(prop, obj)); + if (prop->type == QVariant::String && + prop->values.at(0)->value.isString()) + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); + + } else if (isAttachedPropertyName(prop->name)) { + + COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); + + } else if (prop->index == -1) { + + if (prop->isDefault) { + COMPILE_EXCEPTION(prop->values.first(), tr("Cannot assign to non-existent default property")); + } else { + COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name))); + } + + } else if (prop->value) { + + COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt)); + + } else if (enginePrivate->isList(prop->type)) { + + COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); + + } else if (prop->type == qMetaTypeId<QDeclarativeScriptString>()) { + + COMPILE_CHECK(buildScriptStringProperty(prop, obj, ctxt)); + + } else { + + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); + + } + + return true; +} + +bool QDeclarativeCompiler::buildPropertyInNamespace(QDeclarativeImportedNamespace *ns, + QDeclarativeParser::Property *nsProp, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt) +{ + if (!nsProp->value) + COMPILE_EXCEPTION(nsProp, tr("Invalid use of namespace")); + + foreach (Property *prop, nsProp->value->properties) { + + if (!isAttachedPropertyName(prop->name)) + COMPILE_EXCEPTION(prop, tr("Not an attached property name")); + + // Setup attached property data + + QDeclarativeType *type = 0; + unit->imports().resolveType(ns, prop->name, &type, 0, 0, 0); + + if (!type || !type->attachedPropertiesType()) + COMPILE_EXCEPTION(prop, tr("Non-existent attached object")); + + if (!prop->value) + COMPILE_EXCEPTION(prop, tr("Invalid attached object assignment")); + + Q_ASSERT(type->attachedPropertiesFunction()); + prop->index = type->index(); + prop->value->metatype = type->attachedPropertiesType(); + + COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); + } + + return true; +} + +void QDeclarativeCompiler::genValueProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj) +{ + if (enginePrivate->isList(prop->type)) { + genListProperty(prop, obj); + } else { + genPropertyAssignment(prop, obj); + } +} + +void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj) +{ + int listType = enginePrivate->listType(prop->type); + + QDeclarativeInstruction fetch; + fetch.type = QDeclarativeInstruction::FetchQList; + fetch.line = prop->location.start.line; + fetch.fetchQmlList.property = prop->index; + bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType); + fetch.fetchQmlList.type = listType; + output->bytecode << fetch; + + for (int ii = 0; ii < prop->values.count(); ++ii) { + QDeclarativeParser::Value *v = prop->values.at(ii); + + if (v->type == Value::CreatedObject) { + + genObject(v->object); + if (listTypeIsInterface) { + QDeclarativeInstruction assign; + assign.type = QDeclarativeInstruction::AssignObjectList; + assign.line = prop->location.start.line; + output->bytecode << assign; + } else { + QDeclarativeInstruction store; + store.type = QDeclarativeInstruction::StoreObjectQList; + store.line = prop->location.start.line; + output->bytecode << store; + } + + } else if (v->type == Value::PropertyBinding) { + + genBindingAssignment(v, prop, obj); + + } + + } + + QDeclarativeInstruction pop; + pop.type = QDeclarativeInstruction::PopQList; + pop.line = prop->location.start.line; + output->bytecode << pop; +} + +void QDeclarativeCompiler::genPropertyAssignment(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Property *valueTypeProperty) +{ + for (int ii = 0; ii < prop->values.count(); ++ii) { + QDeclarativeParser::Value *v = prop->values.at(ii); + + Q_ASSERT(v->type == Value::CreatedObject || + v->type == Value::PropertyBinding || + v->type == Value::Literal); + + if (v->type == Value::CreatedObject) { + + genObject(v->object); + + if (QDeclarativeMetaType::isInterface(prop->type)) { + + QDeclarativeInstruction store; + store.type = QDeclarativeInstruction::StoreInterface; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } else if (prop->type == -1) { + + QDeclarativeInstruction store; + store.type = QDeclarativeInstruction::StoreVariantObject; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } else { + + QDeclarativeInstruction store; + store.type = QDeclarativeInstruction::StoreObject; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } + } else if (v->type == Value::PropertyBinding) { + + genBindingAssignment(v, prop, obj, valueTypeProperty); + + } else if (v->type == Value::Literal) { + + QMetaProperty mp = obj->metaObject()->property(prop->index); + genLiteralAssignment(mp, v); + + } + + } + + for (int ii = 0; ii < prop->onValues.count(); ++ii) { + + QDeclarativeParser::Value *v = prop->onValues.at(ii); + + Q_ASSERT(v->type == Value::ValueSource || + v->type == Value::ValueInterceptor); + + if (v->type == Value::ValueSource) { + genObject(v->object); + + QDeclarativeInstruction store; + store.type = QDeclarativeInstruction::StoreValueSource; + store.line = v->object->location.start.line; + if (valueTypeProperty) { + store.assignValueSource.property = genValueTypeData(prop, valueTypeProperty); + store.assignValueSource.owner = 1; + } else { + store.assignValueSource.property = genPropertyData(prop); + store.assignValueSource.owner = 0; + } + QDeclarativeType *valueType = toQmlType(v->object); + store.assignValueSource.castValue = valueType->propertyValueSourceCast(); + output->bytecode << store; + + } else if (v->type == Value::ValueInterceptor) { + genObject(v->object); + + QDeclarativeInstruction store; + store.type = QDeclarativeInstruction::StoreValueInterceptor; + store.line = v->object->location.start.line; + if (valueTypeProperty) { + store.assignValueInterceptor.property = genValueTypeData(prop, valueTypeProperty); + store.assignValueInterceptor.owner = 1; + } else { + store.assignValueInterceptor.property = genPropertyData(prop); + store.assignValueInterceptor.owner = 0; + } + QDeclarativeType *valueType = toQmlType(v->object); + store.assignValueInterceptor.castValue = valueType->propertyValueInterceptorCast(); + output->bytecode << store; + } + + } +} + +bool QDeclarativeCompiler::buildIdProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj) +{ + if (prop->value || + prop->values.count() > 1 || + prop->values.at(0)->object) + COMPILE_EXCEPTION(prop, tr("Invalid use of id property")); + + QDeclarativeParser::Value *idValue = prop->values.at(0); + QString val = idValue->primitive(); + + COMPILE_CHECK(checkValidId(idValue, val)); + + if (compileState.ids.contains(val)) + COMPILE_EXCEPTION(prop, tr("id is not unique")); + + prop->values.at(0)->type = Value::Id; + + obj->id = val; + addId(val, obj); + + return true; +} + +void QDeclarativeCompiler::addId(const QString &id, QDeclarativeParser::Object *obj) +{ + Q_ASSERT(!compileState.ids.contains(id)); + Q_ASSERT(obj->id == id); + obj->idIndex = compileState.ids.count(); + compileState.ids.insert(id, obj); + compileState.idIndexes.insert(obj->idIndex, obj); +} + +void QDeclarativeCompiler::addBindingReference(const BindingReference &ref) +{ + Q_ASSERT(ref.value && !compileState.bindings.contains(ref.value)); + compileState.bindings.insert(ref.value, ref); +} + +void QDeclarativeCompiler::saveComponentState() +{ + Q_ASSERT(compileState.root); + Q_ASSERT(!savedCompileStates.contains(compileState.root)); + + savedCompileStates.insert(compileState.root, compileState); + savedComponentStats.append(componentStat); +} + +QDeclarativeCompiler::ComponentCompileState +QDeclarativeCompiler::componentState(QDeclarativeParser::Object *obj) +{ + Q_ASSERT(savedCompileStates.contains(obj)); + return savedCompileStates.value(obj); +} + +// Build attached property object. In this example, +// Text { +// GridView.row: 10 +// } +// GridView is an attached property object. +bool QDeclarativeCompiler::buildAttachedProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->value); + Q_ASSERT(prop->index != -1); // This is set in buildProperty() + + obj->addAttachedProperty(prop); + + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); + + return true; +} + + +// Build "grouped" properties. In this example: +// Text { +// font.pointSize: 12 +// font.family: "Helvetica" +// } +// font is a nested property. pointSize and family are not. +bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->type != 0); + Q_ASSERT(prop->index != -1); + + if (QDeclarativeValueTypeFactory::isValueType(prop->type)) { + if (prop->type >= 0 /* QVariant == -1 */ && enginePrivate->valueTypes[prop->type]) { + + if (prop->values.count()) { + if (prop->values.at(0)->location < prop->value->location) { + COMPILE_EXCEPTION(prop->value, tr( "Property has already been assigned a value")); + } else { + COMPILE_EXCEPTION(prop->values.at(0), tr( "Property has already been assigned a value")); + } + } + + if (!obj->metaObject()->property(prop->index).isWritable()) { + COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); + } + + + if (prop->isAlias) { + foreach (Property *vtProp, prop->value->properties) + vtProp->isAlias = true; + } + + COMPILE_CHECK(buildValueTypeProperty(enginePrivate->valueTypes[prop->type], + prop->value, obj, ctxt.incr())); + obj->addValueTypeProperty(prop); + } else { + COMPILE_EXCEPTION(prop, tr("Invalid grouped property access")); + } + + } else { + // Load the nested property's meta type + prop->value->metatype = enginePrivate->metaObjectForType(prop->type); + if (!prop->value->metatype) + COMPILE_EXCEPTION(prop, tr("Invalid grouped property access")); + + if (prop->values.count()) + COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign a value directly to a grouped property")); + + obj->addGroupedProperty(prop); + + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); + } + + return true; +} + +bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Object *baseObj, + const BindingContext &ctxt) +{ + if (obj->defaultProperty) + COMPILE_EXCEPTION(obj, tr("Invalid property use")); + obj->metatype = type->metaObject(); + + foreach (Property *prop, obj->properties) { + int idx = type->metaObject()->indexOfProperty(prop->name.constData()); + if (idx == -1) + COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name))); + QMetaProperty p = type->metaObject()->property(idx); + if (!p.isScriptable()) + COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(prop->name))); + prop->index = idx; + prop->type = p.userType(); + prop->isValueTypeSubProperty = true; + + if (prop->value) + COMPILE_EXCEPTION(prop, tr("Property assignment expected")); + + if (prop->values.count() > 1) { + COMPILE_EXCEPTION(prop, tr("Single property assignment expected")); + } else if (prop->values.count()) { + QDeclarativeParser::Value *value = prop->values.at(0); + + if (value->object) { + COMPILE_EXCEPTION(prop, tr("Unexpected object assignment")); + } else if (value->value.isScript()) { + // ### Check for writability + + //optimization for <Type>.<EnumValue> enum assignments + bool isEnumAssignment = false; + COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment)); + if (isEnumAssignment) { + value->type = Value::Literal; + } else { + BindingReference reference; + reference.expression = value->value; + reference.property = prop; + reference.value = value; + reference.bindingContext = ctxt; + reference.bindingContext.owner++; + addBindingReference(reference); + value->type = Value::PropertyBinding; + } + } else { + COMPILE_CHECK(testLiteralAssignment(p, value)); + value->type = Value::Literal; + } + } + + for (int ii = 0; ii < prop->onValues.count(); ++ii) { + QDeclarativeParser::Value *v = prop->onValues.at(ii); + Q_ASSERT(v->object); + + COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt)); + } + + obj->addValueProperty(prop); + } + + return true; +} + +// Build assignments to QML lists. QML lists are properties of type +// QDeclarativeListProperty<T>. List properties can accept a list of +// objects, or a single binding. +bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt) +{ + Q_ASSERT(enginePrivate->isList(prop->type)); + + int t = prop->type; + + obj->addValueProperty(prop); + + int listType = enginePrivate->listType(t); + bool listTypeIsInterface = QDeclarativeMetaType::isInterface(listType); + + bool assignedBinding = false; + for (int ii = 0; ii < prop->values.count(); ++ii) { + QDeclarativeParser::Value *v = prop->values.at(ii); + if (v->object) { + v->type = Value::CreatedObject; + COMPILE_CHECK(buildObject(v->object, ctxt)); + + // We check object coercian here. We check interface assignment + // at runtime. + if (!listTypeIsInterface) { + if (!canCoerce(listType, v->object)) { + COMPILE_EXCEPTION(v, tr("Cannot assign object to list")); + } + } + + } else if (v->value.isScript()) { + if (assignedBinding) + COMPILE_EXCEPTION(v, tr("Can only assign one binding to lists")); + + assignedBinding = true; + COMPILE_CHECK(buildBinding(v, prop, ctxt)); + v->type = Value::PropertyBinding; + } else { + COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists")); + } + } + + return true; +} + +// Compiles an assignment to a QDeclarativeScriptString property +bool QDeclarativeCompiler::buildScriptStringProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt) +{ + if (prop->values.count() > 1) + COMPILE_EXCEPTION(prop->values.at(1), tr( "Cannot assign multiple values to a script property")); + + if (prop->values.at(0)->object) + COMPILE_EXCEPTION(prop->values.at(0), tr( "Invalid property assignment: script expected")); + + obj->addScriptStringProperty(prop, ctxt.stack); + + return true; +} + +// Compile regular property assignments of the form "property: <value>" +bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt) +{ + obj->addValueProperty(prop); + + if (prop->values.count() > 1) + COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") ); + + for (int ii = 0; ii < prop->values.count(); ++ii) { + QDeclarativeParser::Value *v = prop->values.at(ii); + if (v->object) { + + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); + + } else { + + COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt)); + + } + } + + for (int ii = 0; ii < prop->onValues.count(); ++ii) { + QDeclarativeParser::Value *v = prop->onValues.at(ii); + + Q_ASSERT(v->object); + COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt)); + } + + return true; +} + +// Compile assigning a single object instance to a regular property +bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Value *v, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->index != -1); + Q_ASSERT(v->object->type != -1); + + if (!obj->metaObject()->property(prop->index).isWritable()) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); + + if (QDeclarativeMetaType::isInterface(prop->type)) { + + // Assigning an object to an interface ptr property + COMPILE_CHECK(buildObject(v->object, ctxt)); + + v->type = Value::CreatedObject; + + } else if (prop->type == -1) { + + // Assigning an object to a QVariant + COMPILE_CHECK(buildObject(v->object, ctxt)); + + v->type = Value::CreatedObject; + } else { + // Normally buildObject() will set this up, but we need the static + // meta object earlier to test for assignability. It doesn't matter + // that there may still be outstanding synthesized meta object changes + // on this type, as they are not relevant for assignability testing + v->object->metatype = output->types.at(v->object->type).metaObject(); + Q_ASSERT(v->object->metaObject()); + + // We want to raw metaObject here as the raw metaobject is the + // actual property type before we applied any extensions that might + // effect the properties on the type, but don't effect assignability + const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type); + + // Will be true if the assgned type inherits propertyMetaObject + bool isAssignable = false; + // Determine isAssignable value + if (propertyMetaObject) { + const QMetaObject *c = v->object->metatype; + while(c) { + isAssignable |= (QDeclarativePropertyPrivate::equal(c, propertyMetaObject)); + c = c->superClass(); + } + } + + if (isAssignable) { + // Simple assignment + COMPILE_CHECK(buildObject(v->object, ctxt)); + + v->type = Value::CreatedObject; + } else if (propertyMetaObject == &QDeclarativeComponent::staticMetaObject) { + // Automatic "Component" insertion + QDeclarativeParser::Object *root = v->object; + QDeclarativeParser::Object *component = new QDeclarativeParser::Object; + component->type = componentTypeRef(); + component->typeName = "Qt/Component"; + component->metatype = &QDeclarativeComponent::staticMetaObject; + component->location = root->location; + QDeclarativeParser::Value *componentValue = new QDeclarativeParser::Value; + componentValue->object = root; + component->getDefaultProperty()->addValue(componentValue); + v->object = component; + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); + } else { + COMPILE_EXCEPTION(v->object, tr("Cannot assign object to property")); + } + } + + return true; +} + +// Compile assigning a single object instance to a regular property using the "on" syntax. +// +// For example: +// Item { +// NumberAnimation on x { } +// } +bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Object *baseObj, + QDeclarativeParser::Value *v, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->index != -1); + Q_ASSERT(v->object->type != -1); + + if (!obj->metaObject()->property(prop->index).isWritable()) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); + + + // Normally buildObject() will set this up, but we need the static + // meta object earlier to test for assignability. It doesn't matter + // that there may still be outstanding synthesized meta object changes + // on this type, as they are not relevant for assignability testing + v->object->metatype = output->types.at(v->object->type).metaObject(); + Q_ASSERT(v->object->metaObject()); + + // Will be true if the assigned type inherits QDeclarativePropertyValueSource + bool isPropertyValue = false; + // Will be true if the assigned type inherits QDeclarativePropertyValueInterceptor + bool isPropertyInterceptor = false; + if (QDeclarativeType *valueType = toQmlType(v->object)) { + isPropertyValue = valueType->propertyValueSourceCast() != -1; + isPropertyInterceptor = valueType->propertyValueInterceptorCast() != -1; + } + + if (isPropertyValue || isPropertyInterceptor) { + // Assign as a property value source + COMPILE_CHECK(buildObject(v->object, ctxt)); + + if (isPropertyInterceptor && prop->parent->synthdata.isEmpty()) + buildDynamicMeta(baseObj, ForceCreation); + v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor; + } else { + COMPILE_EXCEPTION(v, tr("\"%1\" cannot operate on \"%2\"").arg(QString::fromUtf8(v->object->typeName)).arg(QString::fromUtf8(prop->name.constData()))); + } + + return true; +} + +// Compile assigning a literal or binding to a regular property +bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Value *v, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->index != -1); + + if (v->value.isScript()) { + + //optimization for <Type>.<EnumValue> enum assignments + bool isEnumAssignment = false; + COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, v, &isEnumAssignment)); + if (isEnumAssignment) { + v->type = Value::Literal; + return true; + } + + COMPILE_CHECK(buildBinding(v, prop, ctxt)); + + v->type = Value::PropertyBinding; + + } else { + + COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v)); + + v->type = Value::Literal; + } + + return true; +} + +bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Value *v, + bool *isAssignment) +{ + *isAssignment = false; + if (!prop.isEnumType()) + return true; + + if (!prop.isWritable()) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name()))); + + QString string = v->value.asString(); + if (!string.at(0).isUpper()) + return true; + + QStringList parts = string.split(QLatin1Char('.')); + if (parts.count() != 2) + return true; + + QString typeName = parts.at(0); + QDeclarativeType *type = 0; + unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0); + + //handle enums on value types (where obj->typeName is empty) + QByteArray objTypeName = obj->typeName; + if (objTypeName.isEmpty()) { + QDeclarativeType *objType = toQmlType(obj); + if (objType) + objTypeName = objType->qmlTypeName(); + } + + if (!type || objTypeName != type->qmlTypeName()) + return true; + + QString enumValue = parts.at(1); + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(enumValue.toUtf8().constData()); + } else + value = prop.enumerator().keyToValue(enumValue.toUtf8().constData()); + if (value == -1) + return true; + + v->type = Value::Literal; + v->value = QDeclarativeParser::Variant(enumValue); + *isAssignment = true; + + return true; +} + +// Similar logic to above, but not knowing target property. +int QDeclarativeCompiler::evaluateEnum(const QByteArray& script) const +{ + int dot = script.indexOf('.'); + if (dot > 0) { + QDeclarativeType *type = 0; + unit->imports().resolveType(script.left(dot), &type, 0, 0, 0, 0); + if (!type) + return -1; + const QMetaObject *mo = type->metaObject(); + const char *key = script.constData() + dot+1; + int i = mo->enumeratorCount(); + while (i--) { + int v = mo->enumerator(i).keyToValue(key); + if (v >= 0) + return v; + } + } + return -1; +} + +const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) const +{ + QDeclarativeType *qmltype = 0; + if (!unit->imports().resolveType(name, &qmltype, 0, 0, 0, 0)) + return 0; + if (!qmltype) + return 0; + return qmltype->metaObject(); +} + +// similar to logic of completeComponentBuild, but also sticks data +// into datas at the end +int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name) +{ + QDeclarativeRewrite::RewriteBinding rewriteBinding; + rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1)); + bool isSharable = false; + QString rewrite = rewriteBinding(expression, 0, &isSharable); + + quint32 length = rewrite.length(); + quint32 pc; + + if (isSharable) { + pc = output->cachedClosures.count(); + pc |= 0x80000000; + output->cachedClosures.append(0); + } else { + pc = output->cachedPrograms.length(); + output->cachedPrograms.append(0); + } + + QByteArray compiledData = + QByteArray((const char *)&pc, sizeof(quint32)) + + QByteArray((const char *)&length, sizeof(quint32)) + + QByteArray((const char *)rewrite.constData(), + rewrite.length() * sizeof(QChar)); + + return output->indexForByteArray(compiledData); +} + +// Ensures that the dynamic meta specification on obj is valid +bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj) +{ + QSet<QByteArray> propNames; + QSet<QByteArray> methodNames; + bool seenDefaultProperty = false; + + // Check properties + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const QDeclarativeParser::Object::DynamicProperty &prop = + obj->dynamicProperties.at(ii); + + if (prop.isDefaultProperty) { + if (seenDefaultProperty) + COMPILE_EXCEPTION(&prop, tr("Duplicate default property")); + seenDefaultProperty = true; + } + + if (propNames.contains(prop.name)) + COMPILE_EXCEPTION(&prop, tr("Duplicate property name")); + + QString propName = QString::fromUtf8(prop.name); + if (propName.at(0).isUpper()) + COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter")); + + if (enginePrivate->globalClass->illegalNames().contains(propName)) + COMPILE_EXCEPTION(&prop, tr("Illegal property name")); + + propNames.insert(prop.name); + } + + for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { + QByteArray name = obj->dynamicSignals.at(ii).name; + if (methodNames.contains(name)) + COMPILE_EXCEPTION(obj, tr("Duplicate signal name")); + QString nameStr = QString::fromUtf8(name); + if (nameStr.at(0).isUpper()) + COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter")); + if (enginePrivate->globalClass->illegalNames().contains(nameStr)) + COMPILE_EXCEPTION(obj, tr("Illegal signal name")); + methodNames.insert(name); + } + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + QByteArray name = obj->dynamicSlots.at(ii).name; + if (methodNames.contains(name)) + COMPILE_EXCEPTION(obj, tr("Duplicate method name")); + QString nameStr = QString::fromUtf8(name); + if (nameStr.at(0).isUpper()) + COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter")); + if (enginePrivate->globalClass->illegalNames().contains(nameStr)) + COMPILE_EXCEPTION(obj, tr("Illegal method name")); + methodNames.insert(name); + } + + return true; +} + +bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object *obj) +{ + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if (!p.defaultValue || p.type == Object::DynamicProperty::Alias) + continue; + + Property *property = 0; + if (p.isDefaultProperty) { + property = obj->getDefaultProperty(); + } else { + property = obj->getProperty(p.name); + if (!property->values.isEmpty()) + COMPILE_EXCEPTION(property, tr("Property value set multiple times")); + } + + if (property->value) + COMPILE_EXCEPTION(property, tr("Invalid property nesting")); + + for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) { + QDeclarativeParser::Value *v = p.defaultValue->values.at(ii); + v->addref(); + property->values.append(v); + } + } + return true; +} + +Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter) + +bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode) +{ + Q_ASSERT(obj); + Q_ASSERT(obj->metatype); + + if (mode != ForceCreation && + obj->dynamicProperties.isEmpty() && + obj->dynamicSignals.isEmpty() && + obj->dynamicSlots.isEmpty()) + return true; + + QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0); + + QByteArray newClassName = obj->metatype->className(); + newClassName.append("_QML_"); + int idx = classIndexCounter()->fetchAndAddRelaxed(1); + newClassName.append(QByteArray::number(idx)); + if (compileState.root == obj) { + QString path = output->url.path(); + int lastSlash = path.lastIndexOf(QLatin1Char('/')); + if (lastSlash > -1) { + QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); + if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) + newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx); + } + } + + QMetaObjectBuilder builder; + builder.setClassName(newClassName); + builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + + bool hasAlias = false; + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + int propIdx = obj->metaObject()->indexOfProperty(p.name.constData()); + if (-1 != propIdx) { + QMetaProperty prop = obj->metaObject()->property(propIdx); + if (prop.isFinal()) + COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property")); + } + + if (p.isDefaultProperty && + (p.type != Object::DynamicProperty::Alias || + mode == ResolveAliases)) + builder.addClassInfo("DefaultProperty", p.name); + + QByteArray type; + int propertyType = 0; + bool readonly = false; + switch(p.type) { + case Object::DynamicProperty::Alias: + hasAlias = true; + continue; + break; + case Object::DynamicProperty::CustomList: + case Object::DynamicProperty::Custom: + { + QByteArray customTypeName; + QDeclarativeType *qmltype = 0; + QUrl url; + if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0)) + COMPILE_EXCEPTION(&p, tr("Invalid property type")); + + if (!qmltype) { + QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url); + Q_ASSERT(tdata); + Q_ASSERT(tdata->isComplete()); + + QDeclarativeCompiledData *data = tdata->compiledData(); + customTypeName = data->root->className(); + data->release(); + tdata->release(); + } else { + customTypeName = qmltype->typeName(); + } + + if (p.type == Object::DynamicProperty::Custom) { + type = customTypeName + '*'; + propertyType = QMetaType::QObjectStar; + } else { + readonly = true; + type = "QDeclarativeListProperty<"; + type.append(customTypeName); + type.append(">"); + propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >(); + } + } + break; + case Object::DynamicProperty::Variant: + propertyType = -1; + type = "QVariant"; + break; + case Object::DynamicProperty::Int: + propertyType = QVariant::Int; + type = "int"; + break; + case Object::DynamicProperty::Bool: + propertyType = QVariant::Bool; + type = "bool"; + break; + case Object::DynamicProperty::Real: + propertyType = QVariant::Double; + type = "double"; + break; + case Object::DynamicProperty::String: + propertyType = QVariant::String; + type = "QString"; + break; + case Object::DynamicProperty::Url: + propertyType = QVariant::Url; + type = "QUrl"; + break; + case Object::DynamicProperty::Color: + propertyType = QVariant::Color; + type = "QColor"; + break; + case Object::DynamicProperty::Time: + propertyType = QVariant::Time; + type = "QTime"; + break; + case Object::DynamicProperty::Date: + propertyType = QVariant::Date; + type = "QDate"; + break; + case Object::DynamicProperty::DateTime: + propertyType = QVariant::DateTime; + type = "QDateTime"; + break; + } + + ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++; + QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType }; + dynamicData.append((char *)&propertyData, sizeof(propertyData)); + + builder.addSignal(p.name + "Changed()"); + QMetaPropertyBuilder propBuilder = + builder.addProperty(p.name, type, builder.methodCount() - 1); + propBuilder.setWritable(!readonly); + } + + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if (p.type == Object::DynamicProperty::Alias) { + if (mode == ResolveAliases) { + ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++; + COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p)); + } else { + // Need a fake signal so that the metaobject remains consistent across + // the resolve and non-resolve alias runs + builder.addSignal(p.name + "Changed()"); + } + } + } + + for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { + const Object::DynamicSignal &s = obj->dynamicSignals.at(ii); + QByteArray sig(s.name + '('); + for (int jj = 0; jj < s.parameterTypes.count(); ++jj) { + if (jj) sig.append(','); + sig.append(s.parameterTypes.at(jj)); + } + sig.append(')'); + QMetaMethodBuilder b = builder.addSignal(sig); + b.setParameterNames(s.parameterNames); + ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++; + } + + QStringList funcScripts; + + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + Object::DynamicSlot &s = obj->dynamicSlots[ii]; + QByteArray sig(s.name + '('); + QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('(')); + + for (int jj = 0; jj < s.parameterNames.count(); ++jj) { + if (jj) { + sig.append(','); + funcScript.append(QLatin1Char(',')); + } + funcScript.append(QLatin1String(s.parameterNames.at(jj))); + sig.append("QVariant"); + } + sig.append(')'); + funcScript.append(QLatin1Char(')')); + funcScript.append(s.body); + funcScript.append(QLatin1Char(')')); + funcScripts << funcScript; + + QMetaMethodBuilder b = builder.addSlot(sig); + b.setReturnType("QVariant"); + b.setParameterNames(s.parameterNames); + + ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++; + QDeclarativeVMEMetaData::MethodData methodData = + { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line }; + + dynamicData.append((char *)&methodData, sizeof(methodData)); + } + + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + const QString &funcScript = funcScripts.at(ii); + QDeclarativeVMEMetaData::MethodData *data = + ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii; + + data->bodyOffset = dynamicData.size(); + + dynamicData.append((const char *)funcScript.constData(), + (funcScript.length() * sizeof(QChar))); + } + + obj->metadata = builder.toRelocatableData(); + builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata); + + if (mode == IgnoreAliases && hasAlias) + compileState.aliasingObjects << obj; + + obj->synthdata = dynamicData; + + if (obj->synthCache) { + obj->synthCache->release(); + obj->synthCache = 0; + } + + if (obj->type != -1) { + QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy(); + cache->append(engine, &obj->extObject, QDeclarativePropertyCache::Data::NoFlags, + QDeclarativePropertyCache::Data::IsVMEFunction, + QDeclarativePropertyCache::Data::IsVMESignal); + obj->synthCache = cache; + } + + return true; +} + +bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QString &val) +{ + if (val.isEmpty()) + COMPILE_EXCEPTION(v, tr( "Invalid empty ID")); + + if (val.at(0).isLetter() && !val.at(0).isLower()) + COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter")); + + QChar u(QLatin1Char('_')); + for (int ii = 0; ii < val.count(); ++ii) { + + if (ii == 0 && !val.at(ii).isLetter() && val.at(ii) != u) { + COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore")); + } else if (ii != 0 && !val.at(ii).isLetterOrNumber() && val.at(ii) != u) { + COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores")); + } + + } + + if (enginePrivate->globalClass->illegalNames().contains(val)) + COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property")); + + return true; +} + +#include <qdeclarativejsparser_p.h> + +static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node) +{ + if (node->kind == QDeclarativeJS::AST::Node::Kind_IdentifierExpression) { + QString name = + static_cast<QDeclarativeJS::AST::IdentifierExpression *>(node)->name->asString(); + return QStringList() << name; + } else if (node->kind == QDeclarativeJS::AST::Node::Kind_FieldMemberExpression) { + QDeclarativeJS::AST::FieldMemberExpression *expr = static_cast<QDeclarativeJS::AST::FieldMemberExpression *>(node); + + QStringList rv = astNodeToStringList(expr->base); + if (rv.isEmpty()) + return rv; + rv.append(expr->name->asString()); + return rv; + } + return QStringList(); +} + +bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, + QByteArray &data, + QDeclarativeParser::Object *obj, + const Object::DynamicProperty &prop) +{ + if (!prop.defaultValue) + COMPILE_EXCEPTION(obj, tr("No property alias location")); + + if (prop.defaultValue->values.count() != 1 || + prop.defaultValue->values.at(0)->object || + !prop.defaultValue->values.at(0)->value.isScript()) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + + QDeclarativeJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST(); + if (!node) + COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen? + + QStringList alias = astNodeToStringList(node); + + if (alias.count() < 1 || alias.count() > 3) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); + + if (!compileState.ids.contains(alias.at(0))) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); + + QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)]; + + QByteArray typeName; + + int propIdx = -1; + int flags = 0; + bool writable = false; + if (alias.count() == 2 || alias.count() == 3) { + propIdx = indexOfProperty(idObject, alias.at(1).toUtf8()); + + if (-1 == propIdx) { + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + } else if (propIdx > 0xFFFF) { + COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds")); + } + + QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx); + if (!aliasProperty.isScriptable()) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + + writable = aliasProperty.isWritable(); + + if (alias.count() == 3) { + QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()]; + if (!valueType) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + + propIdx |= ((unsigned int)aliasProperty.type()) << 24; + + int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData()); + if (valueTypeIndex == -1) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + Q_ASSERT(valueTypeIndex <= 0xFF); + + aliasProperty = valueType->metaObject()->property(valueTypeIndex); + propIdx |= (valueTypeIndex << 16); + } + + if (aliasProperty.isEnumType()) + typeName = "int"; // Avoid introducing a dependency on the aliased metaobject + else + typeName = aliasProperty.typeName(); + } else { + typeName = idObject->metaObject()->className(); + + //use the base type since it has been registered with metatype system + int index = typeName.indexOf("_QML_"); + if (index != -1) { + typeName = typeName.left(index); + } else { + index = typeName.indexOf("_QMLTYPE_"); + const QMetaObject *mo = idObject->metaObject(); + while (index != -1 && mo) { + typeName = mo->superClass()->className(); + index = typeName.indexOf("_QMLTYPE_"); + mo = mo->superClass(); + } + } + + typeName += '*'; + } + + if (typeName.endsWith('*')) + flags |= QML_ALIAS_FLAG_PTR; + + data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex)); + data.append((const char *)&propIdx, sizeof(propIdx)); + data.append((const char *)&flags, sizeof(flags)); + + builder.addSignal(prop.name + "Changed()"); + QMetaPropertyBuilder propBuilder = + builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1); + propBuilder.setWritable(writable); + return true; +} + +bool QDeclarativeCompiler::buildBinding(QDeclarativeParser::Value *value, + QDeclarativeParser::Property *prop, + const BindingContext &ctxt) +{ + Q_ASSERT(prop->index != -1); + Q_ASSERT(prop->parent); + Q_ASSERT(prop->parent->metaObject()); + + QMetaProperty mp = prop->parent->metaObject()->property(prop->index); + if (!mp.isWritable() && !QDeclarativeMetaType::isList(prop->type)) + COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop->name))); + + BindingReference reference; + reference.expression = value->value; + reference.property = prop; + reference.value = value; + reference.bindingContext = ctxt; + addBindingReference(reference); + + return true; +} + +void QDeclarativeCompiler::genBindingAssignment(QDeclarativeParser::Value *binding, + QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Property *valueTypeProperty) +{ + Q_UNUSED(obj); + Q_ASSERT(compileState.bindings.contains(binding)); + + const BindingReference &ref = compileState.bindings.value(binding); + if (ref.dataType == BindingReference::Experimental) { + QDeclarativeInstruction store; + store.type = QDeclarativeInstruction::StoreCompiledBinding; + store.assignBinding.value = ref.compiledIndex; + store.assignBinding.context = ref.bindingContext.stack; + store.assignBinding.owner = ref.bindingContext.owner; + if (valueTypeProperty) + store.assignBinding.property = (valueTypeProperty->index & 0xFFFF) | + ((valueTypeProperty->type & 0xFF)) << 16 | + ((prop->index & 0xFF) << 24); + else + store.assignBinding.property = prop->index; + store.line = binding->location.start.line; + output->bytecode << store; + return; + } + + QDeclarativeInstruction store; + if (!prop->isAlias) + store.type = QDeclarativeInstruction::StoreBinding; + else + store.type = QDeclarativeInstruction::StoreBindingOnAlias; + store.assignBinding.value = output->indexForByteArray(ref.compiledData); + store.assignBinding.context = ref.bindingContext.stack; + store.assignBinding.owner = ref.bindingContext.owner; + store.line = binding->location.start.line; + + Q_ASSERT(ref.bindingContext.owner == 0 || + (ref.bindingContext.owner != 0 && valueTypeProperty)); + if (ref.bindingContext.owner) { + store.assignBinding.property = genValueTypeData(prop, valueTypeProperty); + } else { + store.assignBinding.property = genPropertyData(prop); + } + + output->bytecode << store; +} + +int QDeclarativeCompiler::genContextCache() +{ + if (compileState.ids.count() == 0) + return -1; + + QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(engine); + + for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin(); + iter != compileState.ids.end(); + ++iter) + cache->add(iter.key(), (*iter)->idIndex); + + output->contextCaches.append(cache); + return output->contextCaches.count() - 1; +} + +int QDeclarativeCompiler::genValueTypeData(QDeclarativeParser::Property *valueTypeProp, + QDeclarativeParser::Property *prop) +{ + QByteArray data = + QDeclarativePropertyPrivate::saveValueType(prop->parent->metaObject(), prop->index, + enginePrivate->valueTypes[prop->type]->metaObject(), + valueTypeProp->index); +// valueTypeProp->index, valueTypeProp->type); + + return output->indexForByteArray(data); +} + +int QDeclarativeCompiler::genPropertyData(QDeclarativeParser::Property *prop) +{ + return output->indexForByteArray(QDeclarativePropertyPrivate::saveProperty(prop->parent->metaObject(), prop->index)); +} + +bool QDeclarativeCompiler::completeComponentBuild() +{ + componentStat.ids = compileState.ids.count(); + + for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) { + QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii); + COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases)); + } + + QDeclarativeBindingCompiler::Expression expr; + expr.component = compileState.root; + expr.ids = compileState.ids; + + QDeclarativeBindingCompiler bindingCompiler; + + for (QHash<QDeclarativeParser::Value*,BindingReference>::Iterator iter = compileState.bindings.begin(); + iter != compileState.bindings.end(); ++iter) { + + BindingReference &binding = *iter; + + expr.context = binding.bindingContext.object; + expr.property = binding.property; + expr.expression = binding.expression; + expr.imports = unit->imports(); + + // ### We don't currently optimize for bindings on alias's - because + // of the solution to QTBUG-13719 + if (!binding.property->isAlias) { + int index = bindingCompiler.compile(expr, enginePrivate); + if (index != -1) { + binding.dataType = BindingReference::Experimental; + binding.compiledIndex = index; + componentStat.optimizedBindings.append(iter.key()->location); + continue; + } + } + + binding.dataType = BindingReference::QtScript; + + // Pre-rewrite the expression + QString expression = binding.expression.asScript(); + + QDeclarativeRewrite::RewriteBinding rewriteBinding; + rewriteBinding.setName('$'+binding.property->name); + bool isSharable = false; + expression = rewriteBinding(binding.expression.asAST(), expression, &isSharable); + + quint32 length = expression.length(); + quint32 pc; + + if (isSharable) { + pc = output->cachedClosures.count(); + pc |= 0x80000000; + output->cachedClosures.append(0); + } else { + pc = output->cachedPrograms.length(); + output->cachedPrograms.append(0); + } + + binding.compiledData = + QByteArray((const char *)&pc, sizeof(quint32)) + + QByteArray((const char *)&length, sizeof(quint32)) + + QByteArray((const char *)expression.constData(), + expression.length() * sizeof(QChar)); + + componentStat.scriptBindings.append(iter.key()->location); + } + + if (bindingCompiler.isValid()) { + compileState.compiledBindingData = bindingCompiler.program(); + if (bindingsDump()) + QDeclarativeBindingCompiler::dump(compileState.compiledBindingData); + } + + saveComponentState(); + + return true; +} + +void QDeclarativeCompiler::dumpStats() +{ + qWarning().nospace() << "QML Document: " << output->url.toString(); + for (int ii = 0; ii < savedComponentStats.count(); ++ii) { + const ComponentStat &stat = savedComponentStats.at(ii); + qWarning().nospace() << " Component Line " << stat.lineNumber; + qWarning().nospace() << " Total Objects: " << stat.objects; + qWarning().nospace() << " IDs Used: " << stat.ids; + qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count(); + + { + QByteArray output; + for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) { + if (0 == (ii % 10)) { + if (ii) output.append("\n"); + output.append(" "); + } + + output.append("("); + output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line)); + output.append(":"); + output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column)); + output.append(") "); + } + if (!output.isEmpty()) + qWarning().nospace() << output.constData(); + } + + qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count(); + { + QByteArray output; + for (int ii = 0; ii < stat.scriptBindings.count(); ++ii) { + if (0 == (ii % 10)) { + if (ii) output.append("\n"); + output.append(" "); + } + + output.append("("); + output.append(QByteArray::number(stat.scriptBindings.at(ii).start.line)); + output.append(":"); + output.append(QByteArray::number(stat.scriptBindings.at(ii).start.column)); + output.append(") "); + } + if (!output.isEmpty()) + qWarning().nospace() << output.constData(); + } + } +} + +/*! + Returns true if from can be assigned to a (QObject) property of type + to. +*/ +bool QDeclarativeCompiler::canCoerce(int to, QDeclarativeParser::Object *from) +{ + const QMetaObject *toMo = + enginePrivate->rawMetaObjectForType(to); + const QMetaObject *fromMo = from->metaObject(); + + while (fromMo) { + if (QDeclarativePropertyPrivate::equal(fromMo, toMo)) + return true; + fromMo = fromMo->superClass(); + } + return false; +} + +QDeclarativeType *QDeclarativeCompiler::toQmlType(QDeclarativeParser::Object *from) +{ + // ### Optimize + const QMetaObject *mo = from->metatype; + QDeclarativeType *type = 0; + while (!type && mo) { + type = QDeclarativeMetaType::qmlType(mo); + mo = mo->superClass(); + } + return type; +} + +QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeParser::Object *obj) +{ + const QMetaObject *mo = obj->metatype; + + int idx = mo->indexOfClassInfo("DeferredPropertyNames"); + if (idx == -1) + return QStringList(); + + QMetaClassInfo classInfo = mo->classInfo(idx); + QStringList rv = QString::fromUtf8(classInfo.value()).split(QLatin1Char(',')); + return rv; +} + +// This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName +int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, const QByteArray &name, + bool *notInRevision) +{ + if (notInRevision) *notInRevision = false; + + if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) { + // XXX fromUtf8 + QString strName(QString::fromUtf8(name)); + QDeclarativePropertyCache *cache = + object->synthCache?object->synthCache:output->types.at(object->type).propertyCache(); + + QDeclarativePropertyCache::Data *d = cache->property(strName); + if (notInRevision) *notInRevision = false; + + while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction)) + d = cache->overrideData(d); + + if (d && !cache->isAllowedInRevision(d)) { + if (notInRevision) *notInRevision = true; + return -1; + } else if (d) { + return d->coreIndex; + } + + if (name.endsWith("Changed")) { + QByteArray propName = name.mid(0, name.length() - 7); + + int propIndex = indexOfProperty(object, propName, notInRevision); + if (propIndex != -1) { + d = cache->property(propIndex); + return d->notifyIndex; + } + } + + return -1; + } else { + return QDeclarativePropertyPrivate::findSignalByName(object->metaObject(), name).methodIndex(); + } + +} + +int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, const QByteArray &name, + bool *notInRevision) +{ + if (notInRevision) *notInRevision = false; + + if (object->synthCache || (object->type != -1 && output->types.at(object->type).propertyCache())) { + // XXX fromUtf8 + QString strName(QString::fromUtf8(name)); + QDeclarativePropertyCache *cache = + object->synthCache?object->synthCache:output->types.at(object->type).propertyCache(); + + QDeclarativePropertyCache::Data *d = cache->property(strName); + // Find the first property + while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction) + d = cache->overrideData(d); + + if (d && !cache->isAllowedInRevision(d)) { + if (notInRevision) *notInRevision = true; + return -1; + } else { + return d?d->coreIndex:-1; + } + } else { + const QMetaObject *mo = object->metaObject(); + return mo->indexOfProperty(name.constData()); + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h new file mode 100644 index 00000000..619fa3b3 --- /dev/null +++ b/src/declarative/qml/qdeclarativecompiler_p.h @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECOMPILER_P_H +#define QDECLARATIVECOMPILER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarative.h" +#include "qdeclarativeerror.h" +#include "private/qdeclarativeinstruction_p.h" +#include "private/qdeclarativeparser_p.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qbitfield_p.h" +#include "private/qdeclarativepropertycache_p.h" +#include "private/qdeclarativeintegercache_p.h" +#include "private/qdeclarativetypenamecache_p.h" +#include "private/qdeclarativetypeloader_p.h" + +#include <QtCore/qbytearray.h> +#include <QtCore/qset.h> +#include <QtCore/QCoreApplication> + +QT_BEGIN_NAMESPACE + +class QDeclarativeEngine; +class QDeclarativeComponent; +class QDeclarativeContext; +class QDeclarativeContextData; + +class QScriptProgram; +class Q_AUTOTEST_EXPORT QDeclarativeCompiledData : public QDeclarativeRefCount, public QDeclarativeCleanup +{ +public: + QDeclarativeCompiledData(QDeclarativeEngine *engine); + virtual ~QDeclarativeCompiledData(); + + QString name; + QUrl url; + QDeclarativeTypeNameCache *importCache; + + struct TypeReference + { + TypeReference() + : type(0), typePropertyCache(0), component(0) {} + + QByteArray className; + QDeclarativeType *type; + QDeclarativePropertyCache *typePropertyCache; + QDeclarativeCompiledData *component; + + QObject *createInstance(QDeclarativeContextData *, const QBitField &, QList<QDeclarativeError> *) const; + const QMetaObject *metaObject() const; + QDeclarativePropertyCache *propertyCache() const; + QDeclarativePropertyCache *createPropertyCache(QDeclarativeEngine *); + }; + QList<TypeReference> types; + struct CustomTypeData + { + int index; + int type; + }; + + const QMetaObject *root; + QAbstractDynamicMetaObject rootData; + QDeclarativePropertyCache *rootPropertyCache; + QList<QString> primitives; + QList<float> floatData; + QList<int> intData; + QList<CustomTypeData> customTypeData; + QList<QByteArray> datas; + QList<QDeclarativeParser::Location> locations; + QList<QDeclarativeInstruction> bytecode; + QList<QScriptProgram *> cachedPrograms; + QList<QScriptValue *> cachedClosures; + QList<QDeclarativePropertyCache *> propertyCaches; + QList<QDeclarativeIntegerCache *> contextCaches; + QList<QDeclarativeParser::Object::ScriptBlock> scripts; + QList<QUrl> urls; + + void dumpInstructions(); + +protected: + virtual void clear(); // From QDeclarativeCleanup + +private: + void dump(QDeclarativeInstruction *, int idx = -1); + QDeclarativeCompiledData(const QDeclarativeCompiledData &other); + QDeclarativeCompiledData &operator=(const QDeclarativeCompiledData &other); + QByteArray packData; + friend class QDeclarativeCompiler; + int pack(const char *, size_t); + + int indexForString(const QString &); + int indexForByteArray(const QByteArray &); + int indexForFloat(float *, int); + int indexForInt(int *, int); + int indexForLocation(const QDeclarativeParser::Location &); + int indexForLocation(const QDeclarativeParser::LocationSpan &); + int indexForUrl(const QUrl &); +}; + +class QMetaObjectBuilder; +class Q_AUTOTEST_EXPORT QDeclarativeCompiler +{ + Q_DECLARE_TR_FUNCTIONS(QDeclarativeCompiler) +public: + QDeclarativeCompiler(); + + bool compile(QDeclarativeEngine *, QDeclarativeTypeData *, QDeclarativeCompiledData *); + + bool isError() const; + QList<QDeclarativeError> errors() const; + + static bool isAttachedPropertyName(const QByteArray &); + static bool isSignalPropertyName(const QByteArray &); + + int evaluateEnum(const QByteArray& script) const; // for QDeclarativeCustomParser::evaluateEnum + const QMetaObject *resolveType(const QByteArray& name) const; // for QDeclarativeCustomParser::resolveType + int rewriteBinding(const QString& expression, const QByteArray& name); // for QDeclarativeCustomParser::rewriteBinding + +private: + static void reset(QDeclarativeCompiledData *); + + struct BindingContext { + BindingContext() + : stack(0), owner(0), object(0) {} + BindingContext(QDeclarativeParser::Object *o) + : stack(0), owner(0), object(o) {} + BindingContext incr() const { + BindingContext rv(object); + rv.stack = stack + 1; + return rv; + } + bool isSubContext() const { return stack != 0; } + int stack; + int owner; + QDeclarativeParser::Object *object; + }; + + void compileTree(QDeclarativeParser::Object *tree); + + + bool buildObject(QDeclarativeParser::Object *obj, const BindingContext &); + bool buildComponent(QDeclarativeParser::Object *obj, const BindingContext &); + bool buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &); + bool buildSignal(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj, + const BindingContext &); + bool buildProperty(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj, + const BindingContext &); + bool buildPropertyInNamespace(QDeclarativeImportedNamespace *ns, + QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &); + bool buildIdProperty(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj); + bool buildAttachedProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt); + bool buildGroupedProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt); + bool buildValueTypeProperty(QObject *type, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Object *baseObj, + const BindingContext &ctxt); + bool buildListProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt); + bool buildScriptStringProperty(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt); + bool buildPropertyAssignment(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + const BindingContext &ctxt); + bool buildPropertyObjectAssignment(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Value *value, + const BindingContext &ctxt); + bool buildPropertyOnAssignment(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Object *baseObj, + QDeclarativeParser::Value *value, + const BindingContext &ctxt); + bool buildPropertyLiteralAssignment(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Value *value, + const BindingContext &ctxt); + bool doesPropertyExist(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj); + bool testLiteralAssignment(const QMetaProperty &prop, + QDeclarativeParser::Value *value); + bool testQualifiedEnumAssignment(const QMetaProperty &prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Value *value, + bool *isAssignment); + enum DynamicMetaMode { IgnoreAliases, ResolveAliases, ForceCreation }; + bool mergeDynamicMetaProperties(QDeclarativeParser::Object *obj); + bool buildDynamicMeta(QDeclarativeParser::Object *obj, DynamicMetaMode mode); + bool checkDynamicMeta(QDeclarativeParser::Object *obj); + bool buildBinding(QDeclarativeParser::Value *, QDeclarativeParser::Property *prop, + const BindingContext &ctxt); + bool buildComponentFromRoot(QDeclarativeParser::Object *obj, const BindingContext &); + bool compileAlias(QMetaObjectBuilder &, + QByteArray &data, + QDeclarativeParser::Object *obj, + const QDeclarativeParser::Object::DynamicProperty &); + bool completeComponentBuild(); + bool checkValidId(QDeclarativeParser::Value *, const QString &); + + + void genObject(QDeclarativeParser::Object *obj); + void genObjectBody(QDeclarativeParser::Object *obj); + void genValueTypeProperty(QDeclarativeParser::Object *obj,QDeclarativeParser::Property *); + void genComponent(QDeclarativeParser::Object *obj); + void genValueProperty(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj); + void genListProperty(QDeclarativeParser::Property *prop, QDeclarativeParser::Object *obj); + void genPropertyAssignment(QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Property *valueTypeProperty = 0); + void genLiteralAssignment(const QMetaProperty &prop, + QDeclarativeParser::Value *value); + void genBindingAssignment(QDeclarativeParser::Value *binding, + QDeclarativeParser::Property *prop, + QDeclarativeParser::Object *obj, + QDeclarativeParser::Property *valueTypeProperty = 0); + int genContextCache(); + + int genValueTypeData(QDeclarativeParser::Property *prop, QDeclarativeParser::Property *valueTypeProp); + int genPropertyData(QDeclarativeParser::Property *prop); + + int componentTypeRef(); + + static QDeclarativeType *toQmlType(QDeclarativeParser::Object *from); + bool canCoerce(int to, QDeclarativeParser::Object *from); + + QStringList deferredProperties(QDeclarativeParser::Object *); + int indexOfProperty(QDeclarativeParser::Object *, const QByteArray &, bool *notInRevision = 0); + int indexOfSignal(QDeclarativeParser::Object *, const QByteArray &, bool *notInRevision = 0); + + void addId(const QString &, QDeclarativeParser::Object *); + + void dumpStats(); + + struct BindingReference { + QDeclarativeParser::Variant expression; + QDeclarativeParser::Property *property; + QDeclarativeParser::Value *value; + + enum DataType { QtScript, Experimental }; + DataType dataType; + + int compiledIndex; + + QByteArray compiledData; + BindingContext bindingContext; + }; + void addBindingReference(const BindingReference &); + + struct ComponentCompileState + { + ComponentCompileState() + : parserStatusCount(0), pushedProperties(0), root(0) {} + QHash<QString, QDeclarativeParser::Object *> ids; + QHash<int, QDeclarativeParser::Object *> idIndexes; + int parserStatusCount; + int pushedProperties; + + QByteArray compiledBindingData; + + QHash<QDeclarativeParser::Value *, BindingReference> bindings; + QHash<QDeclarativeParser::Value *, BindingContext> signalExpressions; + QList<QDeclarativeParser::Object *> aliasingObjects; + QDeclarativeParser::Object *root; + }; + ComponentCompileState compileState; + + struct ComponentStat + { + ComponentStat() : ids(0), objects(0) {} + + int lineNumber; + + int ids; + QList<QDeclarativeParser::LocationSpan> scriptBindings; + QList<QDeclarativeParser::LocationSpan> optimizedBindings; + int objects; + }; + ComponentStat componentStat; + + void saveComponentState(); + + ComponentCompileState componentState(QDeclarativeParser::Object *); + QHash<QDeclarativeParser::Object *, ComponentCompileState> savedCompileStates; + QList<ComponentStat> savedComponentStats; + + QList<QDeclarativeError> exceptions; + QDeclarativeCompiledData *output; + QDeclarativeEngine *engine; + QDeclarativeEnginePrivate *enginePrivate; + QDeclarativeParser::Object *unitRoot; + QDeclarativeTypeData *unit; +}; +QT_END_NAMESPACE + +#endif // QDECLARATIVECOMPILER_P_H diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp new file mode 100644 index 00000000..e427f4e8 --- /dev/null +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -0,0 +1,1086 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativecomponent.h" +#include "private/qdeclarativecomponent_p.h" + +#include "private/qdeclarativecompiler_p.h" +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativevme_p.h" +#include "qdeclarative.h" +#include "qdeclarativeengine.h" +#include "private/qdeclarativebinding_p.h" +#include "private/qdeclarativebinding_p_p.h" +#include "private/qdeclarativeglobal_p.h" +#include "private/qdeclarativescriptparser_p.h" +#include "private/qdeclarativedebugtrace_p.h" +#include "private/qdeclarativeenginedebugservice_p.h" +#include <QtScript/qscriptvalueiterator.h> + +#include <QStack> +#include <QStringList> +#include <QtCore/qdebug.h> +#include <QApplication> +#include <qdeclarativeinfo.h> + +QT_BEGIN_NAMESPACE + +class QByteArray; + +/*! + \class QDeclarativeComponent + \since 4.7 + \brief The QDeclarativeComponent class encapsulates a QML component definition. + \mainclass + + Components are reusable, encapsulated QML elements with well-defined interfaces. + They are often defined in \l {qdeclarativedocuments.html}{Component Files}. + + A QDeclarativeComponent instance can be created from a QML file. + For example, if there is a \c main.qml file like this: + + \qml + import QtQuick 1.0 + + Item { + width: 200 + height: 200 + } + \endqml + + The following code loads this QML file as a component, creates an instance of + this component using create(), and then queries the \l Item's \l {Item::}{width} + value: + + \code + QDeclarativeEngine *engine = new QDeclarativeEngine; + QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml")); + + QObject *myObject = component.create(); + QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(myObject); + int width = item->width(); // width = 200 + \endcode + + + \section2 Network Components + + If the URL passed to QDeclarativeComponent is a network resource, or if the QML document references a + network resource, the QDeclarativeComponent has to fetch the network data before it is able to create + objects. In this case, the QDeclarativeComponent will have a \l {QDeclarativeComponent::Loading}{Loading} + \l {QDeclarativeComponent::status()}{status}. An application will have to wait until the component + is \l {QDeclarativeComponent::Ready}{Ready} before calling \l {QDeclarativeComponent::create()}. + + The following example shows how to load a QML file from a network resource. After creating + the QDeclarativeComponent, it tests whether the component is loading. If it is, it connects to the + QDeclarativeComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method + directly. Note that QDeclarativeComponent::isLoading() may be false for a network component if the + component has been cached and is ready immediately. + + \code + MyApplication::MyApplication() + { + // ... + component = new QDeclarativeComponent(engine, QUrl("http://www.example.com/main.qml")); + if (component->isLoading()) + QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), + this, SLOT(continueLoading())); + else + continueLoading(); + } + + void MyApplication::continueLoading() + { + if (component->isError()) { + qWarning() << component->errors(); + } else { + QObject *myObject = component->create(); + } + } + \endcode + + \sa {Using QML Bindings in C++ Applications}, {Integrating QML Code with Existing Qt UI Code} +*/ + +/*! + \qmlclass Component QDeclarativeComponent + \ingroup qml-utility-elements + \since 4.7 + \brief The Component element encapsulates a QML component definition. + + Components are reusable, encapsulated QML elements with well-defined interfaces. + + Components are often defined by \l {qdeclarativedocuments.html}{component files} - + that is, \c .qml files. The \e Component element essentially allows QML components + to be defined inline, within a \l {QML Document}{QML document}, rather than as a separate QML file. + This may be useful for reusing a small component within a QML file, or for defining + a component that logically belongs with other QML components within a file. + + For example, here is a component that is used by multiple \l Loader objects. + It contains a single item, a \l Rectangle: + + \snippet doc/src/snippets/declarative/component.qml 0 + + Notice that while a \l Rectangle by itself would be automatically + rendered and displayed, this is not the case for the above rectangle + because it is defined inside a \c Component. The component encapsulates the + QML elements within, as if they were defined in a separate QML + file, and is not loaded until requested (in this case, by the + two \l Loader objects). + + Defining a \c Component is similar to defining a \l {QML Document}{QML document}. + A QML document has a single top-level item that defines the behaviors and + properties of that component, and cannot define properties or behaviors outside + of that top-level item. In the same way, a \c Component definition contains a single + top level item (which in the above example is a \l Rectangle) and cannot define any + data outside of this item, with the exception of an \e id (which in the above example + is \e redSquare). + + The \c Component element is commonly used to provide graphical components + for views. For example, the ListView::delegate property requires a \c Component + to specify how each list item is to be displayed. + + \c Component objects can also be created dynamically using + \l{QML:Qt::createComponent()}{Qt.createComponent()}. +*/ + +/*! + \qmlattachedsignal Component::onCompleted() + + Emitted after component "startup" has completed. This can be used to + execute script code at startup, once the full QML environment has been + established. + + The \c {Component::onCompleted} attached property can be applied to + any element. The order of running the \c onCompleted scripts is + undefined. + + \qml + Rectangle { + Component.onCompleted: console.log("Completed Running!") + Rectangle { + Component.onCompleted: console.log("Nested Completed Running!") + } + } + \endqml +*/ + +/*! + \qmlattachedsignal Component::onDestruction() + + Emitted as the component begins destruction. This can be used to undo + work done in the onCompleted signal, or other imperative code in your + application. + + The \c {Component::onDestruction} attached property can be applied to + any element. However, it applies to the destruction of the component as + a whole, and not the destruction of the specific object. The order of + running the \c onDestruction scripts is undefined. + + \qml + Rectangle { + Component.onDestruction: console.log("Destruction Beginning!") + Rectangle { + Component.onDestruction: console.log("Nested Destruction Beginning!") + } + } + \endqml + + \sa QtDeclarative +*/ + +/*! + \enum QDeclarativeComponent::Status + + Specifies the loading status of the QDeclarativeComponent. + + \value Null This QDeclarativeComponent has no data. Call loadUrl() or setData() to add QML content. + \value Ready This QDeclarativeComponent is ready and create() may be called. + \value Loading This QDeclarativeComponent is loading network data. + \value Error An error has occurred. Call errors() to retrieve a list of \{QDeclarativeError}{errors}. +*/ + +void QDeclarativeComponentPrivate::typeDataReady(QDeclarativeTypeData *) +{ + Q_Q(QDeclarativeComponent); + + Q_ASSERT(typeData); + + fromTypeData(typeData); + typeData = 0; + + emit q->statusChanged(q->status()); +} + +void QDeclarativeComponentPrivate::typeDataProgress(QDeclarativeTypeData *, qreal p) +{ + Q_Q(QDeclarativeComponent); + + progress = p; + + emit q->progressChanged(p); +} + +void QDeclarativeComponentPrivate::fromTypeData(QDeclarativeTypeData *data) +{ + url = data->finalUrl(); + QDeclarativeCompiledData *c = data->compiledData(); + + if (!c) { + Q_ASSERT(data->isError()); + state.errors = data->errors(); + } else { + cc = c; + } + + data->release(); +} + +void QDeclarativeComponentPrivate::clear() +{ + if (typeData) { + typeData->unregisterCallback(this); + typeData->release(); + typeData = 0; + } + + if (cc) { + cc->release(); + cc = 0; + } +} + +/*! + \internal +*/ +QDeclarativeComponent::QDeclarativeComponent(QObject *parent) + : QObject(*(new QDeclarativeComponentPrivate), parent) +{ +} + +/*! + Destruct the QDeclarativeComponent. +*/ +QDeclarativeComponent::~QDeclarativeComponent() +{ + Q_D(QDeclarativeComponent); + + if (d->state.completePending) { + qWarning("QDeclarativeComponent: Component destroyed while completion pending"); + d->completeCreate(); + } + + if (d->typeData) { + d->typeData->unregisterCallback(d); + d->typeData->release(); + } + if (d->cc) + d->cc->release(); +} + +/*! + \qmlproperty enumeration Component::status + This property holds the status of component loading. It can be one of: + \list + \o Component.Null - no data is available for the component + \o Component.Ready - the component has been loaded, and can be used to create instances. + \o Component.Loading - the component is currently being loaded + \o Component.Error - an error occurred while loading the component. + Calling errorString() will provide a human-readable description of any errors. + \endlist + */ + +/*! + \property QDeclarativeComponent::status + The component's current \l{QDeclarativeComponent::Status} {status}. + */ +QDeclarativeComponent::Status QDeclarativeComponent::status() const +{ + Q_D(const QDeclarativeComponent); + + if (d->typeData) + return Loading; + else if (!d->state.errors.isEmpty()) + return Error; + else if (d->engine && d->cc) + return Ready; + else + return Null; +} + +/*! + Returns true if status() == QDeclarativeComponent::Null. +*/ +bool QDeclarativeComponent::isNull() const +{ + return status() == Null; +} + +/*! + Returns true if status() == QDeclarativeComponent::Ready. +*/ +bool QDeclarativeComponent::isReady() const +{ + return status() == Ready; +} + +/*! + Returns true if status() == QDeclarativeComponent::Error. +*/ +bool QDeclarativeComponent::isError() const +{ + return status() == Error; +} + +/*! + Returns true if status() == QDeclarativeComponent::Loading. +*/ +bool QDeclarativeComponent::isLoading() const +{ + return status() == Loading; +} + +/*! + \qmlproperty real Component::progress + The progress of loading the component, from 0.0 (nothing loaded) + to 1.0 (finished). +*/ + +/*! + \property QDeclarativeComponent::progress + The progress of loading the component, from 0.0 (nothing loaded) + to 1.0 (finished). +*/ +qreal QDeclarativeComponent::progress() const +{ + Q_D(const QDeclarativeComponent); + return d->progress; +} + +/*! + \fn void QDeclarativeComponent::progressChanged(qreal progress) + + Emitted whenever the component's loading progress changes. \a progress will be the + current progress between 0.0 (nothing loaded) and 1.0 (finished). +*/ + +/*! + \fn void QDeclarativeComponent::statusChanged(QDeclarativeComponent::Status status) + + Emitted whenever the component's status changes. \a status will be the + new status. +*/ + +/*! + Create a QDeclarativeComponent with no data and give it the specified + \a engine and \a parent. Set the data with setData(). +*/ +QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QObject *parent) + : QObject(*(new QDeclarativeComponentPrivate), parent) +{ + Q_D(QDeclarativeComponent); + d->engine = engine; +} + +/*! + Create a QDeclarativeComponent from the given \a url and give it the + specified \a parent and \a engine. + + Ensure that the URL provided is full and correct, in particular, use + \l QUrl::fromLocalFile() when loading a file from the local filesystem. + + \sa loadUrl() +*/ +QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QUrl &url, QObject *parent) +: QObject(*(new QDeclarativeComponentPrivate), parent) +{ + Q_D(QDeclarativeComponent); + d->engine = engine; + loadUrl(url); +} + +/*! + Create a QDeclarativeComponent from the given \a fileName and give it the specified + \a parent and \a engine. + + \sa loadUrl() +*/ +QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QString &fileName, + QObject *parent) +: QObject(*(new QDeclarativeComponentPrivate), parent) +{ + Q_D(QDeclarativeComponent); + d->engine = engine; + loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName))); +} + +/*! + \internal +*/ +QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QDeclarativeCompiledData *cc, int start, int count, QObject *parent) + : QObject(*(new QDeclarativeComponentPrivate), parent) +{ + Q_D(QDeclarativeComponent); + d->engine = engine; + d->cc = cc; + cc->addref(); + d->start = start; + d->count = count; + d->url = cc->url; + d->progress = 1.0; +} + +/*! + Sets the QDeclarativeComponent to use the given QML \a data. If \a url + is provided, it is used to set the component name and to provide + a base path for items resolved by this component. +*/ +void QDeclarativeComponent::setData(const QByteArray &data, const QUrl &url) +{ + Q_D(QDeclarativeComponent); + + d->clear(); + + d->url = url; + + QDeclarativeTypeData *typeData = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(data, url); + + if (typeData->isCompleteOrError()) { + d->fromTypeData(typeData); + } else { + d->typeData = typeData; + d->typeData->registerCallback(d); + } + + d->progress = 1.0; + emit statusChanged(status()); + emit progressChanged(d->progress); +} + +/*! +Returns the QDeclarativeContext the component was created in. This is only +valid for components created directly from QML. +*/ +QDeclarativeContext *QDeclarativeComponent::creationContext() const +{ + Q_D(const QDeclarativeComponent); + if(d->creationContext) + return d->creationContext->asQDeclarativeContext(); + + return qmlContext(this); +} + +/*! + Load the QDeclarativeComponent from the provided \a url. + + Ensure that the URL provided is full and correct, in particular, use + \l QUrl::fromLocalFile() when loading a file from the local filesystem. +*/ +void QDeclarativeComponent::loadUrl(const QUrl &url) +{ + Q_D(QDeclarativeComponent); + + d->clear(); + + if ((url.isRelative() && !url.isEmpty()) + || url.scheme() == QLatin1String("file")) // Workaround QTBUG-11929 + d->url = d->engine->baseUrl().resolved(url); + else + d->url = url; + + if (url.isEmpty()) { + QDeclarativeError error; + error.setDescription(tr("Invalid empty URL")); + d->state.errors << error; + return; + } + + QDeclarativeTypeData *data = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(d->url); + + if (data->isCompleteOrError()) { + d->fromTypeData(data); + d->progress = 1.0; + } else { + d->typeData = data; + d->typeData->registerCallback(d); + d->progress = data->progress(); + } + + emit statusChanged(status()); + emit progressChanged(d->progress); +} + +/*! + Return the list of errors that occurred during the last compile or create + operation. An empty list is returned if isError() is not set. +*/ +QList<QDeclarativeError> QDeclarativeComponent::errors() const +{ + Q_D(const QDeclarativeComponent); + if (isError()) + return d->state.errors; + else + return QList<QDeclarativeError>(); +} + +/*! + \qmlmethod string Component::errorString() + + Returns a human-readable description of any errors. + + The string includes the file, location, and description of each error. + If multiple errors are present they are separated by a newline character. + + If no errors are present, an empty string is returned. +*/ + +/*! + \internal + errorString is only meant as a way to get the errors in script +*/ +QString QDeclarativeComponent::errorString() const +{ + Q_D(const QDeclarativeComponent); + QString ret; + if(!isError()) + return ret; + foreach(const QDeclarativeError &e, d->state.errors) { + ret += e.url().toString() + QLatin1Char(':') + + QString::number(e.line()) + QLatin1Char(' ') + + e.description() + QLatin1Char('\n'); + } + return ret; +} + +/*! + \qmlproperty url Component::url + The component URL. This is the URL that was used to construct the component. +*/ + +/*! + \property QDeclarativeComponent::url + The component URL. This is the URL passed to either the constructor, + or the loadUrl() or setData() methods. +*/ +QUrl QDeclarativeComponent::url() const +{ + Q_D(const QDeclarativeComponent); + return d->url; +} + +/*! + \internal +*/ +QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} + +/*! + \qmlmethod object Component::createObject(Item parent, object properties) + + Creates and returns an object instance of this component that will have + the given \a parent and \a properties. The \a properties argument is optional. + Returns null if object creation fails. + + The object will be created in the same context as the one in which the component + was created. This function will always return null when called on components + which were not created in QML. + + If you wish to create an object without setting a parent, specify \c null for + the \a parent value. Note that if the returned object is to be displayed, you + must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent} + property, or else the object will not be visible. + + If a \a parent is not provided to createObject(), a reference to the returned object must be held so that + it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards, + since setting the Item parent does not change object ownership; only the graphical parent is changed. + + As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a + map of initial property values for the created object. These values are applied before object + creation is finalized. (This is more efficient than setting property values after object creation, + particularly where large sets of property values are defined, and also allows property bindings + to be set up before the object is created.) + + The \a properties argument is specified as a map of property-value items. For example, the code + below creates an object with initial \c x and \c y values of 100 and 200, respectively: + + \js + var component = Qt.createComponent("Button.qml"); + if (component.status == Component.Ready) + component.createObject(parent, {"x": 100, "y": 100}); + \endjs + + Dynamically created instances can be deleted with the \c destroy() method. + See \l {Dynamic Object Management in QML} for more information. +*/ + +/*! + \internal + A version of create which returns a scriptObject, for use in script. + This function will only work on components created in QML. + + Sets graphics object parent because forgetting to do this is a frequent + and serious problem. +*/ +QScriptValue QDeclarativeComponent::createObject(QObject* parent) +{ + Q_D(QDeclarativeComponent); + return d->createObject(parent, QScriptValue(QScriptValue::NullValue)); +} + +/*! + \internal + Overloadable method allows properties to be set during creation +*/ +QScriptValue QDeclarativeComponent::createObject(QObject* parent, const QScriptValue& valuemap) +{ + Q_D(QDeclarativeComponent); + + if (!valuemap.isObject() || valuemap.isArray()) { + qmlInfo(this) << tr("createObject: value is not an object"); + return QScriptValue(QScriptValue::NullValue); + } + return d->createObject(parent, valuemap); +} + +QScriptValue QDeclarativeComponentPrivate::createObject(QObject *publicParent, const QScriptValue valuemap) +{ + Q_Q(QDeclarativeComponent); + QDeclarativeContext* ctxt = q->creationContext(); + if(!ctxt && engine) + ctxt = engine->rootContext(); + if (!ctxt) + return QScriptValue(QScriptValue::NullValue); + QObject* ret = q->beginCreate(ctxt); + if (!ret) { + q->completeCreate(); + return QScriptValue(QScriptValue::NullValue); + } + + if (publicParent) { + ret->setParent(publicParent); + QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions(); + + bool needParent = false; + + for (int ii = 0; ii < functions.count(); ++ii) { + QDeclarativePrivate::AutoParentResult res = functions.at(ii)(ret, publicParent); + if (res == QDeclarativePrivate::Parented) { + needParent = false; + break; + } else if (res == QDeclarativePrivate::IncompatibleParent) { + needParent = true; + } + } + + if (needParent) + qWarning("QDeclarativeComponent: Created graphical object was not placed in the graphics scene."); + } + + QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine); + QDeclarativeData::get(ret, true)->setImplicitDestructible(); + QScriptValue newObject = priv->objectClass->newQObject(ret, QMetaType::QObjectStar); + + if (valuemap.isObject() && !valuemap.isArray()) { + //Iterate through and assign properties + QScriptValueIterator it(valuemap); + while (it.hasNext()) { + it.next(); + QScriptValue prop = newObject; + QString propName = it.name(); + int index = propName.indexOf(QLatin1Char('.')); + if (index > 0) { + QString subProp = propName; + int lastIndex = 0; + while (index > 0) { + subProp = propName.mid(lastIndex, index - lastIndex); + prop = prop.property(subProp); + lastIndex = index + 1; + index = propName.indexOf(QLatin1Char('.'), index + 1); + } + prop.setProperty(propName.mid(propName.lastIndexOf(QLatin1Char('.')) + 1), it.value()); + } else { + newObject.setProperty(propName, it.value()); + } + } + } + + q->completeCreate(); + + return newObject; +} + +/*! + Create an object instance from this component. Returns 0 if creation + failed. \a context specifies the context within which to create the object + instance. + + If \a context is 0 (the default), it will create the instance in the + engine' s \l {QDeclarativeEngine::rootContext()}{root context}. +*/ +QObject *QDeclarativeComponent::create(QDeclarativeContext *context) +{ + Q_D(QDeclarativeComponent); + + if (!context) + context = d->engine->rootContext(); + + QObject *rv = beginCreate(context); + completeCreate(); + return rv; +} + +/*! + This method provides more advanced control over component instance creation. + In general, programmers should use QDeclarativeComponent::create() to create a + component. + + Create an object instance from this component. Returns 0 if creation + failed. \a context specifies the context within which to create the object + instance. + + When QDeclarativeComponent constructs an instance, it occurs in three steps: + \list 1 + \i The object hierarchy is created, and constant values are assigned. + \i Property bindings are evaluated for the the first time. + \i If applicable, QDeclarativeParserStatus::componentComplete() is called on objects. + \endlist + QDeclarativeComponent::beginCreate() differs from QDeclarativeComponent::create() in that it + only performs step 1. QDeclarativeComponent::completeCreate() must be called to + complete steps 2 and 3. + + This breaking point is sometimes useful when using attached properties to + communicate information to an instantiated component, as it allows their + initial values to be configured before property bindings take effect. +*/ +QObject *QDeclarativeComponent::beginCreate(QDeclarativeContext *context) +{ + Q_D(QDeclarativeComponent); + QObject *rv = d->beginCreate(context?QDeclarativeContextData::get(context):0, QBitField()); + if (rv) { + QDeclarativeData *ddata = QDeclarativeData::get(rv); + Q_ASSERT(ddata); + ddata->indestructible = true; + } + return rv; +} + +QObject * +QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, const QBitField &bindings) +{ + Q_Q(QDeclarativeComponent); + if (!context) { + qWarning("QDeclarativeComponent: Cannot create a component in a null context"); + return 0; + } + + if (!context->isValid()) { + qWarning("QDeclarativeComponent: Cannot create a component in an invalid context"); + return 0; + } + + if (context->engine != engine) { + qWarning("QDeclarativeComponent: Must create component in context from the same QDeclarativeEngine"); + return 0; + } + + if (state.completePending) { + qWarning("QDeclarativeComponent: Cannot create new component instance before completing the previous"); + return 0; + } + + if (!q->isReady()) { + qWarning("QDeclarativeComponent: Component is not ready"); + return 0; + } + + return begin(context, creationContext, cc, start, count, &state, 0, bindings); +} + +QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentContext, + QDeclarativeContextData *componentCreationContext, + QDeclarativeCompiledData *component, int start, int count, + ConstructionState *state, QList<QDeclarativeError> *errors, + const QBitField &bindings) +{ + QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentContext->engine); + bool isRoot = !enginePriv->inBeginCreate; + + Q_ASSERT(!isRoot || state); // Either this isn't a root component, or a state data must be provided + Q_ASSERT((state != 0) ^ (errors != 0)); // One of state or errors (but not both) must be provided + + if (isRoot) { + QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating); + QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, component->url); + } + + QDeclarativeContextData *ctxt = new QDeclarativeContextData; + ctxt->isInternal = true; + ctxt->url = component->url; + ctxt->imports = component->importCache; + + // Nested global imports + if (componentCreationContext && start != -1) + ctxt->importedScripts = componentCreationContext->importedScripts; + + component->importCache->addref(); + ctxt->setParent(parentContext); + + enginePriv->inBeginCreate = true; + + QDeclarativeVME vme; + QObject *rv = vme.run(ctxt, component, start, count, bindings); + + if (vme.isError()) { + if(errors) *errors = vme.errors(); + else state->errors = vme.errors(); + } + + if (isRoot) { + enginePriv->inBeginCreate = false; + + state->bindValues = enginePriv->bindValues; + state->parserStatus = enginePriv->parserStatus; + state->finalizedParserStatus = enginePriv->finalizedParserStatus; + state->componentAttached = enginePriv->componentAttached; + if (state->componentAttached) + state->componentAttached->prev = &state->componentAttached; + + enginePriv->componentAttached = 0; + enginePriv->bindValues.clear(); + enginePriv->parserStatus.clear(); + enginePriv->finalizedParserStatus.clear(); + state->completePending = true; + enginePriv->inProgressCreations++; + } + + if (enginePriv->isDebugging && rv) { + if (!parentContext->isInternal) + parentContext->asQDeclarativeContextPrivate()->instances.append(rv); + QDeclarativeEngineDebugService::instance()->objectCreated(parentContext->engine, rv); + } + + return rv; +} + +void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *enginePriv, + QObject *object, ConstructionState *state) +{ + bool isRoot = !enginePriv->inBeginCreate; + enginePriv->inBeginCreate = true; + + QDeclarativeVME vme; + vme.runDeferred(object); + + if (vme.isError()) + state->errors = vme.errors(); + + if (isRoot) { + enginePriv->inBeginCreate = false; + + state->bindValues = enginePriv->bindValues; + state->parserStatus = enginePriv->parserStatus; + state->finalizedParserStatus = enginePriv->finalizedParserStatus; + state->componentAttached = enginePriv->componentAttached; + if (state->componentAttached) + state->componentAttached->prev = &state->componentAttached; + + enginePriv->componentAttached = 0; + enginePriv->bindValues.clear(); + enginePriv->parserStatus.clear(); + enginePriv->finalizedParserStatus.clear(); + state->completePending = true; + enginePriv->inProgressCreations++; + } +} + +void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state) +{ + if (state->completePending) { + QT_TRY { + for (int ii = 0; ii < state->bindValues.count(); ++ii) { + QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bv = + state->bindValues.at(ii); + for (int jj = 0; jj < bv.count; ++jj) { + if(bv.at(jj)) { + // XXX akennedy + bv.at(jj)->m_mePtr = 0; + bv.at(jj)->setEnabled(true, QDeclarativePropertyPrivate::BypassInterceptor | + QDeclarativePropertyPrivate::DontRemoveBinding); + } + } + QDeclarativeEnginePrivate::clear(bv); + } + + for (int ii = 0; ii < state->parserStatus.count(); ++ii) { + QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> ps = + state->parserStatus.at(ii); + + for (int jj = ps.count - 1; jj >= 0; --jj) { + QDeclarativeParserStatus *status = ps.at(jj); + if (status && status->d) { + status->d = 0; + status->componentComplete(); + } + } + QDeclarativeEnginePrivate::clear(ps); + } + + for (int ii = 0; ii < state->finalizedParserStatus.count(); ++ii) { + QPair<QDeclarativeGuard<QObject>, int> status = state->finalizedParserStatus.at(ii); + QObject *obj = status.first; + if (obj) { + void *args[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, + status.second, args); + } + } + + //componentComplete() can register additional finalization objects + //that are then never handled. Handle them manually here. + if (1 == enginePriv->inProgressCreations) { + for (int ii = 0; ii < enginePriv->finalizedParserStatus.count(); ++ii) { + QPair<QDeclarativeGuard<QObject>, int> status = enginePriv->finalizedParserStatus.at(ii); + QObject *obj = status.first; + if (obj) { + void *args[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, + status.second, args); + } + } + enginePriv->finalizedParserStatus.clear(); + } + + while (state->componentAttached) { + QDeclarativeComponentAttached *a = state->componentAttached; + a->rem(); + QDeclarativeData *d = QDeclarativeData::get(a->parent()); + Q_ASSERT(d); + Q_ASSERT(d->context); + a->add(&d->context->componentAttached); + emit a->completed(); + } + } QT_CATCH(const std::exception&) { + state->bindValues.clear(); + state->parserStatus.clear(); + state->finalizedParserStatus.clear(); + state->completePending = false; + enginePriv->inProgressCreations--; + QT_RETHROW; + } + + state->bindValues.clear(); + state->parserStatus.clear(); + state->finalizedParserStatus.clear(); + state->completePending = false; + + enginePriv->inProgressCreations--; + if (0 == enginePriv->inProgressCreations) { + while (enginePriv->erroredBindings) { + enginePriv->warning(enginePriv->erroredBindings->error); + enginePriv->erroredBindings->removeError(); + } + } + } +} + +/*! + This method provides more advanced control over component instance creation. + In general, programmers should use QDeclarativeComponent::create() to create a + component. + + Complete a component creation begin with QDeclarativeComponent::beginCreate(). +*/ +void QDeclarativeComponent::completeCreate() +{ + Q_D(QDeclarativeComponent); + d->completeCreate(); +} + +void QDeclarativeComponentPrivate::completeCreate() +{ + if (state.completePending) { + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + complete(ep, &state); + + QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Creating); + } +} + +QDeclarativeComponentAttached::QDeclarativeComponentAttached(QObject *parent) +: QObject(parent), prev(0), next(0) +{ +} + +QDeclarativeComponentAttached::~QDeclarativeComponentAttached() +{ + if (prev) *prev = next; + if (next) next->prev = prev; + prev = 0; + next = 0; +} + +/*! + \internal +*/ +QDeclarativeComponentAttached *QDeclarativeComponent::qmlAttachedProperties(QObject *obj) +{ + QDeclarativeComponentAttached *a = new QDeclarativeComponentAttached(obj); + + QDeclarativeEngine *engine = qmlEngine(obj); + if (!engine) + return a; + + if (QDeclarativeEnginePrivate::get(engine)->inBeginCreate) { + QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine); + a->add(&p->componentAttached); + } else { + QDeclarativeData *d = QDeclarativeData::get(obj); + Q_ASSERT(d); + Q_ASSERT(d->context); + a->add(&d->context->componentAttached); + } + + return a; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecomponent.h b/src/declarative/qml/qdeclarativecomponent.h new file mode 100644 index 00000000..50954ad7 --- /dev/null +++ b/src/declarative/qml/qdeclarativecomponent.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECOMPONENT_H +#define QDECLARATIVECOMPONENT_H + +#include <QtDeclarative/qdeclarative.h> +#include <QtDeclarative/qdeclarativeerror.h> + +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeCompiledData; +class QByteArray; +class QDeclarativeComponentPrivate; +class QDeclarativeEngine; +class QDeclarativeComponentAttached; +class Q_DECLARATIVE_EXPORT QDeclarativeComponent : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QDeclarativeComponent) + + Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(QUrl url READ url CONSTANT) + +public: + QDeclarativeComponent(QObject *parent = 0); + QDeclarativeComponent(QDeclarativeEngine *, QObject *parent=0); + QDeclarativeComponent(QDeclarativeEngine *, const QString &fileName, QObject *parent = 0); + QDeclarativeComponent(QDeclarativeEngine *, const QUrl &url, QObject *parent = 0); + virtual ~QDeclarativeComponent(); + + Q_ENUMS(Status) + enum Status { Null, Ready, Loading, Error }; + Status status() const; + + bool isNull() const; + bool isReady() const; + bool isError() const; + bool isLoading() const; + + QList<QDeclarativeError> errors() const; + Q_INVOKABLE QString errorString() const; + + qreal progress() const; + + QUrl url() const; + + virtual QObject *create(QDeclarativeContext *context = 0); + virtual QObject *beginCreate(QDeclarativeContext *); + virtual void completeCreate(); + + void loadUrl(const QUrl &url); + void setData(const QByteArray &, const QUrl &baseUrl); + + QDeclarativeContext *creationContext() const; + + static QDeclarativeComponentAttached *qmlAttachedProperties(QObject *); + +Q_SIGNALS: + void statusChanged(QDeclarativeComponent::Status); + void progressChanged(qreal); + +protected: + QDeclarativeComponent(QDeclarativeComponentPrivate &dd, QObject* parent); + Q_INVOKABLE QScriptValue createObject(QObject* parent); + Q_INVOKABLE Q_REVISION(1) QScriptValue createObject(QObject* parent, const QScriptValue& valuemap); //XXX Versioning + +private: + QDeclarativeComponent(QDeclarativeEngine *, QDeclarativeCompiledData *, int, int, QObject *parent); + + Q_DISABLE_COPY(QDeclarativeComponent) + friend class QDeclarativeVME; + friend class QDeclarativeCompositeTypeData; + friend class QDeclarativeTypeData; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDeclarativeComponent::Status) +QML_DECLARE_TYPE(QDeclarativeComponent) +QML_DECLARE_TYPEINFO(QDeclarativeComponent, QML_HAS_ATTACHED_PROPERTIES) + +QT_END_HEADER + +#endif // QDECLARATIVECOMPONENT_H diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h new file mode 100644 index 00000000..f75999b9 --- /dev/null +++ b/src/declarative/qml/qdeclarativecomponent_p.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECOMPONENT_P_H +#define QDECLARATIVECOMPONENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativecomponent.h" + +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativetypeloader_p.h" +#include "private/qbitfield_p.h" +#include "qdeclarativeerror.h" +#include "qdeclarative.h" + +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QList> + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeComponent; +class QDeclarativeEngine; +class QDeclarativeCompiledData; + +class QDeclarativeComponentAttached; +class Q_AUTOTEST_EXPORT QDeclarativeComponentPrivate : public QObjectPrivate, public QDeclarativeTypeData::TypeDataCallback +{ + Q_DECLARE_PUBLIC(QDeclarativeComponent) + +public: + QDeclarativeComponentPrivate() : typeData(0), progress(0.), start(-1), count(-1), cc(0), engine(0), creationContext(0) {} + + QObject *beginCreate(QDeclarativeContextData *, const QBitField &); + void completeCreate(); + + QDeclarativeTypeData *typeData; + virtual void typeDataReady(QDeclarativeTypeData *); + virtual void typeDataProgress(QDeclarativeTypeData *, qreal); + + void fromTypeData(QDeclarativeTypeData *data); + + QUrl url; + qreal progress; + + int start; + int count; + QDeclarativeCompiledData *cc; + + struct ConstructionState { + ConstructionState() : componentAttached(0), completePending(false) {} + QList<QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> > bindValues; + QList<QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> > parserStatus; + QList<QPair<QDeclarativeGuard<QObject>, int> > finalizedParserStatus; + QDeclarativeComponentAttached *componentAttached; + QList<QDeclarativeError> errors; + bool completePending; + }; + ConstructionState state; + + static QObject *begin(QDeclarativeContextData *parentContext, QDeclarativeContextData *componentCreationContext, + QDeclarativeCompiledData *component, int start, int count, + ConstructionState *state, QList<QDeclarativeError> *errors, + const QBitField &bindings = QBitField()); + static void beginDeferred(QDeclarativeEnginePrivate *enginePriv, QObject *object, + ConstructionState *state); + static void complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state); + + QScriptValue createObject(QObject *publicParent, const QScriptValue valuemap); + + QDeclarativeEngine *engine; + QDeclarativeGuardedContextData creationContext; + + void clear(); + + static QDeclarativeComponentPrivate *get(QDeclarativeComponent *c) { + return static_cast<QDeclarativeComponentPrivate *>(QObjectPrivate::get(c)); + } +}; + +class QDeclarativeComponentAttached : public QObject +{ + Q_OBJECT +public: + QDeclarativeComponentAttached(QObject *parent = 0); + ~QDeclarativeComponentAttached(); + + void add(QDeclarativeComponentAttached **a) { + prev = a; next = *a; *a = this; + if (next) next->prev = &next; + } + void rem() { + if (next) next->prev = prev; + *prev = next; + next = 0; prev = 0; + } + QDeclarativeComponentAttached **prev; + QDeclarativeComponentAttached *next; + +Q_SIGNALS: + void completed(); + void destruction(); + +private: + friend class QDeclarativeContextData; + friend class QDeclarativeComponentPrivate; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVECOMPONENT_P_H diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp new file mode 100644 index 00000000..9132d0e1 --- /dev/null +++ b/src/declarative/qml/qdeclarativecontext.cpp @@ -0,0 +1,774 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativecontext.h" +#include "private/qdeclarativecontext_p.h" + +#include "private/qdeclarativecomponent_p.h" +#include "private/qdeclarativeexpression_p.h" +#include "private/qdeclarativeengine_p.h" +#include "qdeclarativeengine.h" +#include "private/qdeclarativecompiledbindings_p.h" +#include "qdeclarativeinfo.h" +#include "private/qdeclarativeglobalscriptclass_p.h" + +#include <qscriptengine.h> +#include <QtCore/qvarlengtharray.h> +#include <QtCore/qdebug.h> + +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +QDeclarativeContextPrivate::QDeclarativeContextPrivate() +: data(0), notifyIndex(-1) +{ +} + +/*! + \class QDeclarativeContext + \since 4.7 + \brief The QDeclarativeContext class defines a context within a QML engine. + \mainclass + + Contexts allow data to be exposed to the QML components instantiated by the + QML engine. + + Each QDeclarativeContext contains a set of properties, distinct from its QObject + properties, that allow data to be explicitly bound to a context by name. The + context properties are defined and updated by calling + QDeclarativeContext::setContextProperty(). The following example shows a Qt model + being bound to a context and then accessed from a QML file. + + \code + QDeclarativeEngine engine; + QStringListModel modelData; + QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext()); + context->setContextProperty("myModel", &modelData); + + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 1.0\nListView { model: myModel }", QUrl()); + QObject *window = component.create(context); + \endcode + + Note it is the responsibility of the creator to delete any QDeclarativeContext it + constructs. If the \c context object in the example is no longer needed when the + \c window component instance is destroyed, the \c context must be destroyed explicitly. + The simplest way to ensure this is to set \c window as the parent of \c context. + + To simplify binding and maintaining larger data sets, a context object can be set + on a QDeclarativeContext. All the properties of the context object are available + by name in the context, as though they were all individually added through calls + to QDeclarativeContext::setContextProperty(). Changes to the property's values are + detected through the property's notify signal. Setting a context object is both + faster and easier than manually adding and maintaing context property values. + + The following example has the same effect as the previous one, but it uses a context + object. + + \code + class MyDataSet : ... { + ... + Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged) + ... + }; + + MyDataSet myDataSet; + QDeclarativeEngine engine; + QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext()); + context->setContextObject(&myDataSet); + + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 1.0\nListView { model: myModel }", QUrl()); + component.create(context); + \endcode + + All properties added explicitly by QDeclarativeContext::setContextProperty() take + precedence over the context object's properties. + + \section2 The Context Hierarchy + + Contexts form a hierarchy. The root of this hierarchy is the QML engine's + \l {QDeclarativeEngine::rootContext()}{root context}. Child contexts inherit + the context properties of their parents; if a child context sets a context property + that already exists in its parent, the new context property overrides that of the + parent. + + The following example defines two contexts - \c context1 and \c context2. The + second context overrides the "b" context property inherited from the first with a + new value. + + \code + QDeclarativeEngine engine; + QDeclarativeContext *context1 = new QDeclarativeContext(engine.rootContext()); + QDeclarativeContext *context2 = new QDeclarativeContext(context1); + + context1->setContextProperty("a", 12); + context1->setContextProperty("b", 12); + + context2->setContextProperty("b", 15); + \endcode + + While QML objects instantiated in a context are not strictly owned by that + context, their bindings are. If a context is destroyed, the property bindings of + outstanding QML objects will stop evaluating. + + \warning Setting the context object or adding new context properties after an object + has been created in that context is an expensive operation (essentially forcing all bindings + to reevaluate). Thus whenever possible you should complete "setup" of the context + before using it to create any objects. + + \sa {Using QML Bindings in C++ Applications} +*/ + +/*! \internal */ +QDeclarativeContext::QDeclarativeContext(QDeclarativeEngine *e, bool) +: QObject(*(new QDeclarativeContextPrivate)) +{ + Q_D(QDeclarativeContext); + d->data = new QDeclarativeContextData(this); + + d->data->engine = e; +} + +/*! + Create a new QDeclarativeContext as a child of \a engine's root context, and the + QObject \a parent. +*/ +QDeclarativeContext::QDeclarativeContext(QDeclarativeEngine *engine, QObject *parent) +: QObject(*(new QDeclarativeContextPrivate), parent) +{ + Q_D(QDeclarativeContext); + d->data = new QDeclarativeContextData(this); + + d->data->setParent(engine?QDeclarativeContextData::get(engine->rootContext()):0); +} + +/*! + Create a new QDeclarativeContext with the given \a parentContext, and the + QObject \a parent. +*/ +QDeclarativeContext::QDeclarativeContext(QDeclarativeContext *parentContext, QObject *parent) +: QObject(*(new QDeclarativeContextPrivate), parent) +{ + Q_D(QDeclarativeContext); + d->data = new QDeclarativeContextData(this); + + d->data->setParent(parentContext?QDeclarativeContextData::get(parentContext):0); +} + +/*! + \internal +*/ +QDeclarativeContext::QDeclarativeContext(QDeclarativeContextData *data) +: QObject(*(new QDeclarativeContextPrivate), 0) +{ + Q_D(QDeclarativeContext); + d->data = data; +} + +/*! + Destroys the QDeclarativeContext. + + Any expressions, or sub-contexts dependent on this context will be + invalidated, but not destroyed (unless they are parented to the QDeclarativeContext + object). + */ +QDeclarativeContext::~QDeclarativeContext() +{ + Q_D(QDeclarativeContext); + + if (!d->data->isInternal) + d->data->destroy(); +} + +/*! + Returns whether the context is valid. + + To be valid, a context must have a engine, and it's contextObject(), if any, + must not have been deleted. +*/ +bool QDeclarativeContext::isValid() const +{ + Q_D(const QDeclarativeContext); + return d->data && d->data->isValid(); +} + +/*! + Return the context's QDeclarativeEngine, or 0 if the context has no QDeclarativeEngine or the + QDeclarativeEngine was destroyed. +*/ +QDeclarativeEngine *QDeclarativeContext::engine() const +{ + Q_D(const QDeclarativeContext); + return d->data->engine; +} + +/*! + Return the context's parent QDeclarativeContext, or 0 if this context has no + parent or if the parent has been destroyed. +*/ +QDeclarativeContext *QDeclarativeContext::parentContext() const +{ + Q_D(const QDeclarativeContext); + return d->data->parent?d->data->parent->asQDeclarativeContext():0; +} + +/*! + Return the context object, or 0 if there is no context object. +*/ +QObject *QDeclarativeContext::contextObject() const +{ + Q_D(const QDeclarativeContext); + return d->data->contextObject; +} + +/*! + Set the context \a object. +*/ +void QDeclarativeContext::setContextObject(QObject *object) +{ + Q_D(QDeclarativeContext); + + QDeclarativeContextData *data = d->data; + + if (data->isInternal) { + qWarning("QDeclarativeContext: Cannot set context object for internal context."); + return; + } + + if (!isValid()) { + qWarning("QDeclarativeContext: Cannot set context object on invalid context."); + return; + } + + data->contextObject = object; +} + +/*! + Set a the \a value of the \a name property on this context. +*/ +void QDeclarativeContext::setContextProperty(const QString &name, const QVariant &value) +{ + Q_D(QDeclarativeContext); + if (d->notifyIndex == -1) + d->notifyIndex = this->metaObject()->methodCount(); + + QDeclarativeContextData *data = d->data; + + if (data->isInternal) { + qWarning("QDeclarativeContext: Cannot set property on internal context."); + return; + } + + if (!isValid()) { + qWarning("QDeclarativeContext: Cannot set property on invalid context."); + return; + } + + if (data->engine) { + bool ok; + QObject *o = QDeclarativeEnginePrivate::get(data->engine)->toQObject(value, &ok); + if (ok) { + setContextProperty(name, o); + return; + } + } + + if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine); + + int idx = data->propertyNames->value(name); + if (idx == -1) { + data->propertyNames->add(name, data->idValueCount + d->propertyValues.count()); + d->propertyValues.append(value); + + data->refreshExpressions(); + } else { + d->propertyValues[idx] = value; + QMetaObject::activate(this, idx + d->notifyIndex, 0); + } +} + +/*! + Set the \a value of the \a name property on this context. + + QDeclarativeContext does \bold not take ownership of \a value. +*/ +void QDeclarativeContext::setContextProperty(const QString &name, QObject *value) +{ + Q_D(QDeclarativeContext); + if (d->notifyIndex == -1) + d->notifyIndex = this->metaObject()->methodCount(); + + QDeclarativeContextData *data = d->data; + + if (data->isInternal) { + qWarning("QDeclarativeContext: Cannot set property on internal context."); + return; + } + + if (!isValid()) { + qWarning("QDeclarativeContext: Cannot set property on invalid context."); + return; + } + + if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine); + int idx = data->propertyNames->value(name); + + if (idx == -1) { + data->propertyNames->add(name, data->idValueCount + d->propertyValues.count()); + d->propertyValues.append(QVariant::fromValue(value)); + + data->refreshExpressions(); + } else { + d->propertyValues[idx] = QVariant::fromValue(value); + QMetaObject::activate(this, idx + d->notifyIndex, 0); + } +} + +/*! + Returns the value of the \a name property for this context + as a QVariant. + */ +QVariant QDeclarativeContext::contextProperty(const QString &name) const +{ + Q_D(const QDeclarativeContext); + QVariant value; + int idx = -1; + + QDeclarativeContextData *data = d->data; + + if (data->propertyNames) + idx = data->propertyNames->value(name); + + if (idx == -1) { + QByteArray utf8Name = name.toUtf8(); + if (data->contextObject) { + QObject *obj = data->contextObject; + QDeclarativePropertyCache::Data local; + QDeclarativePropertyCache::Data *property = + QDeclarativePropertyCache::property(data->engine, obj, name, local); + + if (property) value = obj->metaObject()->property(property->coreIndex).read(obj); + } + if (!value.isValid() && parentContext()) + value = parentContext()->contextProperty(name); + } else { + if (idx >= d->propertyValues.count()) + value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data()); + else + value = d->propertyValues[idx]; + } + + return value; +} + +/*! + Resolves the URL \a src relative to the URL of the + containing component. + + \sa QDeclarativeEngine::baseUrl(), setBaseUrl() +*/ +QUrl QDeclarativeContext::resolvedUrl(const QUrl &src) +{ + Q_D(QDeclarativeContext); + return d->data->resolvedUrl(src); +} + +QUrl QDeclarativeContextData::resolvedUrl(const QUrl &src) +{ + QDeclarativeContextData *ctxt = this; + + if (src.isRelative() && !src.isEmpty()) { + if (ctxt) { + while(ctxt) { + if(ctxt->url.isValid()) + break; + else + ctxt = ctxt->parent; + } + + if (ctxt) + return ctxt->url.resolved(src); + else if (engine) + return engine->baseUrl().resolved(src); + } + return QUrl(); + } else { + return src; + } +} + + +/*! + Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl. + + Calling this function will override the url of the containing + component used by default. + + \sa resolvedUrl() +*/ +void QDeclarativeContext::setBaseUrl(const QUrl &baseUrl) +{ + Q_D(QDeclarativeContext); + + d->data->url = baseUrl; +} + +/*! + Returns the base url of the component, or the containing component + if none is set. +*/ +QUrl QDeclarativeContext::baseUrl() const +{ + Q_D(const QDeclarativeContext); + const QDeclarativeContextData* data = d->data; + while (data && data->url.isEmpty()) + data = data->parent; + + if (data) + return data->url; + else + return QUrl(); +} + +int QDeclarativeContextPrivate::context_count(QDeclarativeListProperty<QObject> *prop) +{ + QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object); + QDeclarativeContextPrivate *d = QDeclarativeContextPrivate::get(context); + int contextProperty = (int)(quintptr)prop->data; + + if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) { + return 0; + } else { + return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count(); + } +} + +QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject> *prop, int index) +{ + QDeclarativeContext *context = static_cast<QDeclarativeContext*>(prop->object); + QDeclarativeContextPrivate *d = QDeclarativeContextPrivate::get(context); + int contextProperty = (int)(quintptr)prop->data; + + if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) { + return 0; + } else { + return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index); + } +} + + +QDeclarativeContextData::QDeclarativeContextData() +: parent(0), engine(0), isInternal(false), publicContext(0), propertyNames(0), contextObject(0), + imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0), + contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0), + componentAttached(0) +{ +} + +QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt) +: parent(0), engine(0), isInternal(false), publicContext(ctxt), propertyNames(0), contextObject(0), + imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0), + contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0), + componentAttached(0) +{ +} + +void QDeclarativeContextData::invalidate() +{ + while (childContexts) + childContexts->invalidate(); + + while (componentAttached) { + QDeclarativeComponentAttached *a = componentAttached; + componentAttached = a->next; + if (componentAttached) componentAttached->prev = &componentAttached; + + a->next = 0; + a->prev = 0; + + emit a->destruction(); + } + + if (prevChild) { + *prevChild = nextChild; + if (nextChild) nextChild->prevChild = prevChild; + nextChild = 0; + prevChild = 0; + } + + engine = 0; + parent = 0; +} + +void QDeclarativeContextData::clearContext() +{ + if (engine) { + while (componentAttached) { + QDeclarativeComponentAttached *a = componentAttached; + componentAttached = a->next; + if (componentAttached) componentAttached->prev = &componentAttached; + + a->next = 0; + a->prev = 0; + + emit a->destruction(); + } + } + + QDeclarativeAbstractExpression *expression = expressions; + while (expression) { + QDeclarativeAbstractExpression *nextExpression = expression->m_nextExpression; + + expression->m_context = 0; + expression->m_prevExpression = 0; + expression->m_nextExpression = 0; + + expression = nextExpression; + } + expressions = 0; +} + +void QDeclarativeContextData::destroy() +{ + if (linkedContext) + linkedContext->destroy(); + + if (engine) invalidate(); + + clearContext(); + + while (contextObjects) { + QDeclarativeData *co = contextObjects; + contextObjects = contextObjects->nextContextObject; + + co->context = 0; + co->outerContext = 0; + co->nextContextObject = 0; + co->prevContextObject = 0; + } + + QDeclarativeGuardedContextData *contextGuard = contextGuards; + while (contextGuard) { + QDeclarativeGuardedContextData *next = contextGuard->m_next; + contextGuard->m_next = 0; + contextGuard->m_prev = 0; + contextGuard->m_contextData = 0; + contextGuard = next; + } + contextGuards = 0; + + if (propertyNames) + propertyNames->release(); + + if (imports) + imports->release(); + + if (optimizedBindings) + optimizedBindings->release(); + + delete [] idValues; + + if (isInternal) + delete publicContext; + + delete this; +} + +void QDeclarativeContextData::setParent(QDeclarativeContextData *p) +{ + if (p) { + parent = p; + engine = p->engine; + nextChild = p->childContexts; + if (nextChild) nextChild->prevChild = &nextChild; + prevChild = &p->childContexts; + p->childContexts = this; + } +} + +/* +Refreshes all expressions that could possibly depend on this context. Refreshing flushes all +context-tree dependent caches in the expressions, and should occur every time the context tree + *structure* (not values) changes. +*/ +void QDeclarativeContextData::refreshExpressions() +{ + QDeclarativeContextData *child = childContexts; + while (child) { + child->refreshExpressions(); + child = child->nextChild; + } + + QDeclarativeAbstractExpression *expression = expressions; + while (expression) { + expression->refresh(); + expression = expression->m_nextExpression; + } +} + +void QDeclarativeContextData::addObject(QObject *o) +{ + QDeclarativeData *data = QDeclarativeData::get(o, true); + + Q_ASSERT(data->context == 0); + + data->context = this; + data->outerContext = this; + + data->nextContextObject = contextObjects; + if (data->nextContextObject) + data->nextContextObject->prevContextObject = &data->nextContextObject; + data->prevContextObject = &contextObjects; + contextObjects = data; +} + +void QDeclarativeContextData::addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script) +{ + if (!engine) + return; + + QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + const QString &code = script.code; + const QString &url = script.file; + const QDeclarativeParser::Object::ScriptBlock::Pragmas &pragmas = script.pragmas; + + Q_ASSERT(!url.isEmpty()); + + if (pragmas & QDeclarativeParser::Object::ScriptBlock::Shared) { + + QHash<QString, QScriptValue>::Iterator iter = enginePriv->m_sharedScriptImports.find(url); + if (iter == enginePriv->m_sharedScriptImports.end()) { + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); + + scriptContext->pushScope(enginePriv->contextClass->newUrlContext(url)); + scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject()); + + QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine); + scriptContext->pushScope(scope); + + scriptEngine->evaluate(code, url, 1); + + if (scriptEngine->hasUncaughtException()) { + QDeclarativeError error; + QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error); + enginePriv->warning(error); + } + + scriptEngine->popContext(); + + iter = enginePriv->m_sharedScriptImports.insert(url, scope); + } + + importedScripts.append(*iter); + + } else { + + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); + + scriptContext->pushScope(enginePriv->contextClass->newUrlContext(this, 0, url)); + scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject()); + + QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine); + scriptContext->pushScope(scope); + + scriptEngine->evaluate(code, url, 1); + + if (scriptEngine->hasUncaughtException()) { + QDeclarativeError error; + QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error); + enginePriv->warning(error); + } + + scriptEngine->popContext(); + + importedScripts.append(scope); + + } +} + +void QDeclarativeContextData::setIdProperty(int idx, QObject *obj) +{ + idValues[idx] = obj; + idValues[idx].context = this; +} + +void QDeclarativeContextData::setIdPropertyData(QDeclarativeIntegerCache *data) +{ + Q_ASSERT(!propertyNames); + propertyNames = data; + propertyNames->addref(); + + idValueCount = data->count(); + idValues = new ContextGuard[idValueCount]; +} + +QString QDeclarativeContextData::findObjectId(const QObject *obj) const +{ + if (!idValues || !propertyNames) + return QString(); + + for (int i=0; i<idValueCount; i++) { + if (idValues[i] == obj) + return propertyNames->findId(i); + } + + if (linkedContext) + return linkedContext->findObjectId(obj); + return QString(); +} + +QDeclarativeContext *QDeclarativeContextData::asQDeclarativeContext() +{ + if (!publicContext) + publicContext = new QDeclarativeContext(this); + return publicContext; +} + +QDeclarativeContextPrivate *QDeclarativeContextData::asQDeclarativeContextPrivate() +{ + return QDeclarativeContextPrivate::get(asQDeclarativeContext()); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecontext.h b/src/declarative/qml/qdeclarativecontext.h new file mode 100644 index 00000000..d89e1609 --- /dev/null +++ b/src/declarative/qml/qdeclarativecontext.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECONTEXT_H +#define QDECLARATIVECONTEXT_H + +#include <QtCore/qurl.h> +#include <QtCore/qobject.h> +#include <QtScript/qscriptvalue.h> +#include <QtCore/qmetatype.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QString; +class QDeclarativeEngine; +class QDeclarativeRefCount; +class QDeclarativeContextPrivate; +class QDeclarativeCompositeTypeData; +class QDeclarativeContextData; + +class Q_DECLARATIVE_EXPORT QDeclarativeContext : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QDeclarativeContext) + +public: + QDeclarativeContext(QDeclarativeEngine *parent, QObject *objParent=0); + QDeclarativeContext(QDeclarativeContext *parent, QObject *objParent=0); + virtual ~QDeclarativeContext(); + + bool isValid() const; + + QDeclarativeEngine *engine() const; + QDeclarativeContext *parentContext() const; + + QObject *contextObject() const; + void setContextObject(QObject *); + + QVariant contextProperty(const QString &) const; + void setContextProperty(const QString &, QObject *); + void setContextProperty(const QString &, const QVariant &); + + QUrl resolvedUrl(const QUrl &); + + void setBaseUrl(const QUrl &); + QUrl baseUrl() const; + +private: + friend class QDeclarativeVME; + friend class QDeclarativeEngine; + friend class QDeclarativeEnginePrivate; + friend class QDeclarativeExpression; + friend class QDeclarativeExpressionPrivate; + friend class QDeclarativeContextScriptClass; + friend class QDeclarativeObjectScriptClass; + friend class QDeclarativeComponent; + friend class QDeclarativeComponentPrivate; + friend class QDeclarativeScriptPrivate; + friend class QDeclarativeBoundSignalProxy; + friend class QDeclarativeContextData; + QDeclarativeContext(QDeclarativeContextData *); + QDeclarativeContext(QDeclarativeEngine *, bool); + Q_DISABLE_COPY(QDeclarativeContext) +}; +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QList<QObject*>) + +QT_END_HEADER + +#endif // QDECLARATIVECONTEXT_H diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h new file mode 100644 index 00000000..a65fc271 --- /dev/null +++ b/src/declarative/qml/qdeclarativecontext_p.h @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECONTEXT_P_H +#define QDECLARATIVECONTEXT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativecontext.h" + +#include "private/qdeclarativedata_p.h" +#include "private/qdeclarativeintegercache_p.h" +#include "private/qdeclarativetypenamecache_p.h" +#include "private/qdeclarativenotifier_p.h" +#include "qdeclarativelist.h" +#include "private/qdeclarativeparser_p.h" + +#include <QtCore/qhash.h> +#include <QtScript/qscriptvalue.h> +#include <QtCore/qset.h> + +#include <private/qobject_p.h> +#include "private/qdeclarativeguard_p.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativeContext; +class QDeclarativeExpression; +class QDeclarativeEngine; +class QDeclarativeExpression; +class QDeclarativeExpressionPrivate; +class QDeclarativeAbstractExpression; +class QDeclarativeCompiledBindings; +class QDeclarativeContextData; + +class QDeclarativeContextPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QDeclarativeContext) +public: + QDeclarativeContextPrivate(); + + QDeclarativeContextData *data; + + QList<QVariant> propertyValues; + int notifyIndex; + + static QDeclarativeContextPrivate *get(QDeclarativeContext *context) { + return static_cast<QDeclarativeContextPrivate *>(QObjectPrivate::get(context)); + } + static QDeclarativeContext *get(QDeclarativeContextPrivate *context) { + return static_cast<QDeclarativeContext *>(context->q_func()); + } + + // Only used for debugging + QList<QPointer<QObject> > instances; + + static int context_count(QDeclarativeListProperty<QObject> *); + static QObject *context_at(QDeclarativeListProperty<QObject> *, int); +}; + +class QDeclarativeComponentAttached; +class QDeclarativeGuardedContextData; +class Q_AUTOTEST_EXPORT QDeclarativeContextData +{ +public: + QDeclarativeContextData(); + QDeclarativeContextData(QDeclarativeContext *); + void clearContext(); + void destroy(); + void invalidate(); + + inline bool isValid() const { + return engine && (!isInternal || !contextObject || !QObjectPrivate::get(contextObject)->wasDeleted); + } + + // My parent context and engine + QDeclarativeContextData *parent; + QDeclarativeEngine *engine; + + void setParent(QDeclarativeContextData *); + void refreshExpressions(); + + void addObject(QObject *); + + QUrl resolvedUrl(const QUrl &); + + // My containing QDeclarativeContext. If isInternal is true this owns publicContext. + // If internal is false publicContext owns this. + QDeclarativeContext *asQDeclarativeContext(); + QDeclarativeContextPrivate *asQDeclarativeContextPrivate(); + bool isInternal; + QDeclarativeContext *publicContext; + + // Property name cache + QDeclarativeIntegerCache *propertyNames; + + // Context object + QObject *contextObject; + + // Any script blocks that exist on this context + QList<QScriptValue> importedScripts; + void addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script); + + // Context base url + QUrl url; + + // List of imports that apply to this context + QDeclarativeTypeNameCache *imports; + + // My children + QDeclarativeContextData *childContexts; + + // My peers in parent's childContexts list + QDeclarativeContextData *nextChild; + QDeclarativeContextData **prevChild; + + // Expressions that use this context + QDeclarativeAbstractExpression *expressions; + + // Doubly-linked list of objects that are owned by this context + QDeclarativeData *contextObjects; + + // Doubly-linked list of context guards (XXX merge with contextObjects) + QDeclarativeGuardedContextData *contextGuards; + + // id guards + struct ContextGuard : public QDeclarativeGuard<QObject> + { + ContextGuard() : context(0) {} + inline ContextGuard &operator=(QObject *obj) + { QDeclarativeGuard<QObject>::operator=(obj); return *this; } + virtual void objectDestroyed(QObject *) { + if (context->contextObject && !QObjectPrivate::get(context->contextObject)->wasDeleted) bindings.notify(); + } + QDeclarativeContextData *context; + QDeclarativeNotifier bindings; + }; + ContextGuard *idValues; + int idValueCount; + void setIdProperty(int, QObject *); + void setIdPropertyData(QDeclarativeIntegerCache *); + + // Optimized binding pointer + QDeclarativeCompiledBindings *optimizedBindings; + + // Linked contexts. this owns linkedContext. + QDeclarativeContextData *linkedContext; + + // Linked list of uses of the Component attached property in this + // context + QDeclarativeComponentAttached *componentAttached; + + // Return the outermost id for obj, if any. + QString findObjectId(const QObject *obj) const; + + static QDeclarativeContextData *get(QDeclarativeContext *context) { + return QDeclarativeContextPrivate::get(context)->data; + } + +private: + ~QDeclarativeContextData() {} +}; + +class QDeclarativeGuardedContextData +{ +public: + inline QDeclarativeGuardedContextData(); + inline QDeclarativeGuardedContextData(QDeclarativeContextData *); + inline ~QDeclarativeGuardedContextData(); + + inline void setContextData(QDeclarativeContextData *); + + inline QDeclarativeContextData *contextData(); + + inline operator QDeclarativeContextData*() const { return m_contextData; } + inline QDeclarativeContextData* operator->() const { return m_contextData; } + inline QDeclarativeGuardedContextData &operator=(QDeclarativeContextData *d); + +private: + QDeclarativeGuardedContextData &operator=(const QDeclarativeGuardedContextData &); + QDeclarativeGuardedContextData(const QDeclarativeGuardedContextData &); + friend class QDeclarativeContextData; + + inline void clear(); + + QDeclarativeContextData *m_contextData; + QDeclarativeGuardedContextData *m_next; + QDeclarativeGuardedContextData **m_prev; +}; + +QDeclarativeGuardedContextData::QDeclarativeGuardedContextData() +: m_contextData(0), m_next(0), m_prev(0) +{ +} + +QDeclarativeGuardedContextData::QDeclarativeGuardedContextData(QDeclarativeContextData *data) +: m_contextData(0), m_next(0), m_prev(0) +{ + setContextData(data); +} + +QDeclarativeGuardedContextData::~QDeclarativeGuardedContextData() +{ + clear(); +} + +void QDeclarativeGuardedContextData::setContextData(QDeclarativeContextData *contextData) +{ + clear(); + + if (contextData) { + m_contextData = contextData; + m_next = contextData->contextGuards; + if (m_next) m_next->m_prev = &m_next; + m_prev = &contextData->contextGuards; + contextData->contextGuards = this; + } +} + +QDeclarativeContextData *QDeclarativeGuardedContextData::contextData() +{ + return m_contextData; +} + +void QDeclarativeGuardedContextData::clear() +{ + if (m_prev) { + *m_prev = m_next; + if (m_next) m_next->m_prev = m_prev; + m_contextData = 0; + m_next = 0; + m_prev = 0; + } +} + +QDeclarativeGuardedContextData & +QDeclarativeGuardedContextData::operator=(QDeclarativeContextData *d) +{ + setContextData(d); + return *this; +} + +QT_END_NAMESPACE + +#endif // QDECLARATIVECONTEXT_P_H diff --git a/src/declarative/qml/qdeclarativecontextscriptclass.cpp b/src/declarative/qml/qdeclarativecontextscriptclass.cpp new file mode 100644 index 00000000..c3b40273 --- /dev/null +++ b/src/declarative/qml/qdeclarativecontextscriptclass.cpp @@ -0,0 +1,335 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativecontextscriptclass_p.h" + +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativetypenamescriptclass_p.h" +#include "private/qdeclarativelistscriptclass_p.h" +#include "private/qdeclarativeguard_p.h" + +QT_BEGIN_NAMESPACE + +struct ContextData : public QScriptDeclarativeClass::Object { + ContextData() : overrideObject(0), isSharedContext(true) {} + ContextData(QDeclarativeContextData *c, QObject *o) + : context(c), scopeObject(o), overrideObject(0), isSharedContext(false), isUrlContext(false) {} + QDeclarativeGuardedContextData context; + QDeclarativeGuard<QObject> scopeObject; + QObject *overrideObject; + bool isSharedContext:1; + bool isUrlContext:1; + + QDeclarativeContextData *getContext(QDeclarativeEngine *engine) { + if (isSharedContext) { + return QDeclarativeEnginePrivate::get(engine)->sharedContext; + } else { + return context.contextData(); + } + } + + QObject *getScope(QDeclarativeEngine *engine) { + if (isSharedContext) { + return QDeclarativeEnginePrivate::get(engine)->sharedScope; + } else { + return scopeObject.data(); + } + } +}; + +struct UrlContextData : public ContextData { + UrlContextData(QDeclarativeContextData *c, QObject *o, const QString &u) + : ContextData(c, o), url(u) { + isUrlContext = true; + } + UrlContextData(const QString &u) + : ContextData(0, 0), url(u) { + isUrlContext = true; + } + QString url; +}; + +/* + The QDeclarativeContextScriptClass handles property access for a QDeclarativeContext + via QtScript. + */ +QDeclarativeContextScriptClass::QDeclarativeContextScriptClass(QDeclarativeEngine *bindEngine) +: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine), + lastScopeObject(0), lastContext(0), lastData(0), lastPropertyIndex(-1) +{ +} + +QDeclarativeContextScriptClass::~QDeclarativeContextScriptClass() +{ +} + +QScriptValue QDeclarativeContextScriptClass::newContext(QDeclarativeContextData *context, QObject *scopeObject) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, new ContextData(context, scopeObject)); +} + +QScriptValue QDeclarativeContextScriptClass::newUrlContext(QDeclarativeContextData *context, QObject *scopeObject, + const QString &url) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, new UrlContextData(context, scopeObject, url)); +} + +QScriptValue QDeclarativeContextScriptClass::newUrlContext(const QString &url) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, new UrlContextData(url)); +} + +QScriptValue QDeclarativeContextScriptClass::newSharedContext() +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, new ContextData()); +} + +QDeclarativeContextData *QDeclarativeContextScriptClass::contextFromValue(const QScriptValue &v) +{ + if (scriptClass(v) != this) + return 0; + + ContextData *data = (ContextData *)object(v); + return data->getContext(engine); +} + +QUrl QDeclarativeContextScriptClass::urlFromValue(const QScriptValue &v) +{ + if (scriptClass(v) != this) + return QUrl(); + + ContextData *data = (ContextData *)object(v); + if (data->isUrlContext) { + return QUrl(static_cast<UrlContextData *>(data)->url); + } else { + return QUrl(); + } +} + +QObject *QDeclarativeContextScriptClass::setOverrideObject(QScriptValue &v, QObject *override) +{ + if (scriptClass(v) != this) + return 0; + + ContextData *data = (ContextData *)object(v); + QObject *rv = data->overrideObject; + data->overrideObject = override; + return rv; +} + +QScriptClass::QueryFlags +QDeclarativeContextScriptClass::queryProperty(Object *object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + + lastScopeObject = 0; + lastContext = 0; + lastData = 0; + lastPropertyIndex = -1; + + QDeclarativeContextData *bindContext = ((ContextData *)object)->getContext(engine); + QObject *scopeObject = ((ContextData *)object)->getScope(engine); + if (!bindContext) + return 0; + + QObject *overrideObject = ((ContextData *)object)->overrideObject; + if (overrideObject) { + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + QScriptClass::QueryFlags rv = + ep->objectClass->queryProperty(overrideObject, name, flags, bindContext, + QDeclarativeObjectScriptClass::ImplicitObject | + QDeclarativeObjectScriptClass::SkipAttachedProperties); + if (rv) { + lastScopeObject = overrideObject; + lastContext = bindContext; + return rv; + } + } + + bool includeTypes = true; + while (bindContext) { + QScriptClass::QueryFlags rv = + queryProperty(bindContext, scopeObject, name, flags, includeTypes); + scopeObject = 0; // Only applies to the first context + includeTypes = false; // Only applies to the first context + if (rv) return rv; + bindContext = bindContext->parent; + } + + return 0; +} + +QScriptClass::QueryFlags +QDeclarativeContextScriptClass::queryProperty(QDeclarativeContextData *bindContext, QObject *scopeObject, + const Identifier &name, + QScriptClass::QueryFlags flags, + bool includeTypes) +{ + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + + lastPropertyIndex = bindContext->propertyNames?bindContext->propertyNames->value(name):-1; + if (lastPropertyIndex != -1) { + lastContext = bindContext; + return QScriptClass::HandlesReadAccess; + } + + if (includeTypes && bindContext->imports) { + QDeclarativeTypeNameCache::Data *data = bindContext->imports->data(name); + + if (data) { + lastData = data; + lastContext = bindContext; + lastScopeObject = scopeObject; + return QScriptClass::HandlesReadAccess; + } + } + + if (scopeObject) { + QScriptClass::QueryFlags rv = + ep->objectClass->queryProperty(scopeObject, name, flags, bindContext, + QDeclarativeObjectScriptClass::ImplicitObject | QDeclarativeObjectScriptClass::SkipAttachedProperties); + if (rv) { + lastScopeObject = scopeObject; + lastContext = bindContext; + return rv; + } + } + + if (bindContext->contextObject) { + QScriptClass::QueryFlags rv = + ep->objectClass->queryProperty(bindContext->contextObject, name, flags, bindContext, + QDeclarativeObjectScriptClass::ImplicitObject | QDeclarativeObjectScriptClass::SkipAttachedProperties); + + if (rv) { + lastScopeObject = bindContext->contextObject; + lastContext = bindContext; + return rv; + } + } + + return 0; +} + +QDeclarativeContextScriptClass::Value +QDeclarativeContextScriptClass::property(Object *object, const Identifier &name) +{ + Q_UNUSED(object); + + QDeclarativeContextData *bindContext = lastContext; + Q_ASSERT(bindContext); + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + if (lastData) { + + if (lastData->type) { + return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->type)); + } else if (lastData->typeNamespace) { + return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->typeNamespace)); + } else { + int index = lastData->importedScriptIndex; + if (index < bindContext->importedScripts.count()) { + return Value(scriptEngine, bindContext->importedScripts.at(index)); + } else { + return Value(); + } + } + + } else if (lastScopeObject) { + + return ep->objectClass->property(lastScopeObject, name); + + } else if (lastPropertyIndex != -1) { + + QScriptValue rv; + if (lastPropertyIndex < bindContext->idValueCount) { + rv = ep->objectClass->newQObject(bindContext->idValues[lastPropertyIndex].data()); + + if (ep->captureProperties) + ep->capturedProperties << QDeclarativeEnginePrivate::CapturedProperty(&bindContext->idValues[lastPropertyIndex].bindings); + } else { + QDeclarativeContextPrivate *cp = bindContext->asQDeclarativeContextPrivate(); + const QVariant &value = cp->propertyValues.at(lastPropertyIndex); + if (value.userType() == qMetaTypeId<QList<QObject*> >()) { + rv = ep->listClass->newList(QDeclarativeListProperty<QObject>(bindContext->asQDeclarativeContext(), (void*)lastPropertyIndex, 0, QDeclarativeContextPrivate::context_count, QDeclarativeContextPrivate::context_at), qMetaTypeId<QDeclarativeListProperty<QObject> >()); + } else { + rv = ep->scriptValueFromVariant(value); + } + + if (ep->captureProperties) + ep->capturedProperties << QDeclarativeEnginePrivate::CapturedProperty(bindContext->asQDeclarativeContext(), -1, lastPropertyIndex + cp->notifyIndex); + } + + return Value(scriptEngine, rv); + + } else { + + return Value(scriptEngine, lastFunction); + + } +} + +void QDeclarativeContextScriptClass::setProperty(Object *object, const Identifier &name, + const QScriptValue &value) +{ + Q_UNUSED(object); + Q_ASSERT(lastScopeObject); + + QDeclarativeContextData *bindContext = lastContext; + Q_ASSERT(bindContext); + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + + ep->objectClass->setProperty(lastScopeObject, name, value, context(), bindContext); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecontextscriptclass_p.h b/src/declarative/qml/qdeclarativecontextscriptclass_p.h new file mode 100644 index 00000000..6b288d69 --- /dev/null +++ b/src/declarative/qml/qdeclarativecontextscriptclass_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECONTEXTSCRIPTCLASS_P_H +#define QDECLARATIVECONTEXTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativetypenamecache_p.h" +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeEngine; +class QDeclarativeContext; +class QDeclarativeContextData; +class QDeclarativeContextScriptClass : public QScriptDeclarativeClass +{ +public: + QDeclarativeContextScriptClass(QDeclarativeEngine *); + ~QDeclarativeContextScriptClass(); + + QScriptValue newContext(QDeclarativeContextData *, QObject * = 0); + QScriptValue newUrlContext(QDeclarativeContextData *, QObject *, const QString &); + QScriptValue newUrlContext(const QString &); + QScriptValue newSharedContext(); + + QDeclarativeContextData *contextFromValue(const QScriptValue &); + QUrl urlFromValue(const QScriptValue &); + + QObject *setOverrideObject(QScriptValue &, QObject *); + +protected: + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + virtual Value property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); + +private: + QScriptClass::QueryFlags queryProperty(QDeclarativeContextData *, QObject *scopeObject, + const Identifier &, + QScriptClass::QueryFlags flags, + bool includeTypes); + + QDeclarativeEngine *engine; + + QObject *lastScopeObject; + QDeclarativeContextData *lastContext; + QDeclarativeTypeNameCache::Data *lastData; + int lastPropertyIndex; + QScriptValue lastFunction; + + uint m_id; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVECONTEXTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qdeclarativecustomparser.cpp b/src/declarative/qml/qdeclarativecustomparser.cpp new file mode 100644 index 00000000..b6a25830 --- /dev/null +++ b/src/declarative/qml/qdeclarativecustomparser.cpp @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativecustomparser_p.h" +#include "private/qdeclarativecustomparser_p_p.h" + +#include "private/qdeclarativeparser_p.h" +#include "private/qdeclarativecompiler_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace QDeclarativeParser; + +/*! + \class QDeclarativeCustomParser + \brief The QDeclarativeCustomParser class allows you to add new arbitrary types to QML. + \internal + + By subclassing QDeclarativeCustomParser, you can add a parser for + building a particular type. + + The subclass must implement compile() and setCustomData(), and register + itself in the meta type system by calling the macro: + + \code + QML_REGISTER_CUSTOM_TYPE(Module, MajorVersion, MinorVersion, Name, TypeClass, ParserClass) + \endcode +*/ + +/* + \fn QByteArray QDeclarativeCustomParser::compile(const QList<QDeclarativeCustomParserProperty> & properties) + + The custom parser processes \a properties, and returns + a QByteArray containing data meaningful only to the + custom parser; the type engine will pass this same data to + setCustomData() when making an instance of the data. + + Errors must be reported via the error() functions. + + The QByteArray may be cached between executions of the system, so + it must contain correctly-serialized data (not, for example, + pointers to stack objects). +*/ + +/* + \fn void QDeclarativeCustomParser::setCustomData(QObject *object, const QByteArray &data) + + This function sets \a object to have the properties defined + by \a data, which is a block of data previously returned by a call + to compile(). + + Errors should be reported using qmlInfo(object). + + The \a object will be an instance of the TypeClass specified by QML_REGISTER_CUSTOM_TYPE. +*/ + +QDeclarativeCustomParserNode +QDeclarativeCustomParserNodePrivate::fromObject(QDeclarativeParser::Object *root) +{ + QDeclarativeCustomParserNode rootNode; + rootNode.d->name = root->typeName; + rootNode.d->location = root->location.start; + + for(QHash<QByteArray, Property *>::Iterator iter = root->properties.begin(); + iter != root->properties.end(); + ++iter) { + + Property *p = *iter; + + rootNode.d->properties << fromProperty(p); + } + + if (root->defaultProperty) + rootNode.d->properties << fromProperty(root->defaultProperty); + + return rootNode; +} + +QDeclarativeCustomParserProperty +QDeclarativeCustomParserNodePrivate::fromProperty(QDeclarativeParser::Property *p) +{ + QDeclarativeCustomParserProperty prop; + prop.d->name = p->name; + prop.d->isList = (p->values.count() > 1); + prop.d->location = p->location.start; + + if (p->value) { + QDeclarativeCustomParserNode node = fromObject(p->value); + QList<QDeclarativeCustomParserProperty> props = node.properties(); + for (int ii = 0; ii < props.count(); ++ii) + prop.d->values << QVariant::fromValue(props.at(ii)); + } else { + for(int ii = 0; ii < p->values.count(); ++ii) { + QDeclarativeParser::Value *v = p->values.at(ii); + v->type = QDeclarativeParser::Value::Literal; + + if(v->object) { + QDeclarativeCustomParserNode node = fromObject(v->object); + prop.d->values << QVariant::fromValue(node); + } else { + prop.d->values << QVariant::fromValue(v->value); + } + + } + } + + return prop; +} + +QDeclarativeCustomParserNode::QDeclarativeCustomParserNode() +: d(new QDeclarativeCustomParserNodePrivate) +{ +} + +QDeclarativeCustomParserNode::QDeclarativeCustomParserNode(const QDeclarativeCustomParserNode &other) +: d(new QDeclarativeCustomParserNodePrivate) +{ + *this = other; +} + +QDeclarativeCustomParserNode &QDeclarativeCustomParserNode::operator=(const QDeclarativeCustomParserNode &other) +{ + d->name = other.d->name; + d->properties = other.d->properties; + d->location = other.d->location; + return *this; +} + +QDeclarativeCustomParserNode::~QDeclarativeCustomParserNode() +{ + delete d; d = 0; +} + +QByteArray QDeclarativeCustomParserNode::name() const +{ + return d->name; +} + +QList<QDeclarativeCustomParserProperty> QDeclarativeCustomParserNode::properties() const +{ + return d->properties; +} + +QDeclarativeParser::Location QDeclarativeCustomParserNode::location() const +{ + return d->location; +} + +QDeclarativeCustomParserProperty::QDeclarativeCustomParserProperty() +: d(new QDeclarativeCustomParserPropertyPrivate) +{ +} + +QDeclarativeCustomParserProperty::QDeclarativeCustomParserProperty(const QDeclarativeCustomParserProperty &other) +: d(new QDeclarativeCustomParserPropertyPrivate) +{ + *this = other; +} + +QDeclarativeCustomParserProperty &QDeclarativeCustomParserProperty::operator=(const QDeclarativeCustomParserProperty &other) +{ + d->name = other.d->name; + d->isList = other.d->isList; + d->values = other.d->values; + d->location = other.d->location; + return *this; +} + +QDeclarativeCustomParserProperty::~QDeclarativeCustomParserProperty() +{ + delete d; d = 0; +} + +QByteArray QDeclarativeCustomParserProperty::name() const +{ + return d->name; +} + +bool QDeclarativeCustomParserProperty::isList() const +{ + return d->isList; +} + +QDeclarativeParser::Location QDeclarativeCustomParserProperty::location() const +{ + return d->location; +} + +QList<QVariant> QDeclarativeCustomParserProperty::assignedValues() const +{ + return d->values; +} + +void QDeclarativeCustomParser::clearErrors() +{ + exceptions.clear(); +} + +/*! + Reports an error with the given \a description. + + This can only be used during the compile() step. For errors during setCustomData(), use qmlInfo(). + + An error is generated referring to the position of the element in the source file. +*/ +void QDeclarativeCustomParser::error(const QString& description) +{ + Q_ASSERT(object); + QDeclarativeError error; + QString exceptionDescription; + error.setLine(object->location.start.line); + error.setColumn(object->location.start.column); + error.setDescription(description); + exceptions << error; +} + +/*! + Reports an error in parsing \a prop, with the given \a description. + + An error is generated referring to the position of \a node in the source file. +*/ +void QDeclarativeCustomParser::error(const QDeclarativeCustomParserProperty& prop, const QString& description) +{ + QDeclarativeError error; + QString exceptionDescription; + error.setLine(prop.location().line); + error.setColumn(prop.location().column); + error.setDescription(description); + exceptions << error; +} + +/*! + Reports an error in parsing \a node, with the given \a description. + + An error is generated referring to the position of \a node in the source file. +*/ +void QDeclarativeCustomParser::error(const QDeclarativeCustomParserNode& node, const QString& description) +{ + QDeclarativeError error; + QString exceptionDescription; + error.setLine(node.location().line); + error.setColumn(node.location().column); + error.setDescription(description); + exceptions << error; +} + +/*! + If \a script is a simply enum expression (eg. Text.AlignLeft), + returns the integer equivalent (eg. 1). + + Otherwise, returns -1. +*/ +int QDeclarativeCustomParser::evaluateEnum(const QByteArray& script) const +{ + return compiler->evaluateEnum(script); +} + +/*! + Resolves \a name to a type, or 0 if it is not a type. This can be used + to type-check object nodes. +*/ +const QMetaObject *QDeclarativeCustomParser::resolveType(const QByteArray& name) const +{ + return compiler->resolveType(name); +} + +/*! + Rewrites \a expression and returns an identifier that can be + used to construct the binding later. \a name + is used as the name of the rewritten function. +*/ +QDeclarativeBinding::Identifier QDeclarativeCustomParser::rewriteBinding(const QString& expression, const QByteArray& name) +{ + return compiler->rewriteBinding(expression, name); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecustomparser_p.h b/src/declarative/qml/qdeclarativecustomparser_p.h new file mode 100644 index 00000000..41b52258 --- /dev/null +++ b/src/declarative/qml/qdeclarativecustomparser_p.h @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECUSTOMPARSER_H +#define QDECLARATIVECUSTOMPARSER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativemetatype_p.h" +#include "qdeclarativeerror.h" +#include "private/qdeclarativeparser_p.h" +#include "private/qdeclarativebinding_p.h" + +#include <QtCore/qbytearray.h> +#include <QtCore/qxmlstream.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeCompiler; + +class QDeclarativeCustomParserPropertyPrivate; +class Q_DECLARATIVE_EXPORT QDeclarativeCustomParserProperty +{ +public: + QDeclarativeCustomParserProperty(); + QDeclarativeCustomParserProperty(const QDeclarativeCustomParserProperty &); + QDeclarativeCustomParserProperty &operator=(const QDeclarativeCustomParserProperty &); + ~QDeclarativeCustomParserProperty(); + + QByteArray name() const; + QDeclarativeParser::Location location() const; + + bool isList() const; + // Will be one of QDeclarativeParser::Variant, QDeclarativeCustomParserProperty or + // QDeclarativeCustomParserNode + QList<QVariant> assignedValues() const; + +private: + friend class QDeclarativeCustomParserNodePrivate; + friend class QDeclarativeCustomParserPropertyPrivate; + QDeclarativeCustomParserPropertyPrivate *d; +}; + +class QDeclarativeCustomParserNodePrivate; +class Q_DECLARATIVE_EXPORT QDeclarativeCustomParserNode +{ +public: + QDeclarativeCustomParserNode(); + QDeclarativeCustomParserNode(const QDeclarativeCustomParserNode &); + QDeclarativeCustomParserNode &operator=(const QDeclarativeCustomParserNode &); + ~QDeclarativeCustomParserNode(); + + QByteArray name() const; + QDeclarativeParser::Location location() const; + + QList<QDeclarativeCustomParserProperty> properties() const; + +private: + friend class QDeclarativeCustomParserNodePrivate; + QDeclarativeCustomParserNodePrivate *d; +}; + +class Q_DECLARATIVE_EXPORT QDeclarativeCustomParser +{ +public: + enum Flag { + NoFlag = 0x00000000, + AcceptsAttachedProperties = 0x00000001 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + QDeclarativeCustomParser() : compiler(0), object(0), m_flags(NoFlag) {} + QDeclarativeCustomParser(Flags f) : compiler(0), object(0), m_flags(f) {} + virtual ~QDeclarativeCustomParser() {} + + void clearErrors(); + Flags flags() const { return m_flags; } + + virtual QByteArray compile(const QList<QDeclarativeCustomParserProperty> &)=0; + virtual void setCustomData(QObject *, const QByteArray &)=0; + + QList<QDeclarativeError> errors() const { return exceptions; } + +protected: + void error(const QString& description); + void error(const QDeclarativeCustomParserProperty&, const QString& description); + void error(const QDeclarativeCustomParserNode&, const QString& description); + + int evaluateEnum(const QByteArray&) const; + + const QMetaObject *resolveType(const QByteArray&) const; + + QDeclarativeBinding::Identifier rewriteBinding(const QString&, const QByteArray&); + +private: + QList<QDeclarativeError> exceptions; + QDeclarativeCompiler *compiler; + QDeclarativeParser::Object *object; + Flags m_flags; + friend class QDeclarativeCompiler; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeCustomParser::Flags); + +#if 0 +#define QML_REGISTER_CUSTOM_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, CUSTOMTYPE) \ + qmlRegisterCustomType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE, new CUSTOMTYPE) +#endif + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDeclarativeCustomParserProperty) +Q_DECLARE_METATYPE(QDeclarativeCustomParserNode) + +QT_END_HEADER + +#endif diff --git a/src/declarative/qml/qdeclarativecustomparser_p_p.h b/src/declarative/qml/qdeclarativecustomparser_p_p.h new file mode 100644 index 00000000..3f96a835 --- /dev/null +++ b/src/declarative/qml/qdeclarativecustomparser_p_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECUSTOMPARSER_P_H +#define QDECLARATIVECUSTOMPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativecustomparser_p.h" + +#include "private/qdeclarativeparser_p.h" + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeCustomParserNodePrivate +{ +public: + QByteArray name; + QList<QDeclarativeCustomParserProperty> properties; + QDeclarativeParser::Location location; + + static QDeclarativeCustomParserNode fromObject(QDeclarativeParser::Object *); + static QDeclarativeCustomParserProperty fromProperty(QDeclarativeParser::Property *); +}; + +class QDeclarativeCustomParserPropertyPrivate +{ +public: + QDeclarativeCustomParserPropertyPrivate() + : isList(false) {} + + QByteArray name; + bool isList; + QDeclarativeParser::Location location; + QList<QVariant> values; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVECUSTOMPARSER_P_H diff --git a/src/declarative/qml/qdeclarativedata_p.h b/src/declarative/qml/qdeclarativedata_p.h new file mode 100644 index 00000000..b26c4d51 --- /dev/null +++ b/src/declarative/qml/qdeclarativedata_p.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEDATA_P_H +#define QDECLARATIVEDATA_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtScript/qscriptvalue.h> +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeGuardImpl; +class QDeclarativeCompiledData; +class QDeclarativeAbstractBinding; +class QDeclarativeContext; +class QDeclarativePropertyCache; +class QDeclarativeContextData; +class QDeclarativeNotifier; +class QDeclarativeDataExtended; +// This class is structured in such a way, that simply zero'ing it is the +// default state for elemental object allocations. This is crucial in the +// workings of the QDeclarativeInstruction::CreateSimpleObject instruction. +// Don't change anything here without first considering that case! +class Q_AUTOTEST_EXPORT QDeclarativeData : public QAbstractDeclarativeData +{ +public: + QDeclarativeData() + : ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), + context(0), outerContext(0), bindings(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), + bindingBits(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), + scriptValue(0), objectDataRefCount(0), propertyCache(0), guards(0), extendedData(0) { + init(); + } + + static inline void init() { + QAbstractDeclarativeData::destroyed = destroyed; + QAbstractDeclarativeData::parentChanged = parentChanged; + QAbstractDeclarativeData::objectNameChanged = objectNameChanged; + } + + static void destroyed(QAbstractDeclarativeData *, QObject *); + static void parentChanged(QAbstractDeclarativeData *, QObject *, QObject *); + static void objectNameChanged(QAbstractDeclarativeData *, QObject *); + + void destroyed(QObject *); + void parentChanged(QObject *, QObject *); + void objectNameChanged(QObject *); + + void setImplicitDestructible() { + if (!explicitIndestructibleSet) indestructible = false; + } + + quint32 ownMemory:1; + quint32 ownContext:1; + quint32 indestructible:1; + quint32 explicitIndestructibleSet:1; + quint32 dummy:28; + + // The context that created the C++ object + QDeclarativeContextData *context; + // The outermost context in which this object lives + QDeclarativeContextData *outerContext; + + QDeclarativeAbstractBinding *bindings; + + // Linked list for QDeclarativeContext::contextObjects + QDeclarativeData *nextContextObject; + QDeclarativeData**prevContextObject; + + int bindingBitsSize; + quint32 *bindingBits; + bool hasBindingBit(int) const; + void clearBindingBit(int); + void setBindingBit(QObject *obj, int); + + ushort lineNumber; + ushort columnNumber; + + QDeclarativeCompiledData *deferredComponent; // Can't this be found from the context? + unsigned int deferredIdx; + + // ### Can we make this QScriptValuePrivate so we incur no additional allocation + // cost? + QScriptValue *scriptValue; + quint32 objectDataRefCount; + QDeclarativePropertyCache *propertyCache; + + QDeclarativeGuardImpl *guards; + + static QDeclarativeData *get(const QObject *object, bool create = false) { + QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object)); + if (priv->wasDeleted) { + Q_ASSERT(!create); + return 0; + } else if (priv->declarativeData) { + return static_cast<QDeclarativeData *>(priv->declarativeData); + } else if (create) { + priv->declarativeData = new QDeclarativeData; + return static_cast<QDeclarativeData *>(priv->declarativeData); + } else { + return 0; + } + } + + bool hasExtendedData() const { return extendedData != 0; } + QDeclarativeNotifier *objectNameNotifier() const; + QHash<int, QObject *> *attachedProperties() const; + +private: + // For objectNameNotifier and attachedProperties + mutable QDeclarativeDataExtended *extendedData; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEDATA_P_H diff --git a/src/declarative/qml/qdeclarativedirparser.cpp b/src/declarative/qml/qdeclarativedirparser.cpp new file mode 100644 index 00000000..16bc2c3e --- /dev/null +++ b/src/declarative/qml/qdeclarativedirparser.cpp @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativedirparser_p.h" +#include "qdeclarativeerror.h" +#include <private/qdeclarativeglobal_p.h> + +#include <QtCore/QTextStream> +#include <QtCore/QFile> +#include <QtCore/QtDebug> + +QT_BEGIN_NAMESPACE + +QDeclarativeDirParser::QDeclarativeDirParser() + : _isParsed(false) +{ +} + +QDeclarativeDirParser::~QDeclarativeDirParser() +{ +} + +QUrl QDeclarativeDirParser::url() const +{ + return _url; +} + +void QDeclarativeDirParser::setUrl(const QUrl &url) +{ + _url = url; +} + +QString QDeclarativeDirParser::fileSource() const +{ + return _filePathSouce; +} + +void QDeclarativeDirParser::setFileSource(const QString &filePath) +{ + _filePathSouce = filePath; +} + +QString QDeclarativeDirParser::source() const +{ + return _source; +} + +void QDeclarativeDirParser::setSource(const QString &source) +{ + _isParsed = false; + _source = source; +} + +bool QDeclarativeDirParser::isParsed() const +{ + return _isParsed; +} + +bool QDeclarativeDirParser::parse() +{ + if (_isParsed) + return true; + + _isParsed = true; + _errors.clear(); + _plugins.clear(); + _components.clear(); + + if (_source.isEmpty() && !_filePathSouce.isEmpty()) { + QFile file(_filePathSouce); + if (!QDeclarative_isFileCaseCorrect(_filePathSouce)) { + QDeclarativeError error; + error.setDescription(QString::fromUtf8("cannot load module \"$$URI$$\": File name case mismatch for \"%1\"").arg(_filePathSouce)); + _errors.prepend(error); + return false; + } else if (file.open(QFile::ReadOnly)) { + _source = QString::fromUtf8(file.readAll()); + } else { + QDeclarativeError error; + error.setDescription(QString::fromUtf8("module \"$$URI$$\" definition \"%1\" not readable").arg(_filePathSouce)); + _errors.prepend(error); + return false; + } + } + + QTextStream stream(&_source); + int lineNumber = 0; + + forever { + ++lineNumber; + + const QString line = stream.readLine(); + if (line.isNull()) + break; + + QString sections[3]; + int sectionCount = 0; + + int index = 0; + const int length = line.length(); + + while (index != length) { + const QChar ch = line.at(index); + + if (ch.isSpace()) { + do { ++index; } + while (index != length && line.at(index).isSpace()); + + } else if (ch == QLatin1Char('#')) { + // recognized a comment + break; + + } else { + const int start = index; + + do { ++index; } + while (index != length && !line.at(index).isSpace()); + + const QString lexeme = line.mid(start, index - start); + + if (sectionCount >= 3) { + reportError(lineNumber, start, QLatin1String("unexpected token")); + + } else { + sections[sectionCount++] = lexeme; + } + } + } + + if (sectionCount == 0) { + continue; // no sections, no party. + + } else if (sections[0] == QLatin1String("plugin")) { + if (sectionCount < 2) { + reportError(lineNumber, -1, + QString::fromUtf8("plugin directive requires 2 arguments, but %1 were provided").arg(sectionCount + 1)); + + continue; + } + + const Plugin entry(sections[1], sections[2]); + + _plugins.append(entry); + + } else if (sections[0] == QLatin1String("internal")) { + if (sectionCount != 3) { + reportError(lineNumber, -1, + QString::fromUtf8("internal types require 2 arguments, but %1 were provided").arg(sectionCount + 1)); + continue; + } + Component entry(sections[1], sections[2], -1, -1); + entry.internal = true; + _components.append(entry); + } else if (sections[0] == QLatin1String("typeinfo")) { + if (sectionCount != 2) { + reportError(lineNumber, -1, + QString::fromUtf8("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1)); + continue; + } +#ifdef QT_CREATOR + TypeInfo typeInfo(sections[1]); + _typeInfos.append(typeInfo); +#endif + + } else if (sectionCount == 2) { + // No version specified (should only be used for relative qmldir files) + const Component entry(sections[0], sections[1], -1, -1); + _components.append(entry); + } else if (sectionCount == 3) { + const QString &version = sections[1]; + const int dotIndex = version.indexOf(QLatin1Char('.')); + + if (dotIndex == -1) { + reportError(lineNumber, -1, QLatin1String("expected '.'")); + } else if (version.indexOf(QLatin1Char('.'), dotIndex + 1) != -1) { + reportError(lineNumber, -1, QLatin1String("unexpected '.'")); + } else { + bool validVersionNumber = false; + const int majorVersion = version.left(dotIndex).toInt(&validVersionNumber); + + if (validVersionNumber) { + const int minorVersion = version.mid(dotIndex + 1).toInt(&validVersionNumber); + + if (validVersionNumber) { + const Component entry(sections[0], sections[2], majorVersion, minorVersion); + + _components.append(entry); + } + } + } + } else { + reportError(lineNumber, -1, + QString::fromUtf8("a component declaration requires 3 arguments, but %1 were provided").arg(sectionCount + 1)); + } + } + + return hasError(); +} + +void QDeclarativeDirParser::reportError(int line, int column, const QString &description) +{ + QDeclarativeError error; + error.setUrl(_url); + error.setLine(line); + error.setColumn(column); + error.setDescription(description); + _errors.append(error); +} + +bool QDeclarativeDirParser::hasError() const +{ + if (! _errors.isEmpty()) + return true; + + return false; +} + +QList<QDeclarativeError> QDeclarativeDirParser::errors(const QString &uri) const +{ + QList<QDeclarativeError> errors = _errors; + for (int i = 0; i < errors.size(); ++i) { + QDeclarativeError &e = errors[i]; + QString description = e.description(); + description.replace(QLatin1String("$$URI$$"), uri); + e.setDescription(description); + } + return errors; +} + +QList<QDeclarativeDirParser::Plugin> QDeclarativeDirParser::plugins() const +{ + return _plugins; +} + +QList<QDeclarativeDirParser::Component> QDeclarativeDirParser::components() const +{ + return _components; +} + +#ifdef QT_CREATOR +QList<QDeclarativeDirParser::TypeInfo> QDeclarativeDirParser::typeInfos() const +{ + return _typeInfos; +} +#endif + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativedirparser_p.h b/src/declarative/qml/qdeclarativedirparser_p.h new file mode 100644 index 00000000..aa1ace5f --- /dev/null +++ b/src/declarative/qml/qdeclarativedirparser_p.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEDIRPARSER_P_H +#define QDECLARATIVEDIRPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QUrl> +#include <QtCore/QHash> + +QT_BEGIN_NAMESPACE + +class QDeclarativeError; +class QDeclarativeDirParser +{ + Q_DISABLE_COPY(QDeclarativeDirParser) + +public: + QDeclarativeDirParser(); + ~QDeclarativeDirParser(); + + QUrl url() const; + void setUrl(const QUrl &url); + + QString source() const; + void setSource(const QString &source); + + QString fileSource() const; + void setFileSource(const QString &filePath); + + bool isParsed() const; + bool parse(); + + bool hasError() const; + QList<QDeclarativeError> errors(const QString &uri) const; + + struct Plugin + { + Plugin() {} + + Plugin(const QString &name, const QString &path) + : name(name), path(path) {} + + QString name; + QString path; + }; + + struct Component + { + Component() + : majorVersion(0), minorVersion(0), internal(false) {} + + Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion) + : typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion), + internal(false) {} + + QString typeName; + QString fileName; + int majorVersion; + int minorVersion; + bool internal; + }; + + QList<Component> components() const; + QList<Plugin> plugins() const; + +#ifdef QT_CREATOR + struct TypeInfo + { + TypeInfo() {} + TypeInfo(const QString &fileName) + : fileName(fileName) {} + + QString fileName; + }; + + QList<TypeInfo> typeInfos() const; +#endif + +private: + void reportError(int line, int column, const QString &message); + +private: + QList<QDeclarativeError> _errors; + QUrl _url; + QString _source; + QString _filePathSouce; + QList<Component> _components; + QList<Plugin> _plugins; +#ifdef QT_CREATOR + QList<TypeInfo> _typeInfos; +#endif + unsigned _isParsed: 1; +}; + +typedef QList<QDeclarativeDirParser::Component> QDeclarativeDirComponents; + + +QT_END_NAMESPACE + +#endif // QDECLARATIVEDIRPARSER_P_H diff --git a/src/declarative/qml/qdeclarativedom.cpp b/src/declarative/qml/qdeclarativedom.cpp new file mode 100644 index 00000000..bd68d73d --- /dev/null +++ b/src/declarative/qml/qdeclarativedom.cpp @@ -0,0 +1,1835 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativedom_p.h" +#include "private/qdeclarativedom_p_p.h" + +#include "private/qdeclarativecompiler_p.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativescriptparser_p.h" +#include "private/qdeclarativeglobal_p.h" + +#include <QtCore/QByteArray> +#include <QtCore/QDebug> +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +QDeclarativeDomDocumentPrivate::QDeclarativeDomDocumentPrivate() +: root(0) +{ +} + +QDeclarativeDomDocumentPrivate::~QDeclarativeDomDocumentPrivate() +{ + if (root) root->release(); +} + +/*! + \class QDeclarativeDomDocument + \internal + \brief The QDeclarativeDomDocument class represents the root of a QML document + + A QML document is a self-contained snippet of QML, usually contained in a + single file. Each document has a root object, accessible through + QDeclarativeDomDocument::rootObject(). + + The QDeclarativeDomDocument class allows the programmer to inspect a QML document by + calling QDeclarativeDomDocument::load(). + + The following example loads a QML file from disk, and prints out its root + object type and the properties assigned in the root object. + \code + QFile file(inputFileName); + file.open(QIODevice::ReadOnly); + QByteArray xmlData = file.readAll(); + + QDeclarativeDomDocument document; + document.load(qmlengine, xmlData); + + QDeclarativeDomObject rootObject = document.rootObject(); + qDebug() << rootObject.objectType(); + foreach(QDeclarativeDomProperty property, rootObject.properties()) + qDebug() << property.propertyName(); + \endcode +*/ + +/*! + Construct an empty QDeclarativeDomDocument. +*/ +QDeclarativeDomDocument::QDeclarativeDomDocument() +: d(new QDeclarativeDomDocumentPrivate) +{ +} + +/*! + Create a copy of \a other QDeclarativeDomDocument. +*/ +QDeclarativeDomDocument::QDeclarativeDomDocument(const QDeclarativeDomDocument &other) +: d(other.d) +{ +} + +/*! + Destroy the QDeclarativeDomDocument +*/ +QDeclarativeDomDocument::~QDeclarativeDomDocument() +{ +} + +/*! + Assign \a other to this QDeclarativeDomDocument. +*/ +QDeclarativeDomDocument &QDeclarativeDomDocument::operator=(const QDeclarativeDomDocument &other) +{ + d = other.d; + return *this; +} + +/*! + Returns all import statements in qml. +*/ +QList<QDeclarativeDomImport> QDeclarativeDomDocument::imports() const +{ + return d->imports; +} + +/*! + Loads a QDeclarativeDomDocument from \a data. \a data should be valid QML + data. On success, true is returned. If the \a data is malformed, false + is returned and QDeclarativeDomDocument::errors() contains an error description. + + \sa QDeclarativeDomDocument::loadError() +*/ +bool QDeclarativeDomDocument::load(QDeclarativeEngine *engine, const QByteArray &data, const QUrl &url) +{ + d->errors.clear(); + d->imports.clear(); + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + QDeclarativeTypeData *td = ep->typeLoader.get(data, url, QDeclarativeTypeLoader::PreserveParser); + + if(td->isError()) { + d->errors = td->errors(); + td->release(); + return false; + } else if(!td->isCompleteOrError()) { + QDeclarativeError error; + error.setDescription(QLatin1String("QDeclarativeDomDocument supports local types only")); + d->errors << error; + td->release(); + return false; + } + + for (int i = 0; i < td->parser().imports().size(); ++i) { + QDeclarativeScriptParser::Import parserImport = td->parser().imports().at(i); + QDeclarativeDomImport domImport; + domImport.d->type = static_cast<QDeclarativeDomImportPrivate::Type>(parserImport.type); + domImport.d->uri = parserImport.uri; + domImport.d->qualifier = parserImport.qualifier; + domImport.d->version = parserImport.version; + d->imports += domImport; + } + + if (td->parser().tree()) { + d->root = td->parser().tree(); + d->root->addref(); + } + + td->release(); + return true; +} + +/*! + Returns the last load errors. The load errors will be reset after a + successful call to load(). + + \sa load() +*/ +QList<QDeclarativeError> QDeclarativeDomDocument::errors() const +{ + return d->errors; +} + +/*! + Returns the document's root object, or an invalid QDeclarativeDomObject if the + document has no root. + + In the sample QML below, the root object will be the QDeclarativeItem type. + \qml +Item { + Text { + text: "Hello World" + } +} + \endqml +*/ +QDeclarativeDomObject QDeclarativeDomDocument::rootObject() const +{ + QDeclarativeDomObject rv; + rv.d->object = d->root; + if (rv.d->object) rv.d->object->addref(); + return rv; +} + +QDeclarativeDomPropertyPrivate::QDeclarativeDomPropertyPrivate() +: property(0) +{ +} + +QDeclarativeDomPropertyPrivate::~QDeclarativeDomPropertyPrivate() +{ + if (property) property->release(); +} + +QDeclarativeDomDynamicPropertyPrivate::QDeclarativeDomDynamicPropertyPrivate(): + valid(false) +{ +} + +QDeclarativeDomDynamicPropertyPrivate::~QDeclarativeDomDynamicPropertyPrivate() +{ + if (valid && property.defaultValue) property.defaultValue->release(); +} + +/*! + \class QDeclarativeDomProperty + \internal + \brief The QDeclarativeDomProperty class represents one property assignment in the + QML DOM tree + + Properties in QML can be assigned QML \l {QDeclarativeDomValue}{values}. + + \sa QDeclarativeDomObject +*/ + +/*! + Construct an invalid QDeclarativeDomProperty. +*/ +QDeclarativeDomProperty::QDeclarativeDomProperty() +: d(new QDeclarativeDomPropertyPrivate) +{ +} + +/*! + Create a copy of \a other QDeclarativeDomProperty. +*/ +QDeclarativeDomProperty::QDeclarativeDomProperty(const QDeclarativeDomProperty &other) +: d(other.d) +{ +} + +/*! + Destroy the QDeclarativeDomProperty. +*/ +QDeclarativeDomProperty::~QDeclarativeDomProperty() +{ +} + +/*! + Assign \a other to this QDeclarativeDomProperty. +*/ +QDeclarativeDomProperty &QDeclarativeDomProperty::operator=(const QDeclarativeDomProperty &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if this is a valid QDeclarativeDomProperty, false otherwise. +*/ +bool QDeclarativeDomProperty::isValid() const +{ + return d->property != 0; +} + + +/*! + Return the name of this property. + + \qml +Text { + x: 10 + y: 10 + font.bold: true +} + \endqml + + As illustrated above, a property name can be a simple string, such as "x" or + "y", or a more complex "dot property", such as "font.bold". In both cases + the full name is returned ("x", "y" and "font.bold") by this method. + + For dot properties, a split version of the name can be accessed by calling + QDeclarativeDomProperty::propertyNameParts(). + + \sa QDeclarativeDomProperty::propertyNameParts() +*/ +QByteArray QDeclarativeDomProperty::propertyName() const +{ + return d->propertyName; +} + +/*! + Return the name of this property, split into multiple parts in the case + of dot properties. + + \qml +Text { + x: 10 + y: 10 + font.bold: true +} + \endqml + + For each of the properties shown above, this method would return ("x"), + ("y") and ("font", "bold"). + + \sa QDeclarativeDomProperty::propertyName() +*/ +QList<QByteArray> QDeclarativeDomProperty::propertyNameParts() const +{ + if (d->propertyName.isEmpty()) return QList<QByteArray>(); + else return d->propertyName.split('.'); +} + +/*! + Return true if this property is used as a default property in the QML + document. + + \code +<Text text="hello"/> +<Text>hello</Text> + \endcode + + The above two examples return the same DOM tree, except that the second has + the default property flag set on the text property. Observe that whether + or not a property has isDefaultProperty set is determined by how the + property is used, and not only by whether the property is the types default + property. +*/ +bool QDeclarativeDomProperty::isDefaultProperty() const +{ + return d->property && d->property->isDefault; +} + +/*! + Returns the QDeclarativeDomValue that is assigned to this property, or an invalid + QDeclarativeDomValue if no value is assigned. +*/ +QDeclarativeDomValue QDeclarativeDomProperty::value() const +{ + QDeclarativeDomValue rv; + if (d->property) { + rv.d->property = d->property; + if (d->property->values.count()) + rv.d->value = d->property->values.at(0); + else + rv.d->value = d->property->onValues.at(0); + rv.d->property->addref(); + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns the position in the input data where the property ID startd, or -1 if + the property is invalid. +*/ +int QDeclarativeDomProperty::position() const +{ + if (d && d->property) { + return d->property->location.range.offset; + } else + return -1; +} + +/*! + Returns the length in the input data from where the property ID started upto + the end of it, or -1 if the property is invalid. +*/ +int QDeclarativeDomProperty::length() const +{ + if (d && d->property) + return d->property->location.range.length; + else + return -1; +} + +/*! + Construct an invalid QDeclarativeDomDynamicProperty. +*/ +QDeclarativeDomDynamicProperty::QDeclarativeDomDynamicProperty(): + d(new QDeclarativeDomDynamicPropertyPrivate) +{ +} + +/*! + Create a copy of \a other QDeclarativeDomDynamicProperty. +*/ +QDeclarativeDomDynamicProperty::QDeclarativeDomDynamicProperty(const QDeclarativeDomDynamicProperty &other): + d(other.d) +{ +} + +/*! + Destroy the QDeclarativeDomDynamicProperty. +*/ +QDeclarativeDomDynamicProperty::~QDeclarativeDomDynamicProperty() +{ +} + +/*! + Assign \a other to this QDeclarativeDomDynamicProperty. +*/ +QDeclarativeDomDynamicProperty &QDeclarativeDomDynamicProperty::operator=(const QDeclarativeDomDynamicProperty &other) +{ + d = other.d; + return *this; +} + +bool QDeclarativeDomDynamicProperty::isValid() const +{ + return d && d->valid; +} + +/*! + Return the name of this dynamic property. + + \qml +Item { + property int count: 10; +} + \endqml + + As illustrated above, a dynamic property name can have a name and a + default value ("10"). +*/ +QByteArray QDeclarativeDomDynamicProperty::propertyName() const +{ + if (isValid()) + return d->property.name; + else + return QByteArray(); +} + +/*! + Returns the type of the dynamic property. Note that when the property is an + alias property, this will return -1. Use QDeclarativeDomProperty::isAlias() to check + if the property is an alias. +*/ +int QDeclarativeDomDynamicProperty::propertyType() const +{ + if (isValid()) { + switch (d->property.type) { + case QDeclarativeParser::Object::DynamicProperty::Bool: + return QMetaType::type("bool"); + + case QDeclarativeParser::Object::DynamicProperty::Color: + return QMetaType::type("QColor"); + + case QDeclarativeParser::Object::DynamicProperty::Time: + return QMetaType::type("QTime"); + + case QDeclarativeParser::Object::DynamicProperty::Date: + return QMetaType::type("QDate"); + + case QDeclarativeParser::Object::DynamicProperty::DateTime: + return QMetaType::type("QDateTime"); + + case QDeclarativeParser::Object::DynamicProperty::Int: + return QMetaType::type("int"); + + case QDeclarativeParser::Object::DynamicProperty::Real: + return sizeof(qreal) == sizeof(double) ? QMetaType::type("double") : QMetaType::type("float"); + + case QDeclarativeParser::Object::DynamicProperty::String: + return QMetaType::type("QString"); + + case QDeclarativeParser::Object::DynamicProperty::Url: + return QMetaType::type("QUrl"); + + case QDeclarativeParser::Object::DynamicProperty::Variant: + return QMetaType::type("QVariant"); + + default: + break; + } + } + + return -1; +} + +QByteArray QDeclarativeDomDynamicProperty::propertyTypeName() const +{ + if (isValid()) + return d->property.customType; + + return QByteArray(); +} + +/*! + Return true if this property is used as a default property in the QML + document. + + \code +<Text text="hello"/> +<Text>hello</Text> + \endcode + + The above two examples return the same DOM tree, except that the second has + the default property flag set on the text property. Observe that whether + or not a property has isDefaultProperty set is determined by how the + property is used, and not only by whether the property is the types default + property. +*/ +bool QDeclarativeDomDynamicProperty::isDefaultProperty() const +{ + if (isValid()) + return d->property.isDefaultProperty; + else + return false; +} + +/*! + Returns the default value as a QDeclarativeDomProperty. +*/ +QDeclarativeDomProperty QDeclarativeDomDynamicProperty::defaultValue() const +{ + QDeclarativeDomProperty rp; + + if (isValid() && d->property.defaultValue) { + rp.d->property = d->property.defaultValue; + rp.d->propertyName = propertyName(); + rp.d->property->addref(); + } + + return rp; +} + +/*! + Returns true if this dynamic property is an alias for another property, + false otherwise. +*/ +bool QDeclarativeDomDynamicProperty::isAlias() const +{ + if (isValid()) + return d->property.type == QDeclarativeParser::Object::DynamicProperty::Alias; + else + return false; +} + +/*! + Returns the position in the input data where the property ID startd, or 0 if + the property is invalid. +*/ +int QDeclarativeDomDynamicProperty::position() const +{ + if (isValid()) { + return d->property.location.range.offset; + } else + return -1; +} + +/*! + Returns the length in the input data from where the property ID started upto + the end of it, or 0 if the property is invalid. +*/ +int QDeclarativeDomDynamicProperty::length() const +{ + if (isValid()) + return d->property.location.range.length; + else + return -1; +} + +QDeclarativeDomObjectPrivate::QDeclarativeDomObjectPrivate() +: object(0) +{ +} + +QDeclarativeDomObjectPrivate::~QDeclarativeDomObjectPrivate() +{ + if (object) object->release(); +} + +QDeclarativeDomObjectPrivate::Properties +QDeclarativeDomObjectPrivate::properties() const +{ + Properties rv; + + for (QHash<QByteArray, QDeclarativeParser::Property *>::ConstIterator iter = + object->properties.begin(); + iter != object->properties.end(); + ++iter) { + + rv << properties(*iter); + + } + return rv; +} + +QDeclarativeDomObjectPrivate::Properties +QDeclarativeDomObjectPrivate::properties(QDeclarativeParser::Property *property) const +{ + Properties rv; + + if (property->value) { + + for (QHash<QByteArray, QDeclarativeParser::Property *>::ConstIterator iter = + property->value->properties.begin(); + iter != property->value->properties.end(); + ++iter) { + + rv << properties(*iter); + + } + + QByteArray name(property->name + '.'); + for (Properties::Iterator iter = rv.begin(); iter != rv.end(); ++iter) + iter->second.prepend(name); + + } else { + rv << qMakePair(property, property->name); + } + + return rv; +} + +/*! + \class QDeclarativeDomObject + \internal + \brief The QDeclarativeDomObject class represents an object instantiation. + + Each object instantiated in a QML file has a corresponding QDeclarativeDomObject + node in the QML DOM. + + In addition to the type information that determines the object to + instantiate, QDeclarativeDomObject's also have a set of associated QDeclarativeDomProperty's. + Each QDeclarativeDomProperty represents a QML property assignment on the instantiated + object. For example, + + \qml +QGraphicsWidget { + opacity: 0.5 + size: "100x100" +} + \endqml + + describes a single QDeclarativeDomObject - "QGraphicsWidget" - with two properties, + "opacity" and "size". Obviously QGraphicsWidget has many more properties than just + these two, but the QML DOM representation only contains those assigned + values (or bindings) in the QML file. +*/ + +/*! + Construct an invalid QDeclarativeDomObject. +*/ +QDeclarativeDomObject::QDeclarativeDomObject() +: d(new QDeclarativeDomObjectPrivate) +{ +} + +/*! + Create a copy of \a other QDeclarativeDomObject. +*/ +QDeclarativeDomObject::QDeclarativeDomObject(const QDeclarativeDomObject &other) +: d(other.d) +{ +} + +/*! + Destroy the QDeclarativeDomObject. +*/ +QDeclarativeDomObject::~QDeclarativeDomObject() +{ +} + +/*! + Assign \a other to this QDeclarativeDomObject. +*/ +QDeclarativeDomObject &QDeclarativeDomObject::operator=(const QDeclarativeDomObject &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if this is a valid QDeclarativeDomObject, false otherwise. +*/ +bool QDeclarativeDomObject::isValid() const +{ + return d->object != 0; +} + +/*! + Returns the fully-qualified type name of this object. + + For example, the type of this object would be "Qt/4.6/Rectangle". + \qml +Rectangle { } + \endqml +*/ +QByteArray QDeclarativeDomObject::objectType() const +{ + if (d->object) return d->object->typeName; + else return QByteArray(); +} + +/*! + Returns the type name as referenced in the qml file. + + For example, the type of this object would be "Rectangle". + \qml +Rectangle { } + \endqml +*/ +QByteArray QDeclarativeDomObject::objectClassName() const +{ + if (d->object) + return d->object->className; + else + return QByteArray(); +} + +int QDeclarativeDomObject::objectTypeMajorVersion() const +{ + if (d->object) + return d->object->majorVersion; + else + return -1; +} + +int QDeclarativeDomObject::objectTypeMinorVersion() const +{ + if (d->object) + return d->object->minorVersion; + else + return -1; +} + +/*! + Returns the QML id assigned to this object, or an empty QByteArray if no id + has been assigned. + + For example, the object id of this object would be "MyText". + \qml +Text { id: myText } + \endqml +*/ +QString QDeclarativeDomObject::objectId() const +{ + if (d->object) { + return d->object->id; + } else { + return QString(); + } +} + +/*! + Returns the list of assigned properties on this object. + + In the following example, "text" and "x" properties would be returned. + \qml +Text { + text: "Hello world!" + x: 100 +} + \endqml +*/ +QList<QDeclarativeDomProperty> QDeclarativeDomObject::properties() const +{ + QList<QDeclarativeDomProperty> rv; + + if (!d->object || isComponent()) + return rv; + + QDeclarativeDomObjectPrivate::Properties properties = d->properties(); + for (int ii = 0; ii < properties.count(); ++ii) { + + QDeclarativeDomProperty domProperty; + domProperty.d->property = properties.at(ii).first; + domProperty.d->property->addref(); + domProperty.d->propertyName = properties.at(ii).second; + rv << domProperty; + + } + + if (d->object->defaultProperty) { + QDeclarativeDomProperty domProperty; + domProperty.d->property = d->object->defaultProperty; + domProperty.d->property->addref(); + domProperty.d->propertyName = d->object->defaultProperty->name; + rv << domProperty; + } + + return rv; +} + +/*! + Returns the object's \a name property if a value has been assigned to + it, or an invalid QDeclarativeDomProperty otherwise. + + In the example below, \c {object.property("source")} would return a valid + QDeclarativeDomProperty, and \c {object.property("tile")} an invalid QDeclarativeDomProperty. + + \qml +Image { source: "sample.jpg" } + \endqml +*/ +QDeclarativeDomProperty QDeclarativeDomObject::property(const QByteArray &name) const +{ + QList<QDeclarativeDomProperty> props = properties(); + for (int ii = 0; ii < props.count(); ++ii) + if (props.at(ii).propertyName() == name) + return props.at(ii); + return QDeclarativeDomProperty(); +} + +QList<QDeclarativeDomDynamicProperty> QDeclarativeDomObject::dynamicProperties() const +{ + QList<QDeclarativeDomDynamicProperty> properties; + + for (int i = 0; i < d->object->dynamicProperties.size(); ++i) { + QDeclarativeDomDynamicProperty p; + p.d = new QDeclarativeDomDynamicPropertyPrivate; + p.d->property = d->object->dynamicProperties.at(i); + p.d->valid = true; + + if (p.d->property.defaultValue) + p.d->property.defaultValue->addref(); + + properties.append(p); + } + + return properties; +} + +QDeclarativeDomDynamicProperty QDeclarativeDomObject::dynamicProperty(const QByteArray &name) const +{ + QDeclarativeDomDynamicProperty p; + + if (!isValid()) + return p; + + for (int i = 0; i < d->object->dynamicProperties.size(); ++i) { + if (d->object->dynamicProperties.at(i).name == name) { + p.d = new QDeclarativeDomDynamicPropertyPrivate; + p.d->property = d->object->dynamicProperties.at(i); + if (p.d->property.defaultValue) p.d->property.defaultValue->addref(); + p.d->valid = true; + } + } + + return p; +} + +/*! + Returns true if this object is a custom type. Custom types are special + types that allow embeddeding non-QML data, such as SVG or HTML data, + directly into QML files. + + \note Currently this method will always return false, and is a placekeeper + for future functionality. + + \sa QDeclarativeDomObject::customTypeData() +*/ +bool QDeclarativeDomObject::isCustomType() const +{ + return false; +} + +/*! + If this object represents a custom type, returns the data associated with + the custom type, otherwise returns an empty QByteArray(). + QDeclarativeDomObject::isCustomType() can be used to check if this object represents + a custom type. +*/ +QByteArray QDeclarativeDomObject::customTypeData() const +{ + return QByteArray(); +} + +/*! + Returns true if this object is a sub-component object. Sub-component + objects can be converted into QDeclarativeDomComponent instances by calling + QDeclarativeDomObject::toComponent(). + + \sa QDeclarativeDomObject::toComponent() +*/ +bool QDeclarativeDomObject::isComponent() const +{ + return (d->object && (d->object->typeName == "Qt/Component" || d->object->typeName == "QtQuick/Component")); +} + +/*! + Returns a QDeclarativeDomComponent for this object if it is a sub-component, or + an invalid QDeclarativeDomComponent if not. QDeclarativeDomObject::isComponent() can be used + to check if this object represents a sub-component. + + \sa QDeclarativeDomObject::isComponent() +*/ +QDeclarativeDomComponent QDeclarativeDomObject::toComponent() const +{ + QDeclarativeDomComponent rv; + if (isComponent()) + rv.d = d; + return rv; +} + +/*! + Returns the position in the input data where the property assignment started +, or -1 if the property is invalid. +*/ +int QDeclarativeDomObject::position() const +{ + if (d && d->object) + return d->object->location.range.offset; + else + return -1; +} + +/*! + Returns the length in the input data from where the property assignment star +ted upto the end of it, or -1 if the property is invalid. +*/ +int QDeclarativeDomObject::length() const +{ + if (d && d->object) + return d->object->location.range.length; + else + return -1; +} + +// Returns the URL of the type, if it is an external type, or an empty URL if +// not +QUrl QDeclarativeDomObject::url() const +{ + if (d && d->object) + return d->object->url; + else + return QUrl(); +} + +QDeclarativeDomBasicValuePrivate::QDeclarativeDomBasicValuePrivate() +: value(0) +{ +} + +QDeclarativeDomBasicValuePrivate::~QDeclarativeDomBasicValuePrivate() +{ + if (value) value->release(); +} + +/*! + \class QDeclarativeDomValueLiteral + \internal + \brief The QDeclarativeDomValueLiteral class represents a literal value. + + A literal value is a simple value, written inline with the QML. In the + example below, the "x", "y" and "color" properties are being assigned + literal values. + + \qml +Rectangle { + x: 10 + y: 10 + color: "red" +} + \endqml +*/ + +/*! + Construct an empty QDeclarativeDomValueLiteral. +*/ +QDeclarativeDomValueLiteral::QDeclarativeDomValueLiteral(): + d(new QDeclarativeDomBasicValuePrivate) +{ +} + +/*! + Create a copy of \a other QDeclarativeDomValueLiteral. +*/ +QDeclarativeDomValueLiteral::QDeclarativeDomValueLiteral(const QDeclarativeDomValueLiteral &other) +: d(other.d) +{ +} + +/*! + Destroy the QDeclarativeDomValueLiteral. +*/ +QDeclarativeDomValueLiteral::~QDeclarativeDomValueLiteral() +{ +} + +/*! + Assign \a other to this QDeclarativeDomValueLiteral. +*/ +QDeclarativeDomValueLiteral &QDeclarativeDomValueLiteral::operator=(const QDeclarativeDomValueLiteral &other) +{ + d = other.d; + return *this; +} + +/*! + Return the literal value. + + In the example below, the literal value will be the string "10". + \qml +Rectangle { x: 10 } + \endqml +*/ +QString QDeclarativeDomValueLiteral::literal() const +{ + if (d->value) return d->value->primitive(); + else return QString(); +} + +/*! + \class QDeclarativeDomValueBinding + \internal + \brief The QDeclarativeDomValueBinding class represents a property binding. + + A property binding is an ECMAScript expression assigned to a property. In + the example below, the "x" property is being assigned a property binding. + + \qml +Rectangle { x: Other.x } + \endqml +*/ + +/*! + Construct an empty QDeclarativeDomValueBinding. +*/ +QDeclarativeDomValueBinding::QDeclarativeDomValueBinding(): + d(new QDeclarativeDomBasicValuePrivate) +{ +} + +/*! + Create a copy of \a other QDeclarativeDomValueBinding. +*/ +QDeclarativeDomValueBinding::QDeclarativeDomValueBinding(const QDeclarativeDomValueBinding &other) +: d(other.d) +{ +} + +/*! + Destroy the QDeclarativeDomValueBinding. +*/ +QDeclarativeDomValueBinding::~QDeclarativeDomValueBinding() +{ +} + +/*! + Assign \a other to this QDeclarativeDomValueBinding. +*/ +QDeclarativeDomValueBinding &QDeclarativeDomValueBinding::operator=(const QDeclarativeDomValueBinding &other) +{ + d = other.d; + return *this; +} + +/*! + Return the binding expression. + + In the example below, the string "Other.x" will be returned. + \qml +Rectangle { x: Other.x } + \endqml +*/ +QString QDeclarativeDomValueBinding::binding() const +{ + if (d->value) + return d->value->value.asScript(); + else + return QString(); +} + +/*! + \class QDeclarativeDomValueValueSource + \internal + \brief The QDeclarativeDomValueValueSource class represents a value source assignment value. + + In QML, value sources are special value generating types that may be + assigned to properties. Value sources inherit the QDeclarativePropertyValueSource + class. In the example below, the "x" property is being assigned the + NumberAnimation value source. + + \qml +Rectangle { + x: NumberAnimation { + from: 0 + to: 100 + loops: Animation.Infinite + } +} + \endqml +*/ + +/*! + Construct an empty QDeclarativeDomValueValueSource. +*/ +QDeclarativeDomValueValueSource::QDeclarativeDomValueValueSource(): + d(new QDeclarativeDomBasicValuePrivate) +{ +} + +/*! + Create a copy of \a other QDeclarativeDomValueValueSource. +*/ +QDeclarativeDomValueValueSource::QDeclarativeDomValueValueSource(const QDeclarativeDomValueValueSource &other) +: d(other.d) +{ +} + +/*! + Destroy the QDeclarativeDomValueValueSource. +*/ +QDeclarativeDomValueValueSource::~QDeclarativeDomValueValueSource() +{ +} + +/*! + Assign \a other to this QDeclarativeDomValueValueSource. +*/ +QDeclarativeDomValueValueSource &QDeclarativeDomValueValueSource::operator=(const QDeclarativeDomValueValueSource &other) +{ + d = other.d; + return *this; +} + +/*! + Return the value source object. + + In the example below, an object representing the NumberAnimation will be + returned. + \qml +Rectangle { + x: NumberAnimation { + from: 0 + to: 100 + loops: Animation.Infinite + } +} + \endqml +*/ +QDeclarativeDomObject QDeclarativeDomValueValueSource::object() const +{ + QDeclarativeDomObject rv; + if (d->value) { + rv.d->object = d->value->object; + rv.d->object->addref(); + } + return rv; +} + +/*! + \class QDeclarativeDomValueValueInterceptor + \internal + \brief The QDeclarativeDomValueValueInterceptor class represents a value interceptor assignment value. + + In QML, value interceptor are special write-intercepting types that may be + assigned to properties. Value interceptor inherit the QDeclarativePropertyValueInterceptor + class. In the example below, the "x" property is being assigned the + Behavior value interceptor. + + \qml +Rectangle { + Behavior on x { NumberAnimation { duration: 500 } } +} + \endqml +*/ + +/*! + Construct an empty QDeclarativeDomValueValueInterceptor. +*/ +QDeclarativeDomValueValueInterceptor::QDeclarativeDomValueValueInterceptor(): + d(new QDeclarativeDomBasicValuePrivate) +{ +} + +/*! + Create a copy of \a other QDeclarativeDomValueValueInterceptor. +*/ +QDeclarativeDomValueValueInterceptor::QDeclarativeDomValueValueInterceptor(const QDeclarativeDomValueValueInterceptor &other) +: d(other.d) +{ +} + +/*! + Destroy the QDeclarativeDomValueValueInterceptor. +*/ +QDeclarativeDomValueValueInterceptor::~QDeclarativeDomValueValueInterceptor() +{ +} + +/*! + Assign \a other to this QDeclarativeDomValueValueInterceptor. +*/ +QDeclarativeDomValueValueInterceptor &QDeclarativeDomValueValueInterceptor::operator=(const QDeclarativeDomValueValueInterceptor &other) +{ + d = other.d; + return *this; +} + +/*! + Return the value interceptor object. + + In the example below, an object representing the Behavior will be + returned. + \qml +Rectangle { + Behavior on x { NumberAnimation { duration: 500 } } +} + \endqml +*/ +QDeclarativeDomObject QDeclarativeDomValueValueInterceptor::object() const +{ + QDeclarativeDomObject rv; + if (d->value) { + rv.d->object = d->value->object; + rv.d->object->addref(); + } + return rv; +} + +QDeclarativeDomValuePrivate::QDeclarativeDomValuePrivate() +: property(0), value(0) +{ +} + +QDeclarativeDomValuePrivate::~QDeclarativeDomValuePrivate() +{ + if (property) property->release(); + if (value) value->release(); +} + +/*! + \class QDeclarativeDomValue + \internal + \brief The QDeclarativeDomValue class represents a generic Qml value. + + QDeclarativeDomValue's can be assigned to QML \l {QDeclarativeDomProperty}{properties}. In + QML, properties can be assigned various different values, including basic + literals, property bindings, property value sources, objects and lists of + values. The QDeclarativeDomValue class allows a programmer to determine the specific + value type being assigned and access more detailed information through a + corresponding value type class. + + For example, in the following example, + + \qml +Text { + text: "Hello World!" + y: Other.y +} + \endqml + + The text property is being assigned a literal, and the y property a property + binding. To output the values assigned to the text and y properties in the + above example from C++, + + \code + QDeclarativeDomDocument document; + QDeclarativeDomObject root = document.rootObject(); + + QDeclarativeDomProperty text = root.property("text"); + if (text.value().isLiteral()) { + QDeclarativeDomValueLiteral literal = text.value().toLiteral(); + qDebug() << literal.literal(); + } + + QDeclarativeDomProperty y = root.property("y"); + if (y.value().isBinding()) { + QDeclarativeDomValueBinding binding = y.value().toBinding(); + qDebug() << binding.binding(); + } + \endcode +*/ + +/*! + Construct an invalid QDeclarativeDomValue. +*/ +QDeclarativeDomValue::QDeclarativeDomValue() +: d(new QDeclarativeDomValuePrivate) +{ +} + +/*! + Create a copy of \a other QDeclarativeDomValue. +*/ +QDeclarativeDomValue::QDeclarativeDomValue(const QDeclarativeDomValue &other) +: d(other.d) +{ +} + +/*! + Destroy the QDeclarativeDomValue +*/ +QDeclarativeDomValue::~QDeclarativeDomValue() +{ +} + +/*! + Assign \a other to this QDeclarativeDomValue. +*/ +QDeclarativeDomValue &QDeclarativeDomValue::operator=(const QDeclarativeDomValue &other) +{ + d = other.d; + return *this; +} + +/*! + \enum QDeclarativeDomValue::Type + + The type of the QDeclarativeDomValue node. + + \value Invalid The QDeclarativeDomValue is invalid. + \value Literal The QDeclarativeDomValue is a literal value assignment. Use QDeclarativeDomValue::toLiteral() to access the type instance. + \value PropertyBinding The QDeclarativeDomValue is a property binding. Use QDeclarativeDomValue::toBinding() to access the type instance. + \value ValueSource The QDeclarativeDomValue is a property value source. Use QDeclarativeDomValue::toValueSource() to access the type instance. + \value ValueInterceptor The QDeclarativeDomValue is a property value interceptor. Use QDeclarativeDomValue::toValueInterceptor() to access the type instance. + \value Object The QDeclarativeDomValue is an object assignment. Use QDeclarativeDomValue::toObject() to access the type instnace. + \value List The QDeclarativeDomValue is a list of other values. Use QDeclarativeDomValue::toList() to access the type instance. +*/ + +/*! + Returns the type of this QDeclarativeDomValue. +*/ +QDeclarativeDomValue::Type QDeclarativeDomValue::type() const +{ + if (d->property) + if (QDeclarativeMetaType::isList(d->property->type) || + (d->property && (d->property->values.count() + d->property->onValues.count()) > 1)) + return List; + + QDeclarativeParser::Value *value = d->value; + if (!value && !d->property) + return Invalid; + + switch(value->type) { + case QDeclarativeParser::Value::Unknown: + return Invalid; + case QDeclarativeParser::Value::Literal: + return Literal; + case QDeclarativeParser::Value::PropertyBinding: + return PropertyBinding; + case QDeclarativeParser::Value::ValueSource: + return ValueSource; + case QDeclarativeParser::Value::ValueInterceptor: + return ValueInterceptor; + case QDeclarativeParser::Value::CreatedObject: + return Object; + case QDeclarativeParser::Value::SignalObject: + return Invalid; + case QDeclarativeParser::Value::SignalExpression: + return Literal; + case QDeclarativeParser::Value::Id: + return Literal; + } + return Invalid; +} + +/*! + Returns true if this is an invalid value, otherwise false. +*/ +bool QDeclarativeDomValue::isInvalid() const +{ + return type() == Invalid; +} + +/*! + Returns true if this is a literal value, otherwise false. +*/ +bool QDeclarativeDomValue::isLiteral() const +{ + return type() == Literal; +} + +/*! + Returns true if this is a property binding value, otherwise false. +*/ +bool QDeclarativeDomValue::isBinding() const +{ + return type() == PropertyBinding; +} + +/*! + Returns true if this is a value source value, otherwise false. +*/ +bool QDeclarativeDomValue::isValueSource() const +{ + return type() == ValueSource; +} + +/*! + Returns true if this is a value interceptor value, otherwise false. +*/ +bool QDeclarativeDomValue::isValueInterceptor() const +{ + return type() == ValueInterceptor; +} + +/*! + Returns true if this is an object value, otherwise false. +*/ +bool QDeclarativeDomValue::isObject() const +{ + return type() == Object; +} + +/*! + Returns true if this is a list value, otherwise false. +*/ +bool QDeclarativeDomValue::isList() const +{ + return type() == List; +} + +/*! + Returns a QDeclarativeDomValueLiteral if this value is a literal type, otherwise + returns an invalid QDeclarativeDomValueLiteral. + + \sa QDeclarativeDomValue::type() +*/ +QDeclarativeDomValueLiteral QDeclarativeDomValue::toLiteral() const +{ + QDeclarativeDomValueLiteral rv; + if (type() == Literal) { + rv.d->value = d->value; + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns a QDeclarativeDomValueBinding if this value is a property binding type, + otherwise returns an invalid QDeclarativeDomValueBinding. + + \sa QDeclarativeDomValue::type() +*/ +QDeclarativeDomValueBinding QDeclarativeDomValue::toBinding() const +{ + QDeclarativeDomValueBinding rv; + if (type() == PropertyBinding) { + rv.d->value = d->value; + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns a QDeclarativeDomValueValueSource if this value is a property value source + type, otherwise returns an invalid QDeclarativeDomValueValueSource. + + \sa QDeclarativeDomValue::type() +*/ +QDeclarativeDomValueValueSource QDeclarativeDomValue::toValueSource() const +{ + QDeclarativeDomValueValueSource rv; + if (type() == ValueSource) { + rv.d->value = d->value; + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns a QDeclarativeDomValueValueInterceptor if this value is a property value interceptor + type, otherwise returns an invalid QDeclarativeDomValueValueInterceptor. + + \sa QDeclarativeDomValue::type() +*/ +QDeclarativeDomValueValueInterceptor QDeclarativeDomValue::toValueInterceptor() const +{ + QDeclarativeDomValueValueInterceptor rv; + if (type() == ValueInterceptor) { + rv.d->value = d->value; + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns a QDeclarativeDomObject if this value is an object assignment type, otherwise + returns an invalid QDeclarativeDomObject. + + \sa QDeclarativeDomValue::type() +*/ +QDeclarativeDomObject QDeclarativeDomValue::toObject() const +{ + QDeclarativeDomObject rv; + if (type() == Object) { + rv.d->object = d->value->object; + rv.d->object->addref(); + } + return rv; +} + +/*! + Returns a QDeclarativeDomList if this value is a list type, otherwise returns an + invalid QDeclarativeDomList. + + \sa QDeclarativeDomValue::type() +*/ +QDeclarativeDomList QDeclarativeDomValue::toList() const +{ + QDeclarativeDomList rv; + if (type() == List) { + rv.d = d; + } + return rv; +} + +/*! + Returns the position in the input data where the property value startd, or -1 + if the value is invalid. +*/ +int QDeclarativeDomValue::position() const +{ + if (type() == Invalid) + return -1; + else + return d->value->location.range.offset; +} + +/*! + Returns the length in the input data from where the property value started u +pto the end of it, or -1 if the value is invalid. +*/ +int QDeclarativeDomValue::length() const +{ + if (type() == Invalid) + return -1; + else + return d->value->location.range.length; +} + +/*! + \class QDeclarativeDomList + \internal + \brief The QDeclarativeDomList class represents a list of values assigned to a QML property. + + Lists of values can be assigned to properties. For example, the following + example assigns multiple objects to Item's "children" property + \qml +Item { + children: [ + Text { }, + Rectangle { } + ] +} + \endqml + + Lists can also be implicitly created by assigning multiple + \l {QDeclarativeDomValueValueSource}{value sources} or constants to a property. + \qml +Item { + x: 10 + x: NumberAnimation { + running: false + from: 0 + to: 100 + } +} + \endqml +*/ + +/*! + Construct an empty QDeclarativeDomList. +*/ +QDeclarativeDomList::QDeclarativeDomList() +{ +} + +/*! + Create a copy of \a other QDeclarativeDomList. +*/ +QDeclarativeDomList::QDeclarativeDomList(const QDeclarativeDomList &other) +: d(other.d) +{ +} + +/*! + Destroy the QDeclarativeDomList. +*/ +QDeclarativeDomList::~QDeclarativeDomList() +{ +} + +/*! + Assign \a other to this QDeclarativeDomList. +*/ +QDeclarativeDomList &QDeclarativeDomList::operator=(const QDeclarativeDomList &other) +{ + d = other.d; + return *this; +} + +/*! + Returns the list of QDeclarativeDomValue's. +*/ +QList<QDeclarativeDomValue> QDeclarativeDomList::values() const +{ + QList<QDeclarativeDomValue> rv; + if (!d->property) + return rv; + + for (int ii = 0; ii < d->property->values.count(); ++ii) { + QDeclarativeDomValue v; + v.d->value = d->property->values.at(ii); + v.d->value->addref(); + rv << v; + } + + for (int ii = 0; ii < d->property->onValues.count(); ++ii) { + QDeclarativeDomValue v; + v.d->value = d->property->onValues.at(ii); + v.d->value->addref(); + rv << v; + } + + return rv; +} + +/*! + Returns the position in the input data where the list started, or -1 if + the property is invalid. +*/ +int QDeclarativeDomList::position() const +{ + if (d && d->property) { + return d->property->listValueRange.offset; + } else + return -1; +} + +/*! + Returns the length in the input data from where the list started upto + the end of it, or 0 if the property is invalid. +*/ +int QDeclarativeDomList::length() const +{ + if (d && d->property) + return d->property->listValueRange.length; + else + return -1; +} + +/*! + Returns a list of positions of the commas in the QML file. +*/ +QList<int> QDeclarativeDomList:: commaPositions() const +{ + if (d && d->property) + return d->property->listCommaPositions; + else + return QList<int>(); +} + +/*! + \class QDeclarativeDomComponent + \internal + \brief The QDeclarativeDomComponent class represents sub-component within a QML document. + + Sub-components are QDeclarativeComponents defined within a QML document. The + following example shows the definition of a sub-component with the id + "listDelegate". + + \qml +Item { + Component { + id: listDelegate + Text { + text: modelData.text + } + } +} + \endqml + + Like QDeclarativeDomDocument's, components contain a single root object. +*/ + +/*! + Construct an empty QDeclarativeDomComponent. +*/ +QDeclarativeDomComponent::QDeclarativeDomComponent() +{ +} + +/*! + Create a copy of \a other QDeclarativeDomComponent. +*/ +QDeclarativeDomComponent::QDeclarativeDomComponent(const QDeclarativeDomComponent &other) +: QDeclarativeDomObject(other) +{ +} + +/*! + Destroy the QDeclarativeDomComponent. +*/ +QDeclarativeDomComponent::~QDeclarativeDomComponent() +{ +} + +/*! + Assign \a other to this QDeclarativeDomComponent. +*/ +QDeclarativeDomComponent &QDeclarativeDomComponent::operator=(const QDeclarativeDomComponent &other) +{ + static_cast<QDeclarativeDomObject &>(*this) = other; + return *this; +} + +/*! + Returns the component's root object. + + In the example below, the root object is the "Text" object. + \qml +Item { + Component { + id: listDelegate + Text { + text: modelData.text + } + } +} + \endqml +*/ +QDeclarativeDomObject QDeclarativeDomComponent::componentRoot() const +{ + QDeclarativeDomObject rv; + if (d->object) { + QDeclarativeParser::Object *obj = 0; + if (d->object->defaultProperty && + d->object->defaultProperty->values.count() == 1 && + d->object->defaultProperty->values.at(0)->object) + obj = d->object->defaultProperty->values.at(0)->object; + + if (obj) { + rv.d->object = obj; + rv.d->object->addref(); + } + } + + return rv; +} + +QDeclarativeDomImportPrivate::QDeclarativeDomImportPrivate() +: type(File) +{ +} + +QDeclarativeDomImportPrivate::~QDeclarativeDomImportPrivate() +{ +} + +/*! + \class QDeclarativeDomImport + \internal + \brief The QDeclarativeDomImport class represents an import statement. +*/ + +/*! + Construct an empty QDeclarativeDomImport. +*/ +QDeclarativeDomImport::QDeclarativeDomImport() +: d(new QDeclarativeDomImportPrivate) +{ +} + +/*! + Create a copy of \a other QDeclarativeDomImport. +*/ +QDeclarativeDomImport::QDeclarativeDomImport(const QDeclarativeDomImport &other) +: d(other.d) +{ +} + +/*! + Destroy the QDeclarativeDomImport. +*/ +QDeclarativeDomImport::~QDeclarativeDomImport() +{ +} + +/*! + Assign \a other to this QDeclarativeDomImport. +*/ +QDeclarativeDomImport &QDeclarativeDomImport::operator=(const QDeclarativeDomImport &other) +{ + d = other.d; + return *this; +} + +/*! + Returns the type of the import. + */ +QDeclarativeDomImport::Type QDeclarativeDomImport::type() const +{ + return static_cast<QDeclarativeDomImport::Type>(d->type); +} + +/*! + Returns the URI of the import (e.g. 'subdir' or 'com.nokia.Qt') + */ +QString QDeclarativeDomImport::uri() const +{ + return d->uri; +} + +/*! + Returns the version specified by the import. An empty string if no version was specified. + */ +QString QDeclarativeDomImport::version() const +{ + return d->version; +} + +/*! + Returns the (optional) qualifier string (the token following the 'as' keyword) of the import. + */ +QString QDeclarativeDomImport::qualifier() const +{ + return d->qualifier; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativedom_p.h b/src/declarative/qml/qdeclarativedom_p.h new file mode 100644 index 00000000..f8538f97 --- /dev/null +++ b/src/declarative/qml/qdeclarativedom_p.h @@ -0,0 +1,362 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEDOM_P_H +#define QDECLARATIVEDOM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativeerror.h" + +#include <QtCore/qlist.h> +#include <QtCore/qshareddata.h> + +#include <private/qdeclarativeglobal_p.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QString; +class QByteArray; +class QDeclarativeDomObject; +class QDeclarativeDomList; +class QDeclarativeDomValue; +class QDeclarativeEngine; +class QDeclarativeDomComponent; +class QDeclarativeDomImport; +class QIODevice; + +class QDeclarativeDomDocumentPrivate; + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomDocument +{ +public: + QDeclarativeDomDocument(); + QDeclarativeDomDocument(const QDeclarativeDomDocument &); + ~QDeclarativeDomDocument(); + QDeclarativeDomDocument &operator=(const QDeclarativeDomDocument &); + + QList<QDeclarativeDomImport> imports() const; + + QList<QDeclarativeError> errors() const; + bool load(QDeclarativeEngine *, const QByteArray &, const QUrl & = QUrl()); + + QDeclarativeDomObject rootObject() const; + +private: + QSharedDataPointer<QDeclarativeDomDocumentPrivate> d; +}; + +class QDeclarativeDomPropertyPrivate; +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomProperty +{ +public: + QDeclarativeDomProperty(); + QDeclarativeDomProperty(const QDeclarativeDomProperty &); + ~QDeclarativeDomProperty(); + QDeclarativeDomProperty &operator=(const QDeclarativeDomProperty &); + + bool isValid() const; + + QByteArray propertyName() const; + QList<QByteArray> propertyNameParts() const; + + bool isDefaultProperty() const; + + QDeclarativeDomValue value() const; + + int position() const; + int length() const; + +private: + friend class QDeclarativeDomObject; + friend class QDeclarativeDomDynamicProperty; + QSharedDataPointer<QDeclarativeDomPropertyPrivate> d; +}; + +class QDeclarativeDomDynamicPropertyPrivate; +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomDynamicProperty +{ +public: + QDeclarativeDomDynamicProperty(); + QDeclarativeDomDynamicProperty(const QDeclarativeDomDynamicProperty &); + ~QDeclarativeDomDynamicProperty(); + QDeclarativeDomDynamicProperty &operator=(const QDeclarativeDomDynamicProperty &); + + bool isValid() const; + + QByteArray propertyName() const; + int propertyType() const; + QByteArray propertyTypeName() const; + + bool isDefaultProperty() const; + QDeclarativeDomProperty defaultValue() const; + + bool isAlias() const; + + int position() const; + int length() const; + +private: + friend class QDeclarativeDomObject; + QSharedDataPointer<QDeclarativeDomDynamicPropertyPrivate> d; +}; + +class QDeclarativeDomObjectPrivate; +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomObject +{ +public: + QDeclarativeDomObject(); + QDeclarativeDomObject(const QDeclarativeDomObject &); + ~QDeclarativeDomObject(); + QDeclarativeDomObject &operator=(const QDeclarativeDomObject &); + + bool isValid() const; + + QByteArray objectType() const; + QByteArray objectClassName() const; + + int objectTypeMajorVersion() const; + int objectTypeMinorVersion() const; + + QString objectId() const; + + QList<QDeclarativeDomProperty> properties() const; + QDeclarativeDomProperty property(const QByteArray &) const; + + QList<QDeclarativeDomDynamicProperty> dynamicProperties() const; + QDeclarativeDomDynamicProperty dynamicProperty(const QByteArray &) const; + + bool isCustomType() const; + QByteArray customTypeData() const; + + bool isComponent() const; + QDeclarativeDomComponent toComponent() const; + + int position() const; + int length() const; + + QUrl url() const; +private: + friend class QDeclarativeDomDocument; + friend class QDeclarativeDomComponent; + friend class QDeclarativeDomValue; + friend class QDeclarativeDomValueValueSource; + friend class QDeclarativeDomValueValueInterceptor; + QSharedDataPointer<QDeclarativeDomObjectPrivate> d; +}; + +class QDeclarativeDomValuePrivate; +class QDeclarativeDomBasicValuePrivate; +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueLiteral +{ +public: + QDeclarativeDomValueLiteral(); + QDeclarativeDomValueLiteral(const QDeclarativeDomValueLiteral &); + ~QDeclarativeDomValueLiteral(); + QDeclarativeDomValueLiteral &operator=(const QDeclarativeDomValueLiteral &); + + QString literal() const; + +private: + friend class QDeclarativeDomValue; + QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d; +}; + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueBinding +{ +public: + QDeclarativeDomValueBinding(); + QDeclarativeDomValueBinding(const QDeclarativeDomValueBinding &); + ~QDeclarativeDomValueBinding(); + QDeclarativeDomValueBinding &operator=(const QDeclarativeDomValueBinding &); + + QString binding() const; + +private: + friend class QDeclarativeDomValue; + QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d; +}; + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueValueSource +{ +public: + QDeclarativeDomValueValueSource(); + QDeclarativeDomValueValueSource(const QDeclarativeDomValueValueSource &); + ~QDeclarativeDomValueValueSource(); + QDeclarativeDomValueValueSource &operator=(const QDeclarativeDomValueValueSource &); + + QDeclarativeDomObject object() const; + +private: + friend class QDeclarativeDomValue; + QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d; +}; + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValueValueInterceptor +{ +public: + QDeclarativeDomValueValueInterceptor(); + QDeclarativeDomValueValueInterceptor(const QDeclarativeDomValueValueInterceptor &); + ~QDeclarativeDomValueValueInterceptor(); + QDeclarativeDomValueValueInterceptor &operator=(const QDeclarativeDomValueValueInterceptor &); + + QDeclarativeDomObject object() const; + +private: + friend class QDeclarativeDomValue; + QSharedDataPointer<QDeclarativeDomBasicValuePrivate> d; +}; + + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomComponent : public QDeclarativeDomObject +{ +public: + QDeclarativeDomComponent(); + QDeclarativeDomComponent(const QDeclarativeDomComponent &); + ~QDeclarativeDomComponent(); + QDeclarativeDomComponent &operator=(const QDeclarativeDomComponent &); + + QDeclarativeDomObject componentRoot() const; +}; + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomValue +{ +public: + enum Type { + Invalid, + Literal, + PropertyBinding, + ValueSource, + ValueInterceptor, + Object, + List + }; + + QDeclarativeDomValue(); + QDeclarativeDomValue(const QDeclarativeDomValue &); + ~QDeclarativeDomValue(); + QDeclarativeDomValue &operator=(const QDeclarativeDomValue &); + + Type type() const; + + bool isInvalid() const; + bool isLiteral() const; + bool isBinding() const; + bool isValueSource() const; + bool isValueInterceptor() const; + bool isObject() const; + bool isList() const; + + QDeclarativeDomValueLiteral toLiteral() const; + QDeclarativeDomValueBinding toBinding() const; + QDeclarativeDomValueValueSource toValueSource() const; + QDeclarativeDomValueValueInterceptor toValueInterceptor() const; + QDeclarativeDomObject toObject() const; + QDeclarativeDomList toList() const; + + int position() const; + int length() const; + +private: + friend class QDeclarativeDomProperty; + friend class QDeclarativeDomList; + QSharedDataPointer<QDeclarativeDomValuePrivate> d; +}; + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomList +{ +public: + QDeclarativeDomList(); + QDeclarativeDomList(const QDeclarativeDomList &); + ~QDeclarativeDomList(); + QDeclarativeDomList &operator=(const QDeclarativeDomList &); + + QList<QDeclarativeDomValue> values() const; + + int position() const; + int length() const; + + QList<int> commaPositions() const; + +private: + friend class QDeclarativeDomValue; + QSharedDataPointer<QDeclarativeDomValuePrivate> d; +}; + +class QDeclarativeDomImportPrivate; +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDomImport +{ +public: + enum Type { Library, File }; + + QDeclarativeDomImport(); + QDeclarativeDomImport(const QDeclarativeDomImport &); + ~QDeclarativeDomImport(); + QDeclarativeDomImport &operator=(const QDeclarativeDomImport &); + + Type type() const; + QString uri() const; + QString version() const; + QString qualifier() const; + +private: + friend class QDeclarativeDomDocument; + QSharedDataPointer<QDeclarativeDomImportPrivate> d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEDOM_P_H diff --git a/src/declarative/qml/qdeclarativedom_p_p.h b/src/declarative/qml/qdeclarativedom_p_p.h new file mode 100644 index 00000000..720d8289 --- /dev/null +++ b/src/declarative/qml/qdeclarativedom_p_p.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEDOM_P_P_H +#define QDECLARATIVEDOM_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativeparser_p.h" + +#include <QtCore/QtGlobal> + +QT_BEGIN_NAMESPACE + +class QDeclarativeDomDocumentPrivate : public QSharedData +{ +public: + QDeclarativeDomDocumentPrivate(); + QDeclarativeDomDocumentPrivate(const QDeclarativeDomDocumentPrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QDeclarativeDomDocumentPrivate(); + + QList<QDeclarativeError> errors; + QList<QDeclarativeDomImport> imports; + QDeclarativeParser::Object *root; + QList<int> automaticSemicolonOffsets; +}; + +class QDeclarativeDomObjectPrivate : public QSharedData +{ +public: + QDeclarativeDomObjectPrivate(); + QDeclarativeDomObjectPrivate(const QDeclarativeDomObjectPrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QDeclarativeDomObjectPrivate(); + + typedef QList<QPair<QDeclarativeParser::Property *, QByteArray> > Properties; + Properties properties() const; + Properties properties(QDeclarativeParser::Property *) const; + + QDeclarativeParser::Object *object; +}; + +class QDeclarativeDomPropertyPrivate : public QSharedData +{ +public: + QDeclarativeDomPropertyPrivate(); + QDeclarativeDomPropertyPrivate(const QDeclarativeDomPropertyPrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QDeclarativeDomPropertyPrivate(); + + QByteArray propertyName; + QDeclarativeParser::Property *property; +}; + +class QDeclarativeDomDynamicPropertyPrivate : public QSharedData +{ +public: + QDeclarativeDomDynamicPropertyPrivate(); + QDeclarativeDomDynamicPropertyPrivate(const QDeclarativeDomDynamicPropertyPrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QDeclarativeDomDynamicPropertyPrivate(); + + bool valid; + QDeclarativeParser::Object::DynamicProperty property; +}; + +class QDeclarativeDomValuePrivate : public QSharedData +{ +public: + QDeclarativeDomValuePrivate(); + QDeclarativeDomValuePrivate(const QDeclarativeDomValuePrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QDeclarativeDomValuePrivate(); + + QDeclarativeParser::Property *property; + QDeclarativeParser::Value *value; +}; + +class QDeclarativeDomBasicValuePrivate : public QSharedData +{ +public: + QDeclarativeDomBasicValuePrivate(); + QDeclarativeDomBasicValuePrivate(const QDeclarativeDomBasicValuePrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QDeclarativeDomBasicValuePrivate(); + + QDeclarativeParser::Value *value; +}; + +class QDeclarativeDomImportPrivate : public QSharedData +{ +public: + QDeclarativeDomImportPrivate(); + QDeclarativeDomImportPrivate(const QDeclarativeDomImportPrivate &o) + : QSharedData(o) { qFatal("Not impl"); } + ~QDeclarativeDomImportPrivate(); + + enum Type { Library, File }; + + Type type; + QString uri; + QString version; + QString qualifier; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEDOM_P_P_H + diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp new file mode 100644 index 00000000..39a1733e --- /dev/null +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -0,0 +1,2523 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativeengine_p.h" +#include "qdeclarativeengine.h" + +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativecompiler_p.h" +#include "private/qdeclarativeglobalscriptclass_p.h" +#include "qdeclarative.h" +#include "qdeclarativecontext.h" +#include "qdeclarativeexpression.h" +#include "qdeclarativecomponent.h" +#include "private/qdeclarativebinding_p_p.h" +#include "private/qdeclarativevme_p.h" +#include "private/qdeclarativeenginedebugservice_p.h" +#include "private/qdeclarativestringconverters_p.h" +#include "private/qdeclarativexmlhttprequest_p.h" +#include "private/qdeclarativesqldatabase_p.h" +#include "private/qdeclarativetypenamescriptclass_p.h" +#include "private/qdeclarativelistscriptclass_p.h" +#include "qdeclarativescriptstring.h" +#include "private/qdeclarativeglobal_p.h" +#include "private/qdeclarativeworkerscript_p.h" +#include "private/qdeclarativecomponent_p.h" +#include "qdeclarativenetworkaccessmanagerfactory.h" +#include "qdeclarativeimageprovider.h" +#include "private/qdeclarativedirparser_p.h" +#include "qdeclarativeextensioninterface.h" +#include "private/qdeclarativelist_p.h" +#include "private/qdeclarativetypenamecache_p.h" +#include "private/qdeclarativeinclude_p.h" +#include "private/qdeclarativenotifier_p.h" +#include "private/qdeclarativedebugtrace_p.h" +#include "private/qdeclarativeapplication_p.h" +#include "private/qjsdebugservice_p.h" + +#include <QtCore/qmetaobject.h> +#include <QScriptClass> +#include <QNetworkReply> +#include <QNetworkRequest> +#include <QNetworkAccessManager> +#include <QDesktopServices> +#include <QTimer> +#include <QList> +#include <QPair> +#include <QDebug> +#include <QMetaObject> +#include <QStack> +#include <QMap> +#include <QPluginLoader> +#include <QtGui/qfontdatabase.h> +#include <QtCore/qlibraryinfo.h> +#include <QtCore/qthreadstorage.h> +#include <QtCore/qthread.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdir.h> +#include <QtCore/qmutex.h> +#include <QtGui/qcolor.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qsound.h> +#include <QtCore/qcryptographichash.h> + +#include <private/qobject_p.h> +#include <private/qscriptdeclarativeclass_p.h> + +#include <private/qdeclarativeitemsmodule_p.h> +#include <private/qdeclarativeutilmodule_p.h> + +#ifdef Q_OS_WIN // for %APPDATA% +#include <qt_windows.h> +#include <qlibrary.h> +#include <windows.h> + +#define CSIDL_APPDATA 0x001a // <username>\Application Data +#endif + +Q_DECLARE_METATYPE(QDeclarativeProperty) + +QT_BEGIN_NAMESPACE + +/*! + \qmlclass QtObject QObject + \ingroup qml-utility-elements + \since 4.7 + \brief The QtObject element is the most basic element in QML. + + The QtObject element is a non-visual element which contains only the + objectName property. + + It can be useful to create a QtObject if you need an extremely + lightweight element to enclose a set of custom properties: + + \snippet doc/src/snippets/declarative/qtobject.qml 0 + + It can also be useful for C++ integration, as it is just a plain + QObject. See the QObject documentation for further details. +*/ +/*! + \qmlproperty string QML:QtObject::objectName + This property holds the QObject::objectName for this specific object instance. + + This allows a C++ application to locate an item within a QML component + using the QObject::findChild() method. For example, the following C++ + application locates the child \l Rectangle item and dynamically changes its + \c color value: + + \qml + // MyRect.qml + + import QtQuick 1.0 + + Item { + width: 200; height: 200 + + Rectangle { + anchors.fill: parent + color: "red" + objectName: "myRect" + } + } + \endqml + + \code + // main.cpp + + QDeclarativeView view; + view.setSource(QUrl::fromLocalFile("MyRect.qml")); + view.show(); + + QDeclarativeItem *item = view.rootObject()->findChild<QDeclarativeItem*>("myRect"); + if (item) + item->setProperty("color", QColor(Qt::yellow)); + \endcode +*/ + +struct StaticQtMetaObject : public QObject +{ + static const QMetaObject *get() + { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; } +}; + +static bool qt_QmlQtModule_registered = false; +bool QDeclarativeEnginePrivate::qml_debugging_enabled = false; + +void QDeclarativeEnginePrivate::defineModule() +{ + qmlRegisterType<QDeclarativeComponent>("QtQuick",1,0,"Component"); + qmlRegisterType<QObject>("QtQuick",1,0,"QtObject"); + qmlRegisterType<QDeclarativeWorkerScript>("QtQuick",1,0,"WorkerScript"); + +#ifndef QT_NO_IMPORT_QT47_QML + qmlRegisterType<QDeclarativeComponent>("Qt",4,7,"Component"); + qmlRegisterType<QObject>("Qt",4,7,"QtObject"); + qmlRegisterType<QDeclarativeWorkerScript>("Qt",4,7,"WorkerScript"); +#endif + + qmlRegisterType<QDeclarativeBinding>(); +} + +/*! +\qmlclass QML:Qt QDeclarativeEnginePrivate + \ingroup qml-utility-elements +\brief The QML global Qt object provides useful enums and functions from Qt. + +\keyword QmlGlobalQtObject + +\brief The \c Qt object provides useful enums and functions from Qt, for use in all QML files. + +The \c Qt object is a global object with utility functions, properties and enums. + +It is not instantiable; to use it, call the members of the global \c Qt object directly. +For example: + +\qml +import QtQuick 1.0 + +Text { + color: Qt.rgba(1, 0, 0, 1) + text: Qt.md5("hello, world") +} +\endqml + + +\section1 Enums + +The Qt object contains the enums available in the \l {Qt Namespace}. For example, you can access +the \l Qt::LeftButton and \l Qt::RightButton enum values as \c Qt.LeftButton and \c Qt.RightButton. + + +\section1 Types +The Qt object also contains helper functions for creating objects of specific +data types. This is primarily useful when setting the properties of an item +when the property has one of the following types: + +\list +\o \c color - use \l{QML:Qt::rgba()}{Qt.rgba()}, \l{QML:Qt::hsla()}{Qt.hsla()}, \l{QML:Qt::darker()}{Qt.darker()}, \l{QML:Qt::lighter()}{Qt.lighter()} or \l{QML:Qt::tint()}{Qt.tint()} +\o \c rect - use \l{QML:Qt::rect()}{Qt.rect()} +\o \c point - use \l{QML:Qt::point()}{Qt.point()} +\o \c size - use \l{QML:Qt::size()}{Qt.size()} +\o \c vector3d - use \l{QML:Qt::vector3d()}{Qt.vector3d()} +\endlist + +There are also string based constructors for these types. See \l{qdeclarativebasictypes.html}{QML Basic Types} for more information. + +\section1 Date/Time Formatters + +The Qt object contains several functions for formatting QDateTime, QDate and QTime values. + +\list + \o \l{QML:Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)} + \o \l{QML:Qt::formatDate}{string Qt.formatDate(datetime date, variant format)} + \o \l{QML:Qt::formatTime}{string Qt.formatTime(datetime date, variant format)} +\endlist + +The format specification is described at \l{QML:Qt::formatDateTime}{Qt.formatDateTime}. + + +\section1 Dynamic Object Creation +The following functions on the global object allow you to dynamically create QML +items from files or strings. See \l{Dynamic Object Management in QML} for an overview +of their use. + +\list + \o \l{QML:Qt::createComponent()}{object Qt.createComponent(url)} + \o \l{QML:Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)} +\endlist +*/ + + +/*! + \qmlproperty object QML:Qt::application + \since QtQuick 1.1 + + The \c application object provides access to global application state + properties shared by many QML components. + + Its properties are: + + \table + \row + \o \c application.active + \o + This read-only property indicates whether the application is the top-most and focused + application, and the user is able to interact with the application. The property + is false when the application is in the background, the device keylock or screen + saver is active, the screen backlight is turned off, or the global system dialog + is being displayed on top of the application. It can be used for stopping and + pausing animations, timers and active processing of data in order to save device + battery power and free device memory and processor load when the application is not + active. + + \row + \o \c application.layoutDirection + \o + This read-only property can be used to query the default layout direction of the + application. On system start-up, the default layout direction depends on the + application's language. The property has a value of \c Qt.RightToLeft in locales + where text and graphic elements are read from right to left, and \c Qt.LeftToRight + where the reading direction flows from left to right. You can bind to this + property to customize your application layouts to support both layout directions. + + Possible values are: + + \list + \o Qt.LeftToRight - Text and graphics elements should be positioned + from left to right. + \o Qt.RightToLeft - Text and graphics elements should be positioned + from right to left. + \endlist + \endtable + + The following example uses the \c application object to indicate + whether the application is currently active: + + \snippet doc/src/snippets/declarative/application.qml document + +*/ + + +/*! +\qmlmethod object Qt::include(string url, jsobject callback) + +Includes another JavaScript file. This method can only be used from within JavaScript files, +and not regular QML files. + +This imports all functions from \a url into the current script's namespace. + +Qt.include() returns an object that describes the status of the operation. The object has +a single property, \c {status}, that is set to one of the following values: + +\table +\header \o Symbol \o Value \o Description +\row \o result.OK \o 0 \o The include completed successfully. +\row \o result.LOADING \o 1 \o Data is being loaded from the network. +\row \o result.NETWORK_ERROR \o 2 \o A network error occurred while fetching the url. +\row \o result.EXCEPTION \o 3 \o A JavaScript exception occurred while executing the included code. +An additional \c exception property will be set in this case. +\endtable + +The \c status property will be updated as the operation progresses. + +If provided, \a callback is invoked when the operation completes. The callback is passed +the same object as is returned from the Qt.include() call. +*/ +// Qt.include() is implemented in qdeclarativeinclude.cpp + + +QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e) +: captureProperties(false), rootContext(0), isDebugging(false), + outputWarningsToStdErr(true), contextClass(0), sharedContext(0), sharedScope(0), + objectClass(0), valueTypeClass(0), globalClass(0), cleanup(0), erroredBindings(0), + inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttached(0), + inBeginCreate(false), networkAccessManager(0), networkAccessManagerFactory(0), + typeLoader(e), importDatabase(e), uniqueId(1) +{ + if (!qt_QmlQtModule_registered) { + qt_QmlQtModule_registered = true; + QDeclarativeItemModule::defineModule(); + QDeclarativeUtilModule::defineModule(); + QDeclarativeEnginePrivate::defineModule(); + QDeclarativeValueTypeFactory::registerValueTypes(); + } + globalClass = new QDeclarativeGlobalScriptClass(&scriptEngine); +} + +/*! + \qmlmethod url Qt::resolvedUrl(url url) + Returns \a url resolved relative to the URL of the caller. +*/ +QUrl QDeclarativeScriptEngine::resolvedUrl(QScriptContext *context, const QUrl& url) +{ + if (p) { + QDeclarativeContextData *ctxt = p->getContext(context); + if (ctxt) + return ctxt->resolvedUrl(url); + else + return p->getUrl(context).resolved(url); + } + return baseUrl.resolved(url); +} + +QDeclarativeScriptEngine::QDeclarativeScriptEngine(QDeclarativeEnginePrivate *priv) +: p(priv), sqlQueryClass(0), namedNodeMapClass(0), nodeListClass(0) +{ + // Note that all documentation for stuff put on the global object goes in + // doc/src/declarative/globalobject.qdoc + + bool mainthread = priv != 0; + + QScriptValue qtObject = + newQMetaObject(StaticQtMetaObject::get()); + globalObject().setProperty(QLatin1String("Qt"), qtObject); + +#ifndef QT_NO_DESKTOPSERVICES + offlineStoragePath = QDesktopServices::storageLocation(QDesktopServices::DataLocation).replace(QLatin1Char('/'), QDir::separator()) + + QDir::separator() + QLatin1String("QML") + + QDir::separator() + QLatin1String("OfflineStorage"); +#endif + +#ifndef QT_NO_XMLSTREAMREADER + qt_add_qmlxmlhttprequest(this); +#endif + qt_add_qmlsqldatabase(this); + // XXX A Multimedia "Qt.Sound" class also needs to be made available, + // XXX but we don't want a dependency in that cirection. + // XXX When the above a done some better way, that way should also be + // XXX used to add Qt.Sound class. + + //types + if (mainthread) + qtObject.setProperty(QLatin1String("include"), newFunction(QDeclarativeInclude::include, 2)); + else + qtObject.setProperty(QLatin1String("include"), newFunction(QDeclarativeInclude::worker_include, 2)); + + qtObject.setProperty(QLatin1String("isQtObject"), newFunction(QDeclarativeEnginePrivate::isQtObject, 1)); + qtObject.setProperty(QLatin1String("rgba"), newFunction(QDeclarativeEnginePrivate::rgba, 4)); + qtObject.setProperty(QLatin1String("hsla"), newFunction(QDeclarativeEnginePrivate::hsla, 4)); + qtObject.setProperty(QLatin1String("rect"), newFunction(QDeclarativeEnginePrivate::rect, 4)); + qtObject.setProperty(QLatin1String("point"), newFunction(QDeclarativeEnginePrivate::point, 2)); + qtObject.setProperty(QLatin1String("size"), newFunction(QDeclarativeEnginePrivate::size, 2)); + qtObject.setProperty(QLatin1String("vector3d"), newFunction(QDeclarativeEnginePrivate::vector3d, 3)); + + if (mainthread) { + //color helpers + qtObject.setProperty(QLatin1String("lighter"), newFunction(QDeclarativeEnginePrivate::lighter, 1)); + qtObject.setProperty(QLatin1String("darker"), newFunction(QDeclarativeEnginePrivate::darker, 1)); + qtObject.setProperty(QLatin1String("tint"), newFunction(QDeclarativeEnginePrivate::tint, 2)); + } + +#ifndef QT_NO_DATESTRING + //date/time formatting + qtObject.setProperty(QLatin1String("formatDate"),newFunction(QDeclarativeEnginePrivate::formatDate, 2)); + qtObject.setProperty(QLatin1String("formatTime"),newFunction(QDeclarativeEnginePrivate::formatTime, 2)); + qtObject.setProperty(QLatin1String("formatDateTime"),newFunction(QDeclarativeEnginePrivate::formatDateTime, 2)); +#endif + + //misc methods + qtObject.setProperty(QLatin1String("openUrlExternally"),newFunction(QDeclarativeEnginePrivate::desktopOpenUrl, 1)); + qtObject.setProperty(QLatin1String("fontFamilies"),newFunction(QDeclarativeEnginePrivate::fontFamilies, 0)); + qtObject.setProperty(QLatin1String("md5"),newFunction(QDeclarativeEnginePrivate::md5, 1)); + qtObject.setProperty(QLatin1String("btoa"),newFunction(QDeclarativeEnginePrivate::btoa, 1)); + qtObject.setProperty(QLatin1String("atob"),newFunction(QDeclarativeEnginePrivate::atob, 1)); + qtObject.setProperty(QLatin1String("quit"), newFunction(QDeclarativeEnginePrivate::quit, 0)); + qtObject.setProperty(QLatin1String("resolvedUrl"),newFunction(QDeclarativeScriptEngine::resolvedUrl, 1)); + + if (mainthread) { + qtObject.setProperty(QLatin1String("createQmlObject"), + newFunction(QDeclarativeEnginePrivate::createQmlObject, 1)); + qtObject.setProperty(QLatin1String("createComponent"), + newFunction(QDeclarativeEnginePrivate::createComponent, 1)); + } + + //firebug/webkit compat + QScriptValue consoleObject = newObject(); + consoleObject.setProperty(QLatin1String("log"),newFunction(QDeclarativeEnginePrivate::consoleLog, 1)); + consoleObject.setProperty(QLatin1String("debug"),newFunction(QDeclarativeEnginePrivate::consoleLog, 1)); + globalObject().setProperty(QLatin1String("console"), consoleObject); + + // translation functions need to be installed + // before the global script class is constructed (QTBUG-6437) + installTranslatorFunctions(); +} + +QDeclarativeScriptEngine::~QDeclarativeScriptEngine() +{ + delete sqlQueryClass; + delete nodeListClass; + delete namedNodeMapClass; +} + +QScriptValue QDeclarativeScriptEngine::resolvedUrl(QScriptContext *ctxt, QScriptEngine *engine) +{ + QString arg = ctxt->argument(0).toString(); + QUrl r = QDeclarativeScriptEngine::get(engine)->resolvedUrl(ctxt,QUrl(arg)); + return QScriptValue(r.toString()); +} + +QNetworkAccessManager *QDeclarativeScriptEngine::networkAccessManager() +{ + return p->getNetworkAccessManager(); +} + +QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate() +{ + Q_ASSERT(inProgressCreations == 0); + Q_ASSERT(bindValues.isEmpty()); + Q_ASSERT(parserStatus.isEmpty()); + + while (cleanup) { + QDeclarativeCleanup *c = cleanup; + cleanup = c->next; + if (cleanup) cleanup->prev = &cleanup; + c->next = 0; + c->prev = 0; + c->clear(); + } + + delete rootContext; + rootContext = 0; + delete contextClass; + contextClass = 0; + delete objectClass; + objectClass = 0; + delete valueTypeClass; + valueTypeClass = 0; + delete typeNameClass; + typeNameClass = 0; + delete listClass; + listClass = 0; + delete globalClass; + globalClass = 0; + + for(QHash<int, QDeclarativeCompiledData*>::ConstIterator iter = m_compositeTypes.constBegin(); iter != m_compositeTypes.constEnd(); ++iter) + (*iter)->release(); + for(QHash<const QMetaObject *, QDeclarativePropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter) + (*iter)->release(); + for(QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter) + (*iter)->release(); + +} + +void QDeclarativeEnginePrivate::clear(SimpleList<QDeclarativeAbstractBinding> &bvs) +{ + bvs.clear(); +} + +void QDeclarativeEnginePrivate::clear(SimpleList<QDeclarativeParserStatus> &pss) +{ + for (int ii = 0; ii < pss.count; ++ii) { + QDeclarativeParserStatus *ps = pss.at(ii); + if(ps) + ps->d = 0; + } + pss.clear(); +} + +void QDeclarativePrivate::qdeclarativeelement_destructor(QObject *o) +{ + QObjectPrivate *p = QObjectPrivate::get(o); + if (p->declarativeData) { + QDeclarativeData *d = static_cast<QDeclarativeData*>(p->declarativeData); + if (d->ownContext && d->context) { + d->context->destroy(); + d->context = 0; + } + } +} + +void QDeclarativeData::destroyed(QAbstractDeclarativeData *d, QObject *o) +{ + static_cast<QDeclarativeData *>(d)->destroyed(o); +} + +void QDeclarativeData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p) +{ + static_cast<QDeclarativeData *>(d)->parentChanged(o, p); +} + +void QDeclarativeData::objectNameChanged(QAbstractDeclarativeData *d, QObject *o) +{ + static_cast<QDeclarativeData *>(d)->objectNameChanged(o); +} + +void QDeclarativeEnginePrivate::init() +{ + Q_Q(QDeclarativeEngine); + qRegisterMetaType<QVariant>("QVariant"); + qRegisterMetaType<QDeclarativeScriptString>("QDeclarativeScriptString"); + qRegisterMetaType<QScriptValue>("QScriptValue"); + qRegisterMetaType<QDeclarativeComponent::Status>("QDeclarativeComponent::Status"); + + QDeclarativeData::init(); + + contextClass = new QDeclarativeContextScriptClass(q); + objectClass = new QDeclarativeObjectScriptClass(q); + valueTypeClass = new QDeclarativeValueTypeScriptClass(q); + typeNameClass = new QDeclarativeTypeNameScriptClass(q); + listClass = new QDeclarativeListScriptClass(q); + rootContext = new QDeclarativeContext(q,true); + + QScriptValue applicationObject = objectClass->newQObject(new QDeclarativeApplication(q)); + scriptEngine.globalObject().property(QLatin1String("Qt")).setProperty(QLatin1String("application"), applicationObject); + + if (QCoreApplication::instance()->thread() == q->thread() && + QDeclarativeEngineDebugService::isDebuggingEnabled()) { + isDebugging = true; + QDeclarativeEngineDebugService::instance()->addEngine(q); + QJSDebugService::instance()->addEngine(q); + } +} + +QDeclarativeWorkerScriptEngine *QDeclarativeEnginePrivate::getWorkerScriptEngine() +{ + Q_Q(QDeclarativeEngine); + if (!workerScriptEngine) + workerScriptEngine = new QDeclarativeWorkerScriptEngine(q); + return workerScriptEngine; +} + +/*! + \class QDeclarativeEngine + \since 4.7 + \brief The QDeclarativeEngine class provides an environment for instantiating QML components. + \mainclass + + Each QML component is instantiated in a QDeclarativeContext. + QDeclarativeContext's are essential for passing data to QML + components. In QML, contexts are arranged hierarchically and this + hierarchy is managed by the QDeclarativeEngine. + + Prior to creating any QML components, an application must have + created a QDeclarativeEngine to gain access to a QML context. The + following example shows how to create a simple Text item. + + \code + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 1.0\nText { text: \"Hello world!\" }", QUrl()); + QDeclarativeItem *item = qobject_cast<QDeclarativeItem *>(component.create()); + + //add item to view, etc + ... + \endcode + + In this case, the Text item will be created in the engine's + \l {QDeclarativeEngine::rootContext()}{root context}. + + \sa QDeclarativeComponent QDeclarativeContext +*/ + +/*! + Create a new QDeclarativeEngine with the given \a parent. +*/ +QDeclarativeEngine::QDeclarativeEngine(QObject *parent) +: QObject(*new QDeclarativeEnginePrivate(this), parent) +{ + Q_D(QDeclarativeEngine); + d->init(); +} + +/*! + Destroys the QDeclarativeEngine. + + Any QDeclarativeContext's created on this engine will be + invalidated, but not destroyed (unless they are parented to the + QDeclarativeEngine object). +*/ +QDeclarativeEngine::~QDeclarativeEngine() +{ + Q_D(QDeclarativeEngine); + if (d->isDebugging) { + QDeclarativeEngineDebugService::instance()->remEngine(this); + QJSDebugService::instance()->removeEngine(this); + } +} + +/*! \fn void QDeclarativeEngine::quit() + This signal is emitted when the QML loaded by the engine would like to quit. + */ + +/*! \fn void QDeclarativeEngine::warnings(const QList<QDeclarativeError> &warnings) + This signal is emitted when \a warnings messages are generated by QML. + */ + +/*! + Clears the engine's internal component cache. + + Normally the QDeclarativeEngine caches components loaded from qml + files. This method clears this cache and forces the component to be + reloaded. + */ +void QDeclarativeEngine::clearComponentCache() +{ + Q_D(QDeclarativeEngine); + d->typeLoader.clearCache(); +} + +/*! + Returns the engine's root context. + + The root context is automatically created by the QDeclarativeEngine. + Data that should be available to all QML component instances + instantiated by the engine should be put in the root context. + + Additional data that should only be available to a subset of + component instances should be added to sub-contexts parented to the + root context. +*/ +QDeclarativeContext *QDeclarativeEngine::rootContext() const +{ + Q_D(const QDeclarativeEngine); + return d->rootContext; +} + +/*! + Sets the \a factory to use for creating QNetworkAccessManager(s). + + QNetworkAccessManager is used for all network access by QML. By + implementing a factory it is possible to create custom + QNetworkAccessManager with specialized caching, proxy and cookie + support. + + The factory must be set before executing the engine. +*/ +void QDeclarativeEngine::setNetworkAccessManagerFactory(QDeclarativeNetworkAccessManagerFactory *factory) +{ + Q_D(QDeclarativeEngine); + QMutexLocker locker(&d->mutex); + d->networkAccessManagerFactory = factory; +} + +/*! + Returns the current QDeclarativeNetworkAccessManagerFactory. + + \sa setNetworkAccessManagerFactory() +*/ +QDeclarativeNetworkAccessManagerFactory *QDeclarativeEngine::networkAccessManagerFactory() const +{ + Q_D(const QDeclarativeEngine); + return d->networkAccessManagerFactory; +} + +QNetworkAccessManager *QDeclarativeEnginePrivate::createNetworkAccessManager(QObject *parent) const +{ + QMutexLocker locker(&mutex); + QNetworkAccessManager *nam; + if (networkAccessManagerFactory) { + nam = networkAccessManagerFactory->create(parent); + } else { + nam = new QNetworkAccessManager(parent); + } + + return nam; +} + +QNetworkAccessManager *QDeclarativeEnginePrivate::getNetworkAccessManager() const +{ + Q_Q(const QDeclarativeEngine); + if (!networkAccessManager) + networkAccessManager = createNetworkAccessManager(const_cast<QDeclarativeEngine*>(q)); + return networkAccessManager; +} + +/*! + Returns a common QNetworkAccessManager which can be used by any QML + element instantiated by this engine. + + If a QDeclarativeNetworkAccessManagerFactory has been set and a + QNetworkAccessManager has not yet been created, the + QDeclarativeNetworkAccessManagerFactory will be used to create the + QNetworkAccessManager; otherwise the returned QNetworkAccessManager + will have no proxy or cache set. + + \sa setNetworkAccessManagerFactory() +*/ +QNetworkAccessManager *QDeclarativeEngine::networkAccessManager() const +{ + Q_D(const QDeclarativeEngine); + return d->getNetworkAccessManager(); +} + +/*! + + Sets the \a provider to use for images requested via the \e + image: url scheme, with host \a providerId. The QDeclarativeEngine + takes ownership of \a provider. + + Image providers enable support for pixmap and threaded image + requests. See the QDeclarativeImageProvider documentation for details on + implementing and using image providers. + + All required image providers should be added to the engine before any + QML sources files are loaded. + + \sa removeImageProvider() +*/ +void QDeclarativeEngine::addImageProvider(const QString &providerId, QDeclarativeImageProvider *provider) +{ + Q_D(QDeclarativeEngine); + QMutexLocker locker(&d->mutex); + d->imageProviders.insert(providerId.toLower(), QSharedPointer<QDeclarativeImageProvider>(provider)); +} + +/*! + Returns the QDeclarativeImageProvider set for \a providerId. +*/ +QDeclarativeImageProvider *QDeclarativeEngine::imageProvider(const QString &providerId) const +{ + Q_D(const QDeclarativeEngine); + QMutexLocker locker(&d->mutex); + return d->imageProviders.value(providerId).data(); +} + +/*! + Removes the QDeclarativeImageProvider for \a providerId. + + Returns the provider if it was found; otherwise returns 0. + + \sa addImageProvider() +*/ +void QDeclarativeEngine::removeImageProvider(const QString &providerId) +{ + Q_D(QDeclarativeEngine); + QMutexLocker locker(&d->mutex); + d->imageProviders.take(providerId); +} + +QDeclarativeImageProvider::ImageType QDeclarativeEnginePrivate::getImageProviderType(const QUrl &url) +{ + QMutexLocker locker(&mutex); + QSharedPointer<QDeclarativeImageProvider> provider = imageProviders.value(url.host()); + locker.unlock(); + if (provider) + return provider->imageType(); + return static_cast<QDeclarativeImageProvider::ImageType>(-1); +} + +QImage QDeclarativeEnginePrivate::getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size) +{ + QMutexLocker locker(&mutex); + QImage image; + QSharedPointer<QDeclarativeImageProvider> provider = imageProviders.value(url.host()); + locker.unlock(); + if (provider) { + QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1); + image = provider->requestImage(imageId, size, req_size); + } + return image; +} + +QPixmap QDeclarativeEnginePrivate::getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size) +{ + QMutexLocker locker(&mutex); + QPixmap pixmap; + QSharedPointer<QDeclarativeImageProvider> provider = imageProviders.value(url.host()); + locker.unlock(); + if (provider) { + QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1); + pixmap = provider->requestPixmap(imageId, size, req_size); + } + return pixmap; +} + +/*! + Return the base URL for this engine. The base URL is only used to + resolve components when a relative URL is passed to the + QDeclarativeComponent constructor. + + If a base URL has not been explicitly set, this method returns the + application's current working directory. + + \sa setBaseUrl() +*/ +QUrl QDeclarativeEngine::baseUrl() const +{ + Q_D(const QDeclarativeEngine); + if (d->baseUrl.isEmpty()) { + return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator()); + } else { + return d->baseUrl; + } +} + +/*! + Set the base URL for this engine to \a url. + + \sa baseUrl() +*/ +void QDeclarativeEngine::setBaseUrl(const QUrl &url) +{ + Q_D(QDeclarativeEngine); + d->baseUrl = url; +} + +/*! + Returns true if warning messages will be output to stderr in addition + to being emitted by the warnings() signal, otherwise false. + + The default value is true. +*/ +bool QDeclarativeEngine::outputWarningsToStandardError() const +{ + Q_D(const QDeclarativeEngine); + return d->outputWarningsToStdErr; +} + +/*! + Set whether warning messages will be output to stderr to \a enabled. + + If \a enabled is true, any warning messages generated by QML will be + output to stderr and emitted by the warnings() signal. If \a enabled + is false, on the warnings() signal will be emitted. This allows + applications to handle warning output themselves. + + The default value is true. +*/ +void QDeclarativeEngine::setOutputWarningsToStandardError(bool enabled) +{ + Q_D(QDeclarativeEngine); + d->outputWarningsToStdErr = enabled; +} + +/*! + Returns the QDeclarativeContext for the \a object, or 0 if no + context has been set. + + When the QDeclarativeEngine instantiates a QObject, the context is + set automatically. + */ +QDeclarativeContext *QDeclarativeEngine::contextForObject(const QObject *object) +{ + if(!object) + return 0; + + QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object)); + + QDeclarativeData *data = + static_cast<QDeclarativeData *>(priv->declarativeData); + + if (!data) + return 0; + else if (data->outerContext) + return data->outerContext->asQDeclarativeContext(); + else + return 0; +} + +/*! + Sets the QDeclarativeContext for the \a object to \a context. + If the \a object already has a context, a warning is + output, but the context is not changed. + + When the QDeclarativeEngine instantiates a QObject, the context is + set automatically. + */ +void QDeclarativeEngine::setContextForObject(QObject *object, QDeclarativeContext *context) +{ + if (!object || !context) + return; + + QDeclarativeData *data = QDeclarativeData::get(object, true); + if (data->context) { + qWarning("QDeclarativeEngine::setContextForObject(): Object already has a QDeclarativeContext"); + return; + } + + QDeclarativeContextData *contextData = QDeclarativeContextData::get(context); + contextData->addObject(object); +} + +/*! + \enum QDeclarativeEngine::ObjectOwnership + + Ownership controls whether or not QML automatically destroys the + QObject when the object is garbage collected by the JavaScript + engine. The two ownership options are: + + \value CppOwnership The object is owned by C++ code, and will + never be deleted by QML. The JavaScript destroy() method cannot be + used on objects with CppOwnership. This option is similar to + QScriptEngine::QtOwnership. + + \value JavaScriptOwnership The object is owned by JavaScript. + When the object is returned to QML as the return value of a method + call or property access, QML will delete the object if there are no + remaining JavaScript references to it and it has no + QObject::parent(). This option is similar to + QScriptEngine::ScriptOwnership. + + Generally an application doesn't need to set an object's ownership + explicitly. QML uses a heuristic to set the default object + ownership. By default, an object that is created by QML has + JavaScriptOwnership. The exception to this are the root objects + created by calling QDeclarativeCompnent::create() or + QDeclarativeComponent::beginCreate() which have CppOwnership by + default. The ownership of these root-level objects is considered to + have been transferred to the C++ caller. + + Objects not-created by QML have CppOwnership by default. The + exception to this is objects returned from a C++ method call. The + ownership of these objects is passed to JavaScript. + + Calling setObjectOwnership() overrides the default ownership + heuristic used by QML. +*/ + +/*! + Sets the \a ownership of \a object. +*/ +void QDeclarativeEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership) +{ + if (!object) + return; + + QDeclarativeData *ddata = QDeclarativeData::get(object, true); + if (!ddata) + return; + + ddata->indestructible = (ownership == CppOwnership)?true:false; + ddata->explicitIndestructibleSet = true; +} + +/*! + Returns the ownership of \a object. +*/ +QDeclarativeEngine::ObjectOwnership QDeclarativeEngine::objectOwnership(QObject *object) +{ + if (!object) + return CppOwnership; + + QDeclarativeData *ddata = QDeclarativeData::get(object, false); + if (!ddata) + return CppOwnership; + else + return ddata->indestructible?CppOwnership:JavaScriptOwnership; +} + +Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object) +{ + QDeclarativeData *data = QDeclarativeData::get(object); + + if (data && data->deferredComponent) { + if (QDeclarativeDebugService::isDebuggingEnabled()) { + QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating); + QDeclarativeType *type = QDeclarativeMetaType::qmlType(object->metaObject()); + QString typeName = type ? QLatin1String(type->qmlTypeName()) : QString::fromLatin1(object->metaObject()->className()); + QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, typeName); + if (data->outerContext) + QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Creating, data->outerContext->url, data->lineNumber); + } + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(data->context->engine); + + QDeclarativeComponentPrivate::ConstructionState state; + QDeclarativeComponentPrivate::beginDeferred(ep, object, &state); + + data->deferredComponent->release(); + data->deferredComponent = 0; + + QDeclarativeComponentPrivate::complete(ep, &state); + QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Creating); + } +} + +QDeclarativeContext *qmlContext(const QObject *obj) +{ + return QDeclarativeEngine::contextForObject(obj); +} + +QDeclarativeEngine *qmlEngine(const QObject *obj) +{ + QDeclarativeContext *context = QDeclarativeEngine::contextForObject(obj); + return context?context->engine():0; +} + +QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create) +{ + QDeclarativeData *data = QDeclarativeData::get(object); + if (!data) + return 0; // Attached properties are only on objects created by QML + + QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0; + if (rv || !create) + return rv; + + QDeclarativeAttachedPropertiesFunc pf = QDeclarativeMetaType::attachedPropertiesFuncById(id); + if (!pf) + return 0; + + rv = pf(const_cast<QObject *>(object)); + + if (rv) + data->attachedProperties()->insert(id, rv); + + return rv; +} + +QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object, + const QMetaObject *attachedMetaObject, bool create) +{ + if (*idCache == -1) + *idCache = QDeclarativeMetaType::attachedPropertiesFuncId(attachedMetaObject); + + if (*idCache == -1 || !object) + return 0; + + return qmlAttachedPropertiesObjectById(*idCache, object, create); +} + +QDeclarativeDebuggingEnabler::QDeclarativeDebuggingEnabler() +{ +#ifndef QDECLARATIVE_NO_DEBUG_PROTOCOL + if (!QDeclarativeEnginePrivate::qml_debugging_enabled) { + qDebug("Qml debugging is enabled. Only use this in a safe environment!"); + } + QDeclarativeEnginePrivate::qml_debugging_enabled = true; +#endif +} + + +class QDeclarativeDataExtended { +public: + QDeclarativeDataExtended(); + ~QDeclarativeDataExtended(); + + QHash<int, QObject *> attachedProperties; + QDeclarativeNotifier objectNameNotifier; +}; + +QDeclarativeDataExtended::QDeclarativeDataExtended() +{ +} + +QDeclarativeDataExtended::~QDeclarativeDataExtended() +{ +} + +QDeclarativeNotifier *QDeclarativeData::objectNameNotifier() const +{ + if (!extendedData) extendedData = new QDeclarativeDataExtended; + return &extendedData->objectNameNotifier; +} + +QHash<int, QObject *> *QDeclarativeData::attachedProperties() const +{ + if (!extendedData) extendedData = new QDeclarativeDataExtended; + return &extendedData->attachedProperties; +} + +void QDeclarativeData::destroyed(QObject *object) +{ + if (deferredComponent) + deferredComponent->release(); + + if (nextContextObject) + nextContextObject->prevContextObject = prevContextObject; + if (prevContextObject) + *prevContextObject = nextContextObject; + + QDeclarativeAbstractBinding *binding = bindings; + while (binding) { + QDeclarativeAbstractBinding *next = binding->m_nextBinding; + binding->m_prevBinding = 0; + binding->m_nextBinding = 0; + binding->destroy(); + binding = next; + } + + if (bindingBits) + free(bindingBits); + + if (propertyCache) + propertyCache->release(); + + if (ownContext && context) + context->destroy(); + + while (guards) { + QDeclarativeGuard<QObject> *guard = static_cast<QDeclarativeGuard<QObject> *>(guards); + *guard = (QObject *)0; + guard->objectDestroyed(object); + } + + if (scriptValue) + delete scriptValue; + + if (extendedData) + delete extendedData; + + if (ownMemory) + delete this; +} + +void QDeclarativeData::parentChanged(QObject *, QObject *parent) +{ + if (!parent && scriptValue) { delete scriptValue; scriptValue = 0; } +} + +void QDeclarativeData::objectNameChanged(QObject *) +{ + if (extendedData) objectNameNotifier()->notify(); +} + +bool QDeclarativeData::hasBindingBit(int bit) const +{ + if (bindingBitsSize > bit) + return bindingBits[bit / 32] & (1 << (bit % 32)); + else + return false; +} + +void QDeclarativeData::clearBindingBit(int bit) +{ + if (bindingBitsSize > bit) + bindingBits[bit / 32] &= ~(1 << (bit % 32)); +} + +void QDeclarativeData::setBindingBit(QObject *obj, int bit) +{ + if (bindingBitsSize <= bit) { + int props = obj->metaObject()->propertyCount(); + Q_ASSERT(bit < props); + + int arraySize = (props + 31) / 32; + int oldArraySize = bindingBitsSize / 32; + + bindingBits = (quint32 *)q_check_ptr(realloc(bindingBits, + arraySize * sizeof(quint32))); + + memset(bindingBits + oldArraySize, + 0x00, + sizeof(quint32) * (arraySize - oldArraySize)); + + bindingBitsSize = arraySize * 32; + } + + bindingBits[bit / 32] |= (1 << (bit % 32)); +} + +/*! + Creates a QScriptValue allowing you to use \a object in QML script. + \a engine is the QDeclarativeEngine it is to be created in. + + The QScriptValue returned is a QtScript Object, not a QtScript QObject, due + to the special needs of QML requiring more functionality than a standard + QtScript QObject. +*/ +QScriptValue QDeclarativeEnginePrivate::qmlScriptObject(QObject* object, + QDeclarativeEngine* engine) +{ + QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); + return enginePriv->objectClass->newQObject(object); +} + +/*! + Returns the QDeclarativeContext for the executing QScript \a ctxt. +*/ +QDeclarativeContextData *QDeclarativeEnginePrivate::getContext(QScriptContext *ctxt) +{ + QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3); + Q_ASSERT(scopeNode.isValid()); + Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass); + return contextClass->contextFromValue(scopeNode); +} + +/*! + Returns the QUrl associated with the script \a ctxt for the case that there is + no QDeclarativeContext. +*/ +QUrl QDeclarativeEnginePrivate::getUrl(QScriptContext *ctxt) +{ + QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3); + Q_ASSERT(scopeNode.isValid()); + Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass); + return contextClass->urlFromValue(scopeNode); +} + +QString QDeclarativeEnginePrivate::urlToLocalFileOrQrc(const QUrl& url) +{ + if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0) { + if (url.authority().isEmpty()) + return QLatin1Char(':') + url.path(); + return QString(); + } + return url.toLocalFile(); +} + +/*! +\qmlmethod object Qt::createComponent(url) + +Returns a \l Component object created using the QML file at the specified \a url, +or \c null if an empty string was given. + +The returned component's \l Component::status property indicates whether the +component was successfully created. If the status is \c Component.Error, +see \l Component::errorString() for an error description. + +Call \l {Component::createObject()}{Component.createObject()} on the returned +component to create an object instance of the component. + +For example: + +\snippet doc/src/snippets/declarative/createComponent-simple.qml 0 + +See \l {Dynamic Object Management in QML} for more information on using this function. + +To create a QML object from an arbitrary string of QML (instead of a file), +use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}. +*/ + +QScriptValue QDeclarativeEnginePrivate::createComponent(QScriptContext *ctxt, QScriptEngine *engine) +{ + QDeclarativeEnginePrivate *activeEnginePriv = + static_cast<QDeclarativeScriptEngine*>(engine)->p; + QDeclarativeEngine* activeEngine = activeEnginePriv->q_func(); + + if(ctxt->argumentCount() != 1) { + return ctxt->throwError(QLatin1String("Qt.createComponent(): Invalid arguments")); + } else { + + QString arg = ctxt->argument(0).toString(); + if (arg.isEmpty()) + return engine->nullValue(); + QUrl url = QDeclarativeScriptEngine::get(engine)->resolvedUrl(ctxt, QUrl(arg)); + QDeclarativeContextData* context = activeEnginePriv->getContext(ctxt); + QDeclarativeComponent *c = new QDeclarativeComponent(activeEngine, url, activeEngine); + QDeclarativeComponentPrivate::get(c)->creationContext = context; + QDeclarativeData::get(c, true)->setImplicitDestructible(); + return activeEnginePriv->objectClass->newQObject(c, qMetaTypeId<QDeclarativeComponent*>()); + } +} + +/*! +\qmlmethod object Qt::createQmlObject(string qml, object parent, string filepath) + +Returns a new object created from the given \a string of QML which will have the specified \a parent, +or \c null if there was an error in creating the object. + +If \a filepath is specified, it will be used for error reporting for the created object. + +Example (where \c parentItem is the id of an existing QML item): + +\snippet doc/src/snippets/declarative/createQmlObject.qml 0 + +In the case of an error, a QtScript Error object is thrown. This object has an additional property, +\c qmlErrors, which is an array of the errors encountered. +Each object in this array has the members \c lineNumber, \c columnNumber, \c fileName and \c message. +For example, if the above snippet had misspelled color as 'colro' then the array would contain an object like the following: +{ "lineNumber" : 1, "columnNumber" : 32, "fileName" : "dynamicSnippet1", "message" : "Cannot assign to non-existent property \"colro\""}. + +Note that this function returns immediately, and therefore may not work if +the \a qml string loads new components (that is, external QML files that have not yet been loaded). +If this is the case, consider using \l{QML:Qt::createComponent()}{Qt.createComponent()} instead. + +See \l {Dynamic Object Management in QML} for more information on using this function. +*/ + +QScriptValue QDeclarativeEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngine *engine) +{ + QDeclarativeEnginePrivate *activeEnginePriv = + static_cast<QDeclarativeScriptEngine*>(engine)->p; + QDeclarativeEngine* activeEngine = activeEnginePriv->q_func(); + + if(ctxt->argumentCount() < 2 || ctxt->argumentCount() > 3) + return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Invalid arguments")); + + QDeclarativeContextData* context = activeEnginePriv->getContext(ctxt); + Q_ASSERT(context); + + QString qml = ctxt->argument(0).toString(); + if (qml.isEmpty()) + return engine->nullValue(); + + QUrl url; + if(ctxt->argumentCount() > 2) + url = QUrl(ctxt->argument(2).toString()); + else + url = QUrl(QLatin1String("inline")); + + if (url.isValid() && url.isRelative()) + url = context->resolvedUrl(url); + + QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1)); + if(!parentArg) + return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Missing parent object")); + + QDeclarativeComponent component(activeEngine); + component.setData(qml.toUtf8(), url); + + if(component.isError()) { + QList<QDeclarativeError> errors = component.errors(); + QString errstr = QLatin1String("Qt.createQmlObject() failed to create object: "); + QScriptValue arr = ctxt->engine()->newArray(errors.length()); + int i = 0; + foreach (const QDeclarativeError &error, errors){ + errstr += QLatin1String(" ") + error.toString() + QLatin1String("\n"); + QScriptValue qmlErrObject = ctxt->engine()->newObject(); + qmlErrObject.setProperty(QLatin1String("lineNumber"), QScriptValue(error.line())); + qmlErrObject.setProperty(QLatin1String("columnNumber"), QScriptValue(error.column())); + qmlErrObject.setProperty(QLatin1String("fileName"), QScriptValue(error.url().toString())); + qmlErrObject.setProperty(QLatin1String("message"), QScriptValue(error.description())); + arr.setProperty(i++, qmlErrObject); + } + QScriptValue err = ctxt->throwError(errstr); + err.setProperty(QLatin1String("qmlErrors"),arr); + return err; + } + + if (!component.isReady()) + return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Component is not ready")); + + QObject *obj = component.beginCreate(context->asQDeclarativeContext()); + if(obj) + QDeclarativeData::get(obj, true)->setImplicitDestructible(); + component.completeCreate(); + + if(component.isError()) { + QList<QDeclarativeError> errors = component.errors(); + QString errstr = QLatin1String("Qt.createQmlObject() failed to create object: "); + QScriptValue arr = ctxt->engine()->newArray(errors.length()); + int i = 0; + foreach (const QDeclarativeError &error, errors){ + errstr += QLatin1String(" ") + error.toString() + QLatin1String("\n"); + QScriptValue qmlErrObject = ctxt->engine()->newObject(); + qmlErrObject.setProperty(QLatin1String("lineNumber"), QScriptValue(error.line())); + qmlErrObject.setProperty(QLatin1String("columnNumber"), QScriptValue(error.column())); + qmlErrObject.setProperty(QLatin1String("fileName"), QScriptValue(error.url().toString())); + qmlErrObject.setProperty(QLatin1String("message"), QScriptValue(error.description())); + arr.setProperty(i++, qmlErrObject); + } + QScriptValue err = ctxt->throwError(errstr); + err.setProperty(QLatin1String("qmlErrors"),arr); + return err; + } + + Q_ASSERT(obj); + + obj->setParent(parentArg); + + QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions(); + for (int ii = 0; ii < functions.count(); ++ii) { + if (QDeclarativePrivate::Parented == functions.at(ii)(obj, parentArg)) + break; + } + + QDeclarativeData::get(obj, true)->setImplicitDestructible(); + return activeEnginePriv->objectClass->newQObject(obj, QMetaType::QObjectStar); +} + +/*! +\qmlmethod bool Qt::isQtObject(object) +Returns true if \c object is a valid reference to a Qt or QML object, otherwise false. +*/ +QScriptValue QDeclarativeEnginePrivate::isQtObject(QScriptContext *ctxt, QScriptEngine *engine) +{ + if (ctxt->argumentCount() == 0) + return QScriptValue(engine, false); + + return QScriptValue(engine, 0 != ctxt->argument(0).toQObject()); +} + +/*! +\qmlmethod Qt::vector3d(real x, real y, real z) +Returns a Vector3D with the specified \c x, \c y and \c z. +*/ +QScriptValue QDeclarativeEnginePrivate::vector3d(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 3) + return ctxt->throwError(QLatin1String("Qt.vector(): Invalid arguments")); + qsreal x = ctxt->argument(0).toNumber(); + qsreal y = ctxt->argument(1).toNumber(); + qsreal z = ctxt->argument(2).toNumber(); + return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QVector3D(x, y, z))); +} + +/*! +\qmlmethod string Qt::formatDate(datetime date, variant format) + +Returns a string representation of \c date, optionally formatted according +to \c format. + +The \a date parameter may be a JavaScript \c Date object, a \l{date}{date} +property, a QDate, or QDateTime value. The \a format parameter may be any of +the possible format values as described for +\l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}. + +If \a format is not specified, \a date is formatted using +\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. +*/ +#ifndef QT_NO_DATESTRING +QScriptValue QDeclarativeEnginePrivate::formatDate(QScriptContext*ctxt, QScriptEngine*engine) +{ + int argCount = ctxt->argumentCount(); + if(argCount == 0 || argCount > 2) + return ctxt->throwError(QLatin1String("Qt.formatDate(): Invalid arguments")); + + QDate date = ctxt->argument(0).toDateTime().date(); + Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate; + if (argCount == 2) { + QScriptValue formatArg = ctxt->argument(1); + if (formatArg.isString()) { + QString format = formatArg.toString(); + return engine->newVariant(QVariant::fromValue(date.toString(format))); + } else if (formatArg.isNumber()) { + enumFormat = Qt::DateFormat(formatArg.toUInt32()); + } else { + return ctxt->throwError(QLatin1String("Qt.formatDate(): Invalid date format")); + } + } + return engine->newVariant(QVariant::fromValue(date.toString(enumFormat))); +} + +/*! +\qmlmethod string Qt::formatTime(datetime time, variant format) + +Returns a string representation of \c time, optionally formatted according to +\c format. + +The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime +value. The \a format parameter may be any of the possible format values as +described for \l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}. + +If \a format is not specified, \a time is formatted using +\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. +*/ +QScriptValue QDeclarativeEnginePrivate::formatTime(QScriptContext*ctxt, QScriptEngine*engine) +{ + int argCount = ctxt->argumentCount(); + if(argCount == 0 || argCount > 2) + return ctxt->throwError(QLatin1String("Qt.formatTime(): Invalid arguments")); + + QTime time; + QScriptValue sv = ctxt->argument(0); + if (sv.isDate()) + time = sv.toDateTime().time(); + else if (sv.toVariant().type() == QVariant::Time) + time = sv.toVariant().toTime(); + + Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate; + if (argCount == 2) { + QScriptValue formatArg = ctxt->argument(1); + if (formatArg.isString()) { + QString format = formatArg.toString(); + return engine->newVariant(QVariant::fromValue(time.toString(format))); + } else if (formatArg.isNumber()) { + enumFormat = Qt::DateFormat(formatArg.toUInt32()); + } else { + return ctxt->throwError(QLatin1String("Qt.formatTime(): Invalid time format")); + } + } + return engine->newVariant(QVariant::fromValue(time.toString(enumFormat))); +} + +/*! +\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format) + +Returns a string representation of \c datetime, optionally formatted according to +\c format. + +The \a date parameter may be a JavaScript \c Date object, a \l{date}{date} +property, a QDate, QTime, or QDateTime value. + +If \a format is not provided, \a dateTime is formatted using +\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. Otherwise, +\a format should be either. + +\list +\o One of the Qt::DateFormat enumeration values, such as + \c Qt.DefaultLocaleShortDate or \c Qt.ISODate +\o A string that specifies the format of the returned string, as detailed below. +\endlist + +If \a format specifies a format string, it should use the following expressions +to specify the date: + + \table + \header \i Expression \i Output + \row \i d \i the day as number without a leading zero (1 to 31) + \row \i dd \i the day as number with a leading zero (01 to 31) + \row \i ddd + \i the abbreviated localized day name (e.g. 'Mon' to 'Sun'). + Uses QDate::shortDayName(). + \row \i dddd + \i the long localized day name (e.g. 'Monday' to 'Qt::Sunday'). + Uses QDate::longDayName(). + \row \i M \i the month as number without a leading zero (1-12) + \row \i MM \i the month as number with a leading zero (01-12) + \row \i MMM + \i the abbreviated localized month name (e.g. 'Jan' to 'Dec'). + Uses QDate::shortMonthName(). + \row \i MMMM + \i the long localized month name (e.g. 'January' to 'December'). + Uses QDate::longMonthName(). + \row \i yy \i the year as two digit number (00-99) + \row \i yyyy \i the year as four digit number + \endtable + +In addition the following expressions can be used to specify the time: + + \table + \header \i Expression \i Output + \row \i h + \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display) + \row \i hh + \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display) + \row \i m \i the minute without a leading zero (0 to 59) + \row \i mm \i the minute with a leading zero (00 to 59) + \row \i s \i the second without a leading zero (0 to 59) + \row \i ss \i the second with a leading zero (00 to 59) + \row \i z \i the milliseconds without leading zeroes (0 to 999) + \row \i zzz \i the milliseconds with leading zeroes (000 to 999) + \row \i AP + \i use AM/PM display. \e AP will be replaced by either "AM" or "PM". + \row \i ap + \i use am/pm display. \e ap will be replaced by either "am" or "pm". + \endtable + + All other input characters will be ignored. Any sequence of characters that + are enclosed in single quotes will be treated as text and not be used as an + expression. Two consecutive single quotes ("''") are replaced by a single quote + in the output. + +For example, if the following date/time value was specified: + + \code + // 21 May 2001 14:13:09 + var dateTime = new Date(2001, 5, 21, 14, 13, 09) + \endcode + +This \a dateTime value could be passed to \c Qt.formatDateTime(), +\l {QML:Qt::formatDate()}{Qt.formatDate()} or \l {QML:Qt::formatTime()}{Qt.formatTime()} +with the \a format values below to produce the following results: + + \table + \header \i Format \i Result + \row \i "dd.MM.yyyy" \i 21.05.2001 + \row \i "ddd MMMM d yy" \i Tue May 21 01 + \row \i "hh:mm:ss.zzz" \i 14:13:09.042 + \row \i "h:m:s ap" \i 2:13:9 pm + \endtable +*/ +QScriptValue QDeclarativeEnginePrivate::formatDateTime(QScriptContext*ctxt, QScriptEngine*engine) +{ + int argCount = ctxt->argumentCount(); + if(argCount == 0 || argCount > 2) + return ctxt->throwError(QLatin1String("Qt.formatDateTime(): Invalid arguments")); + + QDateTime date = ctxt->argument(0).toDateTime(); + Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate; + if (argCount == 2) { + QScriptValue formatArg = ctxt->argument(1); + if (formatArg.isString()) { + QString format = formatArg.toString(); + return engine->newVariant(QVariant::fromValue(date.toString(format))); + } else if (formatArg.isNumber()) { + enumFormat = Qt::DateFormat(formatArg.toUInt32()); + } else { + return ctxt->throwError(QLatin1String("Qt.formatDateTime(): Invalid datetime format")); + } + } + return engine->newVariant(QVariant::fromValue(date.toString(enumFormat))); +} +#endif // QT_NO_DATESTRING + +/*! +\qmlmethod color Qt::rgba(real red, real green, real blue, real alpha) + +Returns a color with the specified \c red, \c green, \c blue and \c alpha components. +All components should be in the range 0-1 inclusive. +*/ +QScriptValue QDeclarativeEnginePrivate::rgba(QScriptContext *ctxt, QScriptEngine *engine) +{ + int argCount = ctxt->argumentCount(); + if(argCount < 3 || argCount > 4) + return ctxt->throwError(QLatin1String("Qt.rgba(): Invalid arguments")); + qsreal r = ctxt->argument(0).toNumber(); + qsreal g = ctxt->argument(1).toNumber(); + qsreal b = ctxt->argument(2).toNumber(); + qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1; + + if (r < 0.0) r=0.0; + if (r > 1.0) r=1.0; + if (g < 0.0) g=0.0; + if (g > 1.0) g=1.0; + if (b < 0.0) b=0.0; + if (b > 1.0) b=1.0; + if (a < 0.0) a=0.0; + if (a > 1.0) a=1.0; + + return engine->toScriptValue(QVariant::fromValue(QColor::fromRgbF(r, g, b, a))); +} + +/*! +\qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha) + +Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components. +All components should be in the range 0-1 inclusive. +*/ +QScriptValue QDeclarativeEnginePrivate::hsla(QScriptContext *ctxt, QScriptEngine *engine) +{ + int argCount = ctxt->argumentCount(); + if(argCount < 3 || argCount > 4) + return ctxt->throwError(QLatin1String("Qt.hsla(): Invalid arguments")); + qsreal h = ctxt->argument(0).toNumber(); + qsreal s = ctxt->argument(1).toNumber(); + qsreal l = ctxt->argument(2).toNumber(); + qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1; + + if (h < 0.0) h=0.0; + if (h > 1.0) h=1.0; + if (s < 0.0) s=0.0; + if (s > 1.0) s=1.0; + if (l < 0.0) l=0.0; + if (l > 1.0) l=1.0; + if (a < 0.0) a=0.0; + if (a > 1.0) a=1.0; + + return engine->toScriptValue(QVariant::fromValue(QColor::fromHslF(h, s, l, a))); +} + +/*! +\qmlmethod rect Qt::rect(int x, int y, int width, int height) + +Returns a \c rect with the top-left corner at \c x, \c y and the specified \c width and \c height. + +The returned object has \c x, \c y, \c width and \c height attributes with the given values. +*/ +QScriptValue QDeclarativeEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 4) + return ctxt->throwError(QLatin1String("Qt.rect(): Invalid arguments")); + + qsreal x = ctxt->argument(0).toNumber(); + qsreal y = ctxt->argument(1).toNumber(); + qsreal w = ctxt->argument(2).toNumber(); + qsreal h = ctxt->argument(3).toNumber(); + + return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QRectF(x, y, w, h))); +} + +/*! +\qmlmethod point Qt::point(int x, int y) +Returns a Point with the specified \c x and \c y coordinates. +*/ +QScriptValue QDeclarativeEnginePrivate::point(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 2) + return ctxt->throwError(QLatin1String("Qt.point(): Invalid arguments")); + qsreal x = ctxt->argument(0).toNumber(); + qsreal y = ctxt->argument(1).toNumber(); + return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QPointF(x, y))); +} + +/*! +\qmlmethod Qt::size(int width, int height) +Returns a Size with the specified \c width and \c height. +*/ +QScriptValue QDeclarativeEnginePrivate::size(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 2) + return ctxt->throwError(QLatin1String("Qt.size(): Invalid arguments")); + qsreal w = ctxt->argument(0).toNumber(); + qsreal h = ctxt->argument(1).toNumber(); + return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QSizeF(w, h))); +} + +/*! +\qmlmethod color Qt::lighter(color baseColor, real factor) +Returns a color lighter than \c baseColor by the \c factor provided. + +If the factor is greater than 1.0, this functions returns a lighter color. +Setting factor to 1.5 returns a color that is 50% brighter. If the factor is less than 1.0, +the return color is darker, but we recommend using the Qt.darker() function for this purpose. +If the factor is 0 or negative, the return value is unspecified. + +The function converts the current RGB color to HSV, multiplies the value (V) component +by factor and converts the color back to RGB. + +If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5). +*/ +QScriptValue QDeclarativeEnginePrivate::lighter(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 1 && ctxt->argumentCount() != 2) + return ctxt->throwError(QLatin1String("Qt.lighter(): Invalid arguments")); + QVariant v = ctxt->argument(0).toVariant(); + QColor color; + if (v.userType() == QVariant::Color) + color = v.value<QColor>(); + else if (v.userType() == QVariant::String) { + bool ok; + color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok); + if (!ok) + return engine->nullValue(); + } else + return engine->nullValue(); + qsreal factor = 1.5; + if (ctxt->argumentCount() == 2) + factor = ctxt->argument(1).toNumber(); + color = color.lighter(int(qRound(factor*100.))); + return engine->toScriptValue(QVariant::fromValue(color)); +} + +/*! +\qmlmethod color Qt::darker(color baseColor, real factor) +Returns a color darker than \c baseColor by the \c factor provided. + +If the factor is greater than 1.0, this function returns a darker color. +Setting factor to 3.0 returns a color that has one-third the brightness. +If the factor is less than 1.0, the return color is lighter, but we recommend using +the Qt.lighter() function for this purpose. If the factor is 0 or negative, the return +value is unspecified. + +The function converts the current RGB color to HSV, divides the value (V) component +by factor and converts the color back to RGB. + +If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0). +*/ +QScriptValue QDeclarativeEnginePrivate::darker(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 1 && ctxt->argumentCount() != 2) + return ctxt->throwError(QLatin1String("Qt.darker(): Invalid arguments")); + QVariant v = ctxt->argument(0).toVariant(); + QColor color; + if (v.userType() == QVariant::Color) + color = v.value<QColor>(); + else if (v.userType() == QVariant::String) { + bool ok; + color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok); + if (!ok) + return engine->nullValue(); + } else + return engine->nullValue(); + qsreal factor = 2.0; + if (ctxt->argumentCount() == 2) + factor = ctxt->argument(1).toNumber(); + color = color.darker(int(qRound(factor*100.))); + return engine->toScriptValue(QVariant::fromValue(color)); +} + +/*! +\qmlmethod bool Qt::openUrlExternally(url target) +Attempts to open the specified \c target url in an external application, based on the user's desktop preferences. Returns true if it succeeds, and false otherwise. +*/ +QScriptValue QDeclarativeEnginePrivate::desktopOpenUrl(QScriptContext *ctxt, QScriptEngine *e) +{ + if(ctxt->argumentCount() < 1) + return QScriptValue(e, false); + bool ret = false; +#ifndef QT_NO_DESKTOPSERVICES + ret = QDesktopServices::openUrl(QDeclarativeScriptEngine::get(e)->resolvedUrl(ctxt, QUrl(ctxt->argument(0).toString()))); +#endif + return QScriptValue(e, ret); +} + +/*! +\qmlmethod list<string> Qt::fontFamilies() +Returns a list of the font families available to the application. +*/ + +QScriptValue QDeclarativeEnginePrivate::fontFamilies(QScriptContext *ctxt, QScriptEngine *e) +{ + if(ctxt->argumentCount() != 0) + return ctxt->throwError(QLatin1String("Qt.fontFamilies(): Invalid arguments")); + + QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(e); + QFontDatabase database; + return p->scriptValueFromVariant(database.families()); +} + +/*! +\qmlmethod string Qt::md5(data) +Returns a hex string of the md5 hash of \c data. +*/ +QScriptValue QDeclarativeEnginePrivate::md5(QScriptContext *ctxt, QScriptEngine *) +{ + if (ctxt->argumentCount() != 1) + return ctxt->throwError(QLatin1String("Qt.md5(): Invalid arguments")); + + QByteArray data = ctxt->argument(0).toString().toUtf8(); + QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5); + + return QScriptValue(QLatin1String(result.toHex())); +} + +/*! +\qmlmethod string Qt::btoa(data) +Binary to ASCII - this function returns a base64 encoding of \c data. +*/ +QScriptValue QDeclarativeEnginePrivate::btoa(QScriptContext *ctxt, QScriptEngine *) +{ + if (ctxt->argumentCount() != 1) + return ctxt->throwError(QLatin1String("Qt.btoa(): Invalid arguments")); + + QByteArray data = ctxt->argument(0).toString().toUtf8(); + + return QScriptValue(QLatin1String(data.toBase64())); +} + +/*! +\qmlmethod string Qt::atob(data) +ASCII to binary - this function returns a base64 decoding of \c data. +*/ + +QScriptValue QDeclarativeEnginePrivate::atob(QScriptContext *ctxt, QScriptEngine *) +{ + if (ctxt->argumentCount() != 1) + return ctxt->throwError(QLatin1String("Qt.atob(): Invalid arguments")); + + QByteArray data = ctxt->argument(0).toString().toUtf8(); + + return QScriptValue(QLatin1String(QByteArray::fromBase64(data))); +} + +QScriptValue QDeclarativeEnginePrivate::consoleLog(QScriptContext *ctxt, QScriptEngine *e) +{ + if(ctxt->argumentCount() < 1) + return e->newVariant(QVariant(false)); + + QByteArray msg; + + for (int i=0; i<ctxt->argumentCount(); ++i) { + if (!msg.isEmpty()) msg += ' '; + msg += ctxt->argument(i).toString().toLocal8Bit(); + // does not support firebug "%[a-z]" formatting, since firebug really + // does just ignore the format letter, which makes it pointless. + } + + qDebug("%s",msg.constData()); + + return e->newVariant(QVariant(true)); +} + +void QDeclarativeEnginePrivate::sendQuit() +{ + Q_Q(QDeclarativeEngine); + emit q->quit(); + if (q->receivers(SIGNAL(quit())) == 0) { + qWarning("Signal QDeclarativeEngine::quit() emitted, but no receivers connected to handle it."); + } +} + +static void dumpwarning(const QDeclarativeError &error) +{ + qWarning().nospace() << qPrintable(error.toString()); +} + +static void dumpwarning(const QList<QDeclarativeError> &errors) +{ + for (int ii = 0; ii < errors.count(); ++ii) + dumpwarning(errors.at(ii)); +} + +void QDeclarativeEnginePrivate::warning(const QDeclarativeError &error) +{ + Q_Q(QDeclarativeEngine); + q->warnings(QList<QDeclarativeError>() << error); + if (outputWarningsToStdErr) + dumpwarning(error); +} + +void QDeclarativeEnginePrivate::warning(const QList<QDeclarativeError> &errors) +{ + Q_Q(QDeclarativeEngine); + q->warnings(errors); + if (outputWarningsToStdErr) + dumpwarning(errors); +} + +void QDeclarativeEnginePrivate::warning(QDeclarativeEngine *engine, const QDeclarativeError &error) +{ + if (engine) + QDeclarativeEnginePrivate::get(engine)->warning(error); + else + dumpwarning(error); +} + +void QDeclarativeEnginePrivate::warning(QDeclarativeEngine *engine, const QList<QDeclarativeError> &error) +{ + if (engine) + QDeclarativeEnginePrivate::get(engine)->warning(error); + else + dumpwarning(error); +} + +void QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate *engine, const QDeclarativeError &error) +{ + if (engine) + engine->warning(error); + else + dumpwarning(error); +} + +void QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate *engine, const QList<QDeclarativeError> &error) +{ + if (engine) + engine->warning(error); + else + dumpwarning(error); +} + +/*! +\qmlmethod Qt::quit() +This function causes the QDeclarativeEngine::quit() signal to be emitted. +Within the \l {QML Viewer}, this causes the launcher application to exit; +to quit a C++ application when this method is called, connect the +QDeclarativeEngine::quit() signal to the QCoreApplication::quit() slot. +*/ + +QScriptValue QDeclarativeEnginePrivate::quit(QScriptContext * /*ctxt*/, QScriptEngine *e) +{ + QDeclarativeEnginePrivate *qe = get (e); + qe->sendQuit(); + return QScriptValue(); +} + +/*! + \qmlmethod color Qt::tint(color baseColor, color tintColor) + This function allows tinting one color with another. + + The tint color should usually be mostly transparent, or you will not be + able to see the underlying color. The below example provides a slight red + tint by having the tint color be pure red which is only 1/16th opaque. + + \qml + Item { + Rectangle { + x: 0; width: 80; height: 80 + color: "lightsteelblue" + } + Rectangle { + x: 100; width: 80; height: 80 + color: Qt.tint("lightsteelblue", "#10FF0000") + } + } + \endqml + \image declarative-rect_tint.png + + Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color. +*/ +QScriptValue QDeclarativeEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine *engine) +{ + if(ctxt->argumentCount() != 2) + return ctxt->throwError(QLatin1String("Qt.tint(): Invalid arguments")); + //get color + QVariant v = ctxt->argument(0).toVariant(); + QColor color; + if (v.userType() == QVariant::Color) + color = v.value<QColor>(); + else if (v.userType() == QVariant::String) { + bool ok; + color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok); + if (!ok) + return engine->nullValue(); + } else + return engine->nullValue(); + + //get tint color + v = ctxt->argument(1).toVariant(); + QColor tintColor; + if (v.userType() == QVariant::Color) + tintColor = v.value<QColor>(); + else if (v.userType() == QVariant::String) { + bool ok; + tintColor = QDeclarativeStringConverters::colorFromString(v.toString(), &ok); + if (!ok) + return engine->nullValue(); + } else + return engine->nullValue(); + + //tint + QColor finalColor; + int a = tintColor.alpha(); + if (a == 0xFF) + finalColor = tintColor; + else if (a == 0x00) + finalColor = color; + else { + qreal a = tintColor.alphaF(); + qreal inv_a = 1.0 - a; + + finalColor.setRgbF(tintColor.redF() * a + color.redF() * inv_a, + tintColor.greenF() * a + color.greenF() * inv_a, + tintColor.blueF() * a + color.blueF() * inv_a, + a + inv_a * color.alphaF()); + } + + return engine->toScriptValue(QVariant::fromValue(finalColor)); +} + +QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &val) +{ + if (val.userType() == qMetaTypeId<QDeclarativeListReference>()) { + QDeclarativeListReferencePrivate *p = + QDeclarativeListReferencePrivate::get((QDeclarativeListReference*)val.constData()); + if (p->object) { + return listClass->newList(p->property, p->propertyType); + } else { + return scriptEngine.nullValue(); + } + } else if (val.userType() == qMetaTypeId<QList<QObject *> >()) { + const QList<QObject *> &list = *(QList<QObject *>*)val.constData(); + QScriptValue rv = scriptEngine.newArray(list.count()); + for (int ii = 0; ii < list.count(); ++ii) { + QObject *object = list.at(ii); + rv.setProperty(ii, objectClass->newQObject(object)); + } + return rv; + } else if (QDeclarativeValueType *vt = valueTypes[val.userType()]) { + return valueTypeClass->newObject(val, vt); + } + + bool objOk; + QObject *obj = QDeclarativeMetaType::toQObject(val, &objOk); + if (objOk) { + return objectClass->newQObject(obj); + } else { + return scriptEngine.toScriptValue(val); + } +} + +QVariant QDeclarativeEnginePrivate::scriptValueToVariant(const QScriptValue &val, int hint) +{ + QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val); + if (dc == objectClass) + return QVariant::fromValue(objectClass->toQObject(val)); + else if (dc == valueTypeClass) + return valueTypeClass->toVariant(val); + else if (dc == contextClass) + return QVariant(); + + // Convert to a QList<QObject*> only if val is an array and we were explicitly hinted + if (hint == qMetaTypeId<QList<QObject *> >() && val.isArray()) { + QList<QObject *> list; + int length = val.property(QLatin1String("length")).toInt32(); + for (int ii = 0; ii < length; ++ii) { + QScriptValue arrayItem = val.property(ii); + QObject *d = arrayItem.toQObject(); + list << d; + } + return QVariant::fromValue(list); + } + + return val.toVariant(); +} + +/*! + Adds \a path as a directory where the engine searches for + installed modules in a URL-based directory structure. + The \a path may be a local filesystem directory or a URL. + + The newly added \a path will be first in the importPathList(). + + \sa setImportPathList(), {QML Modules} +*/ +void QDeclarativeEngine::addImportPath(const QString& path) +{ + Q_D(QDeclarativeEngine); + d->importDatabase.addImportPath(path); +} + +/*! + Returns the list of directories where the engine searches for + installed modules in a URL-based directory structure. + + For example, if \c /opt/MyApp/lib/imports is in the path, then QML that + imports \c com.mycompany.Feature will cause the QDeclarativeEngine to look + in \c /opt/MyApp/lib/imports/com/mycompany/Feature/ for the components + provided by that module. A \c qmldir file is required for defining the + type version mapping and possibly declarative extensions plugins. + + By default, the list contains the directory of the application executable, + paths specified in the \c QML_IMPORT_PATH environment variable, + and the builtin \c ImportsPath from QLibraryInfo. + + \sa addImportPath() setImportPathList() +*/ +QStringList QDeclarativeEngine::importPathList() const +{ + Q_D(const QDeclarativeEngine); + return d->importDatabase.importPathList(); +} + +/*! + Sets \a paths as the list of directories where the engine searches for + installed modules in a URL-based directory structure. + + By default, the list contains the directory of the application executable, + paths specified in the \c QML_IMPORT_PATH environment variable, + and the builtin \c ImportsPath from QLibraryInfo. + + \sa importPathList() addImportPath() + */ +void QDeclarativeEngine::setImportPathList(const QStringList &paths) +{ + Q_D(QDeclarativeEngine); + d->importDatabase.setImportPathList(paths); +} + + +/*! + Adds \a path as a directory where the engine searches for + native plugins for imported modules (referenced in the \c qmldir file). + + By default, the list contains only \c ., i.e. the engine searches + in the directory of the \c qmldir file itself. + + The newly added \a path will be first in the pluginPathList(). + + \sa setPluginPathList() +*/ +void QDeclarativeEngine::addPluginPath(const QString& path) +{ + Q_D(QDeclarativeEngine); + d->importDatabase.addPluginPath(path); +} + + +/*! + Returns the list of directories where the engine searches for + native plugins for imported modules (referenced in the \c qmldir file). + + By default, the list contains only \c ., i.e. the engine searches + in the directory of the \c qmldir file itself. + + \sa addPluginPath() setPluginPathList() +*/ +QStringList QDeclarativeEngine::pluginPathList() const +{ + Q_D(const QDeclarativeEngine); + return d->importDatabase.pluginPathList(); +} + +/*! + Sets the list of directories where the engine searches for + native plugins for imported modules (referenced in the \c qmldir file) + to \a paths. + + By default, the list contains only \c ., i.e. the engine searches + in the directory of the \c qmldir file itself. + + \sa pluginPathList() addPluginPath() + */ +void QDeclarativeEngine::setPluginPathList(const QStringList &paths) +{ + Q_D(QDeclarativeEngine); + d->importDatabase.setPluginPathList(paths); +} + + +/*! + Imports the plugin named \a filePath with the \a uri provided. + Returns true if the plugin was successfully imported; otherwise returns false. + + On failure and if non-null, *\a errorString will be set to a message describing the failure. + + The plugin has to be a Qt plugin which implements the QDeclarativeExtensionPlugin interface. +*/ +bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &uri, QString *errorString) +{ + Q_D(QDeclarativeEngine); + return d->importDatabase.importPlugin(filePath, uri, errorString); +} + +/*! + \property QDeclarativeEngine::offlineStoragePath + \brief the directory for storing offline user data + + Returns the directory where SQL and other offline + storage is placed. + + QDeclarativeWebView and the SQL databases created with openDatabase() + are stored here. + + The default is QML/OfflineStorage in the platform-standard + user application data directory. + + Note that the path may not currently exist on the filesystem, so + callers wanting to \e create new files at this location should create + it first - see QDir::mkpath(). +*/ +void QDeclarativeEngine::setOfflineStoragePath(const QString& dir) +{ + Q_D(QDeclarativeEngine); + d->scriptEngine.offlineStoragePath = dir; +} + +QString QDeclarativeEngine::offlineStoragePath() const +{ + Q_D(const QDeclarativeEngine); + return d->scriptEngine.offlineStoragePath; +} + +static void voidptr_destructor(void *v) +{ + void **ptr = (void **)v; + delete ptr; +} + +static void *voidptr_constructor(const void *v) +{ + if (!v) { + return new void*; + } else { + return new void*(*(void **)v); + } +} + +QDeclarativePropertyCache *QDeclarativeEnginePrivate::createCache(const QMetaObject *mo) +{ + Q_Q(QDeclarativeEngine); + + if (!mo->superClass()) { + QDeclarativePropertyCache *rv = new QDeclarativePropertyCache(q, mo); + propertyCache.insert(mo, rv); + return rv; + } else { + QDeclarativePropertyCache *super = cache(mo->superClass()); + QDeclarativePropertyCache *rv = super->copy(); + rv->append(q, mo); + propertyCache.insert(mo, rv); + return rv; + } +} + +QDeclarativePropertyCache *QDeclarativeEnginePrivate::createCache(QDeclarativeType *type, int minorVersion, + QDeclarativeError &error) +{ + QList<QDeclarativeType *> types; + + int maxMinorVersion = 0; + + const QMetaObject *metaObject = type->metaObject(); + while (metaObject) { + QDeclarativeType *t = QDeclarativeMetaType::qmlType(metaObject, type->module(), + type->majorVersion(), minorVersion); + if (t) { + maxMinorVersion = qMax(maxMinorVersion, t->minorVersion()); + types << t; + } else { + types << 0; + } + + metaObject = metaObject->superClass(); + } + + if (QDeclarativePropertyCache *c = typePropertyCache.value(qMakePair(type, maxMinorVersion))) { + c->addref(); + typePropertyCache.insert(qMakePair(type, minorVersion), c); + return c; + } + + QDeclarativePropertyCache *raw = cache(type->metaObject()); + + bool hasCopied = false; + + for (int ii = 0; ii < types.count(); ++ii) { + QDeclarativeType *currentType = types.at(ii); + if (!currentType) + continue; + + int rev = currentType->metaObjectRevision(); + int moIndex = types.count() - 1 - ii; + + if (raw->allowedRevisionCache[moIndex] != rev) { + if (!hasCopied) { + raw = raw->copy(); + hasCopied = true; + } + raw->allowedRevisionCache[moIndex] = rev; + } + } + + // Test revision compatibility - the basic rule is: + // * Anything that is excluded, cannot overload something that is not excluded * + + // Signals override: + // * other signals and methods of the same name. + // * properties named on<Signal Name> + // * automatic <property name>Changed notify signals + + // Methods override: + // * other methods of the same name + + // Properties override: + // * other elements of the same name + + bool overloadError = false; + QString overloadName; + +#if 0 + for (QDeclarativePropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin(); + !overloadError && iter != raw->stringCache.end(); + ++iter) { + + QDeclarativePropertyCache::Data *d = *iter; + if (raw->isAllowedInRevision(d)) + continue; // Not excluded - no problems + + // check that a regular "name" overload isn't happening + QDeclarativePropertyCache::Data *current = d; + while (!overloadError && current) { + current = d->overrideData(current); + if (current && raw->isAllowedInRevision(current)) + overloadError = true; + } + } +#endif + + if (overloadError) { + if (hasCopied) raw->release(); + + error.setDescription(QLatin1String("Type ") + QString::fromUtf8(type->qmlTypeName()) + QLatin1String(" ") + QString::number(type->majorVersion()) + QLatin1String(".") + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation.")); + return 0; + } + + if (!hasCopied) raw->addref(); + typePropertyCache.insert(qMakePair(type, minorVersion), raw); + + if (minorVersion != maxMinorVersion) { + raw->addref(); + typePropertyCache.insert(qMakePair(type, maxMinorVersion), raw); + } + + return raw; +} + +void QDeclarativeEnginePrivate::registerCompositeType(QDeclarativeCompiledData *data) +{ + QByteArray name = data->root->className(); + + QByteArray ptr = name + '*'; + QByteArray lst = "QDeclarativeListProperty<" + name + '>'; + + int ptr_type = QMetaType::registerType(ptr.constData(), voidptr_destructor, + voidptr_constructor); + int lst_type = QMetaType::registerType(lst.constData(), voidptr_destructor, + voidptr_constructor); + + m_qmlLists.insert(lst_type, ptr_type); + m_compositeTypes.insert(ptr_type, data); + data->addref(); +} + +bool QDeclarativeEnginePrivate::isList(int t) const +{ + return m_qmlLists.contains(t) || QDeclarativeMetaType::isList(t); +} + +int QDeclarativeEnginePrivate::listType(int t) const +{ + QHash<int, int>::ConstIterator iter = m_qmlLists.find(t); + if (iter != m_qmlLists.end()) + return *iter; + else + return QDeclarativeMetaType::listType(t); +} + +bool QDeclarativeEnginePrivate::isQObject(int t) +{ + return m_compositeTypes.contains(t) || QDeclarativeMetaType::isQObject(t); +} + +QObject *QDeclarativeEnginePrivate::toQObject(const QVariant &v, bool *ok) const +{ + int t = v.userType(); + if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) { + if (ok) *ok = true; + return *(QObject **)(v.constData()); + } else { + return QDeclarativeMetaType::toQObject(v, ok); + } +} + +QDeclarativeMetaType::TypeCategory QDeclarativeEnginePrivate::typeCategory(int t) const +{ + if (m_compositeTypes.contains(t)) + return QDeclarativeMetaType::Object; + else if (m_qmlLists.contains(t)) + return QDeclarativeMetaType::List; + else + return QDeclarativeMetaType::typeCategory(t); +} + +const QMetaObject *QDeclarativeEnginePrivate::rawMetaObjectForType(int t) const +{ + QHash<int, QDeclarativeCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); + if (iter != m_compositeTypes.end()) { + return (*iter)->root; + } else { + QDeclarativeType *type = QDeclarativeMetaType::qmlType(t); + return type?type->baseMetaObject():0; + } +} + +const QMetaObject *QDeclarativeEnginePrivate::metaObjectForType(int t) const +{ + QHash<int, QDeclarativeCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); + if (iter != m_compositeTypes.end()) { + return (*iter)->root; + } else { + QDeclarativeType *type = QDeclarativeMetaType::qmlType(t); + return type?type->metaObject():0; + } +} + +bool QDeclarative_isFileCaseCorrect(const QString &fileName) +{ +#if defined(Q_OS_MAC) || defined(Q_OS_WIN32) + QFileInfo info(fileName); + + QString absolute = info.absoluteFilePath(); + +#if defined(Q_OS_MAC) + QString canonical = info.canonicalFilePath(); +#elif defined(Q_OS_WIN32) + wchar_t buffer[1024]; + + DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024); + if (rv == 0 || rv >= 1024) return true; + rv = ::GetLongPathName(buffer, buffer, 1024); + if (rv == 0 || rv >= 1024) return true; + + QString canonical((QChar *)buffer); +#endif + + int absoluteLength = absolute.length(); + int canonicalLength = canonical.length(); + + int length = qMin(absoluteLength, canonicalLength); + for (int ii = 0; ii < length; ++ii) { + const QChar &a = absolute.at(absoluteLength - 1 - ii); + const QChar &c = canonical.at(canonicalLength - 1 - ii); + + if (a.toLower() != c.toLower()) + return true; + if (a != c) + return false; + } +#else + Q_UNUSED(fileName) +#endif + return true; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h new file mode 100644 index 00000000..fd061159 --- /dev/null +++ b/src/declarative/qml/qdeclarativeengine.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEENGINE_H +#define QDECLARATIVEENGINE_H + +#include <QtCore/qurl.h> +#include <QtCore/qobject.h> +#include <QtCore/qmap.h> +#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qdeclarativeerror.h> +#include <QtDeclarative/qdeclarativedebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeComponent; +class QDeclarativeEnginePrivate; +class QDeclarativeImportsPrivate; +class QDeclarativeExpression; +class QDeclarativeContext; +class QDeclarativeType; +class QUrl; +class QScriptEngine; +class QScriptContext; +class QDeclarativeImageProvider; +class QNetworkAccessManager; +class QDeclarativeNetworkAccessManagerFactory; +class Q_DECLARATIVE_EXPORT QDeclarativeEngine : public QObject +{ + Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath) + Q_OBJECT +public: + QDeclarativeEngine(QObject *p = 0); + virtual ~QDeclarativeEngine(); + + QDeclarativeContext *rootContext() const; + + void clearComponentCache(); + + QStringList importPathList() const; + void setImportPathList(const QStringList &paths); + void addImportPath(const QString& dir); + + QStringList pluginPathList() const; + void setPluginPathList(const QStringList &paths); + void addPluginPath(const QString& dir); + + bool importPlugin(const QString &filePath, const QString &uri, QString *errorString); + + void setNetworkAccessManagerFactory(QDeclarativeNetworkAccessManagerFactory *); + QDeclarativeNetworkAccessManagerFactory *networkAccessManagerFactory() const; + + QNetworkAccessManager *networkAccessManager() const; + + void addImageProvider(const QString &id, QDeclarativeImageProvider *); + QDeclarativeImageProvider *imageProvider(const QString &id) const; + void removeImageProvider(const QString &id); + + void setOfflineStoragePath(const QString& dir); + QString offlineStoragePath() const; + + QUrl baseUrl() const; + void setBaseUrl(const QUrl &); + + bool outputWarningsToStandardError() const; + void setOutputWarningsToStandardError(bool); + + static QDeclarativeContext *contextForObject(const QObject *); + static void setContextForObject(QObject *, QDeclarativeContext *); + + enum ObjectOwnership { CppOwnership, JavaScriptOwnership }; + static void setObjectOwnership(QObject *, ObjectOwnership); + static ObjectOwnership objectOwnership(QObject *); + +Q_SIGNALS: + void quit(); + void warnings(const QList<QDeclarativeError> &warnings); + +private: + Q_DISABLE_COPY(QDeclarativeEngine) + Q_DECLARE_PRIVATE(QDeclarativeEngine) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEENGINE_H diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h new file mode 100644 index 00000000..e43f75bb --- /dev/null +++ b/src/declarative/qml/qdeclarativeengine_p.h @@ -0,0 +1,387 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEENGINE_P_H +#define QDECLARATIVEENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativeengine.h" + +#include "private/qdeclarativetypeloader_p.h" +#include "private/qdeclarativeimport_p.h" +#include "private/qpodvector_p.h" +#include "qdeclarative.h" +#include "private/qdeclarativevaluetype_p.h" +#include "qdeclarativecontext.h" +#include "private/qdeclarativecontext_p.h" +#include "qdeclarativeexpression.h" +#include "qdeclarativeimageprovider.h" +#include "private/qdeclarativeproperty_p.h" +#include "private/qdeclarativepropertycache_p.h" +#include "private/qdeclarativeobjectscriptclass_p.h" +#include "private/qdeclarativecontextscriptclass_p.h" +#include "private/qdeclarativevaluetypescriptclass_p.h" +#include "private/qdeclarativemetatype_p.h" +#include "private/qdeclarativedirparser_p.h" + +#include <QtScript/QScriptClass> +#include <QtScript/QScriptValue> +#include <QtScript/QScriptString> +#include <QtCore/qstring.h> +#include <QtCore/qlist.h> +#include <QtCore/qpair.h> +#include <QtCore/qstack.h> +#include <QtCore/qmutex.h> +#include <QtScript/qscriptengine.h> + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeContext; +class QDeclarativeEngine; +class QDeclarativeContextPrivate; +class QDeclarativeExpression; +class QDeclarativeContextScriptClass; +class QDeclarativeImportDatabase; +class QDeclarativeObjectScriptClass; +class QDeclarativeTypeNameScriptClass; +class QDeclarativeValueTypeScriptClass; +class QNetworkReply; +class QNetworkAccessManager; +class QDeclarativeNetworkAccessManagerFactory; +class QDeclarativeAbstractBinding; +class QScriptDeclarativeClass; +class QDeclarativeTypeNameScriptClass; +class QDeclarativeTypeNameCache; +class QDeclarativeComponentAttached; +class QDeclarativeListScriptClass; +class QDeclarativeCleanup; +class QDeclarativeDelayedError; +class QDeclarativeWorkerScriptEngine; +class QDeclarativeGlobalScriptClass; +class QDir; + +class QDeclarativeScriptEngine : public QScriptEngine +{ +public: + QDeclarativeScriptEngine(QDeclarativeEnginePrivate *priv); + virtual ~QDeclarativeScriptEngine(); + + QUrl resolvedUrl(QScriptContext *context, const QUrl& url); // resolved against p's context, or baseUrl if no p + static QScriptValue resolvedUrl(QScriptContext *ctxt, QScriptEngine *engine); + + static QDeclarativeScriptEngine *get(QScriptEngine* e) { return static_cast<QDeclarativeScriptEngine*>(e); } + + QDeclarativeEnginePrivate *p; + + // User by SQL API + QScriptClass *sqlQueryClass; + QString offlineStoragePath; + + // Used by DOM Core 3 API + QScriptClass *namedNodeMapClass; + QScriptClass *nodeListClass; + + QUrl baseUrl; + + virtual QNetworkAccessManager *networkAccessManager(); +}; + +class Q_AUTOTEST_EXPORT QDeclarativeEnginePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QDeclarativeEngine) +public: + QDeclarativeEnginePrivate(QDeclarativeEngine *); + ~QDeclarativeEnginePrivate(); + + void init(); + + struct CapturedProperty { + CapturedProperty(QObject *o, int c, int n) + : object(o), coreIndex(c), notifier(0), notifyIndex(n) {} + CapturedProperty(QDeclarativeNotifier *n) + : object(0), coreIndex(-1), notifier(n), notifyIndex(-1) {} + + QObject *object; + int coreIndex; + QDeclarativeNotifier *notifier; + int notifyIndex; + }; + bool captureProperties; + QPODVector<CapturedProperty> capturedProperties; + + QDeclarativeContext *rootContext; + bool isDebugging; + + bool outputWarningsToStdErr; + + QDeclarativeContextScriptClass *contextClass; + QDeclarativeContextData *sharedContext; + QObject *sharedScope; + QDeclarativeObjectScriptClass *objectClass; + QDeclarativeValueTypeScriptClass *valueTypeClass; + QDeclarativeTypeNameScriptClass *typeNameClass; + QDeclarativeListScriptClass *listClass; + // Global script class + QDeclarativeGlobalScriptClass *globalClass; + + // Registered cleanup handlers + QDeclarativeCleanup *cleanup; + + // Bindings that have had errors during startup + QDeclarativeDelayedError *erroredBindings; + int inProgressCreations; + + QDeclarativeScriptEngine scriptEngine; + + QDeclarativeWorkerScriptEngine *getWorkerScriptEngine(); + QDeclarativeWorkerScriptEngine *workerScriptEngine; + + QUrl baseUrl; + + template<class T> + struct SimpleList { + SimpleList() + : count(0), values(0) {} + SimpleList(int r) + : count(0), values(new T*[r]) {} + + int count; + T **values; + + void append(T *v) { + values[count++] = v; + } + + T *at(int idx) const { + return values[idx]; + } + + void clear() { + delete [] values; + } + }; + + static void clear(SimpleList<QDeclarativeAbstractBinding> &); + static void clear(SimpleList<QDeclarativeParserStatus> &); + + QList<SimpleList<QDeclarativeAbstractBinding> > bindValues; + QList<SimpleList<QDeclarativeParserStatus> > parserStatus; + QList<QPair<QDeclarativeGuard<QObject>,int> > finalizedParserStatus; + QDeclarativeComponentAttached *componentAttached; + + void registerFinalizedParserStatusObject(QObject *obj, int index) { + finalizedParserStatus.append(qMakePair(QDeclarativeGuard<QObject>(obj), index)); + } + + bool inBeginCreate; + + QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const; + QNetworkAccessManager *getNetworkAccessManager() const; + mutable QNetworkAccessManager *networkAccessManager; + mutable QDeclarativeNetworkAccessManagerFactory *networkAccessManagerFactory; + + QHash<QString,QSharedPointer<QDeclarativeImageProvider> > imageProviders; + QDeclarativeImageProvider::ImageType getImageProviderType(const QUrl &url); + QImage getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size); + QPixmap getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size); + + mutable QMutex mutex; + + QDeclarativeTypeLoader typeLoader; + QDeclarativeImportDatabase importDatabase; + + QString offlineStoragePath; + + mutable quint32 uniqueId; + quint32 getUniqueId() const { + return uniqueId++; + } + + QDeclarativeValueTypeFactory valueTypes; + + QHash<const QMetaObject *, QDeclarativePropertyCache *> propertyCache; + QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *> typePropertyCache; + inline QDeclarativePropertyCache *cache(QObject *obj); + inline QDeclarativePropertyCache *cache(const QMetaObject *); + inline QDeclarativePropertyCache *cache(QDeclarativeType *, int, QDeclarativeError &error); + QDeclarativePropertyCache *createCache(const QMetaObject *); + QDeclarativePropertyCache *createCache(QDeclarativeType *, int, QDeclarativeError &error); + + void registerCompositeType(QDeclarativeCompiledData *); + + bool isQObject(int); + QObject *toQObject(const QVariant &, bool *ok = 0) const; + QDeclarativeMetaType::TypeCategory typeCategory(int) const; + bool isList(int) const; + int listType(int) const; + const QMetaObject *rawMetaObjectForType(int) const; + const QMetaObject *metaObjectForType(int) const; + QHash<int, int> m_qmlLists; + QHash<int, QDeclarativeCompiledData *> m_compositeTypes; + + QHash<QString, QScriptValue> m_sharedScriptImports; + + QScriptValue scriptValueFromVariant(const QVariant &); + QVariant scriptValueToVariant(const QScriptValue &, int hint = QVariant::Invalid); + + void sendQuit(); + void warning(const QDeclarativeError &); + void warning(const QList<QDeclarativeError> &); + static void warning(QDeclarativeEngine *, const QDeclarativeError &); + static void warning(QDeclarativeEngine *, const QList<QDeclarativeError> &); + static void warning(QDeclarativeEnginePrivate *, const QDeclarativeError &); + static void warning(QDeclarativeEnginePrivate *, const QList<QDeclarativeError> &); + + static QScriptValue qmlScriptObject(QObject*, QDeclarativeEngine*); + + static QScriptValue createComponent(QScriptContext*, QScriptEngine*); + static QScriptValue createQmlObject(QScriptContext*, QScriptEngine*); + static QScriptValue isQtObject(QScriptContext*, QScriptEngine*); + static QScriptValue vector3d(QScriptContext*, QScriptEngine*); + static QScriptValue rgba(QScriptContext*, QScriptEngine*); + static QScriptValue hsla(QScriptContext*, QScriptEngine*); + static QScriptValue point(QScriptContext*, QScriptEngine*); + static QScriptValue size(QScriptContext*, QScriptEngine*); + static QScriptValue rect(QScriptContext*, QScriptEngine*); + + static QScriptValue lighter(QScriptContext*, QScriptEngine*); + static QScriptValue darker(QScriptContext*, QScriptEngine*); + static QScriptValue tint(QScriptContext*, QScriptEngine*); + + static QScriptValue desktopOpenUrl(QScriptContext*, QScriptEngine*); + static QScriptValue fontFamilies(QScriptContext*, QScriptEngine*); + static QScriptValue md5(QScriptContext*, QScriptEngine*); + static QScriptValue btoa(QScriptContext*, QScriptEngine*); + static QScriptValue atob(QScriptContext*, QScriptEngine*); + static QScriptValue consoleLog(QScriptContext*, QScriptEngine*); + static QScriptValue quit(QScriptContext*, QScriptEngine*); + +#ifndef QT_NO_DATESTRING + static QScriptValue formatDate(QScriptContext*, QScriptEngine*); + static QScriptValue formatTime(QScriptContext*, QScriptEngine*); + static QScriptValue formatDateTime(QScriptContext*, QScriptEngine*); +#endif + static QScriptEngine *getScriptEngine(QDeclarativeEngine *e) { return &e->d_func()->scriptEngine; } + static QDeclarativeEngine *getEngine(QScriptEngine *e) { return static_cast<QDeclarativeScriptEngine*>(e)->p->q_func(); } + static QDeclarativeEnginePrivate *get(QDeclarativeEngine *e) { return e->d_func(); } + static QDeclarativeEnginePrivate *get(QDeclarativeContext *c) { return (c && c->engine()) ? QDeclarativeEnginePrivate::get(c->engine()) : 0; } + static QDeclarativeEnginePrivate *get(QDeclarativeContextData *c) { return (c && c->engine) ? QDeclarativeEnginePrivate::get(c->engine) : 0; } + static QDeclarativeEnginePrivate *get(QScriptEngine *e) { return static_cast<QDeclarativeScriptEngine*>(e)->p; } + static QDeclarativeEngine *get(QDeclarativeEnginePrivate *p) { return p->q_func(); } + QDeclarativeContextData *getContext(QScriptContext *); + QUrl getUrl(QScriptContext *); + + static QString urlToLocalFileOrQrc(const QUrl& url); + + static void defineModule(); + + static bool qml_debugging_enabled; +}; + +/*! +Returns a QDeclarativePropertyCache for \a obj if one is available. + +If \a obj is null, being deleted or contains a dynamic meta object 0 +is returned. + +The returned cache is not referenced, so if it is to be stored, call addref(). +*/ +QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(QObject *obj) +{ + if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted) + return 0; + + const QMetaObject *mo = obj->metaObject(); + QDeclarativePropertyCache *rv = propertyCache.value(mo); + if (!rv) rv = createCache(mo); + return rv; +} + +/*! +Returns a QDeclarativePropertyCache for \a metaObject. + +As the cache is persisted for the life of the engine, \a metaObject must be +a static "compile time" meta-object, or a meta-object that is otherwise known to +exist for the lifetime of the QDeclarativeEngine. + +The returned cache is not referenced, so if it is to be stored, call addref(). +*/ +QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(const QMetaObject *metaObject) +{ + Q_ASSERT(metaObject); + + QDeclarativePropertyCache *rv = propertyCache.value(metaObject); + if (!rv) rv = createCache(metaObject); + return rv; +} + +/*! +Returns a QDeclarativePropertyCache for \a type with \a minorVersion. + +The returned cache is not referenced, so if it is to be stored, call addref(). +*/ +QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(QDeclarativeType *type, int minorVersion, QDeclarativeError &error) +{ + Q_ASSERT(type); + + if (minorVersion == -1 || !type->containsRevisionedAttributes()) + return cache(type->metaObject()); + + QDeclarativePropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion)); + if (!rv) rv = createCache(type, minorVersion, error); + return rv; +} + +QT_END_NAMESPACE + +#endif // QDECLARATIVEENGINE_P_H diff --git a/src/declarative/qml/qdeclarativeerror.cpp b/src/declarative/qml/qdeclarativeerror.cpp new file mode 100644 index 00000000..a538c751 --- /dev/null +++ b/src/declarative/qml/qdeclarativeerror.cpp @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeerror.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qfile.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QDeclarativeError + \since 4.7 + \brief The QDeclarativeError class encapsulates a QML error. + + QDeclarativeError includes a textual description of the error, as well + as location information (the file, line, and column). The toString() + method creates a single-line, human-readable string containing all of + this information, for example: + \code + file:///home/user/test.qml:7:8: Invalid property assignment: double expected + \endcode + + You can use qDebug() or qWarning() to output errors to the console. This method + will attempt to open the file indicated by the error + and include additional contextual information. + \code + file:///home/user/test.qml:7:8: Invalid property assignment: double expected + y: "hello" + ^ + \endcode + + \sa QDeclarativeView::errors(), QDeclarativeComponent::errors() +*/ +class QDeclarativeErrorPrivate +{ +public: + QDeclarativeErrorPrivate(); + + QUrl url; + QString description; + int line; + int column; +}; + +QDeclarativeErrorPrivate::QDeclarativeErrorPrivate() +: line(-1), column(-1) +{ +} + +/*! + Creates an empty error object. +*/ +QDeclarativeError::QDeclarativeError() +: d(0) +{ +} + +/*! + Creates a copy of \a other. +*/ +QDeclarativeError::QDeclarativeError(const QDeclarativeError &other) +: d(0) +{ + *this = other; +} + +/*! + Assigns \a other to this error object. +*/ +QDeclarativeError &QDeclarativeError::operator=(const QDeclarativeError &other) +{ + if (!other.d) { + delete d; + d = 0; + } else { + if (!d) d = new QDeclarativeErrorPrivate; + d->url = other.d->url; + d->description = other.d->description; + d->line = other.d->line; + d->column = other.d->column; + } + return *this; +} + +/*! + \internal +*/ +QDeclarativeError::~QDeclarativeError() +{ + delete d; d = 0; +} + +/*! + Returns true if this error is valid, otherwise false. +*/ +bool QDeclarativeError::isValid() const +{ + return d != 0; +} + +/*! + Returns the url for the file that caused this error. +*/ +QUrl QDeclarativeError::url() const +{ + if (d) return d->url; + else return QUrl(); +} + +/*! + Sets the \a url for the file that caused this error. +*/ +void QDeclarativeError::setUrl(const QUrl &url) +{ + if (!d) d = new QDeclarativeErrorPrivate; + d->url = url; +} + +/*! + Returns the error description. +*/ +QString QDeclarativeError::description() const +{ + if (d) return d->description; + else return QString(); +} + +/*! + Sets the error \a description. +*/ +void QDeclarativeError::setDescription(const QString &description) +{ + if (!d) d = new QDeclarativeErrorPrivate; + d->description = description; +} + +/*! + Returns the error line number. +*/ +int QDeclarativeError::line() const +{ + if (d) return d->line; + else return -1; +} + +/*! + Sets the error \a line number. +*/ +void QDeclarativeError::setLine(int line) +{ + if (!d) d = new QDeclarativeErrorPrivate; + d->line = line; +} + +/*! + Returns the error column number. +*/ +int QDeclarativeError::column() const +{ + if (d) return d->column; + else return -1; +} + +/*! + Sets the error \a column number. +*/ +void QDeclarativeError::setColumn(int column) +{ + if (!d) d = new QDeclarativeErrorPrivate; + d->column = column; +} + +/*! + Returns the error as a human readable string. +*/ +QString QDeclarativeError::toString() const +{ + QString rv; + if (url().isEmpty()) { + rv = QLatin1String("<Unknown File>"); + } else if (line() != -1) { + rv = url().toString() + QLatin1Char(':') + QString::number(line()); + if(column() != -1) + rv += QLatin1Char(':') + QString::number(column()); + } else { + rv = url().toString(); + } + + rv += QLatin1String(": ") + description(); + + return rv; +} + +/*! + \relates QDeclarativeError + \fn QDebug operator<<(QDebug debug, const QDeclarativeError &error) + + Outputs a human readable version of \a error to \a debug. +*/ + +QDebug operator<<(QDebug debug, const QDeclarativeError &error) +{ + debug << qPrintable(error.toString()); + + QUrl url = error.url(); + + if (error.line() > 0 && url.scheme() == QLatin1String("file")) { + QString file = url.toLocalFile(); + QFile f(file); + if (f.open(QIODevice::ReadOnly)) { + QByteArray data = f.readAll(); + QTextStream stream(data, QIODevice::ReadOnly); +#ifndef QT_NO_TEXTCODEC + stream.setCodec("UTF-8"); +#endif + const QString code = stream.readAll(); + const QStringList lines = code.split(QLatin1Char('\n')); + + if (lines.count() >= error.line()) { + const QString &line = lines.at(error.line() - 1); + debug << "\n " << qPrintable(line); + + if(error.column() > 0) { + int column = qMax(0, error.column() - 1); + column = qMin(column, line.length()); + + QByteArray ind; + ind.reserve(column); + for (int i = 0; i < column; ++i) { + const QChar ch = line.at(i); + if (ch.isSpace()) + ind.append(ch.unicode()); + else + ind.append(' '); + } + ind.append('^'); + debug << "\n " << ind.constData(); + } + } + } + } + return debug; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeerror.h b/src/declarative/qml/qdeclarativeerror.h new file mode 100644 index 00000000..0de1628b --- /dev/null +++ b/src/declarative/qml/qdeclarativeerror.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEERROR_H +#define QDECLARATIVEERROR_H + +#include <QtCore/qurl.h> +#include <QtCore/qstring.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDebug; +class QDeclarativeErrorPrivate; +class Q_DECLARATIVE_EXPORT QDeclarativeError +{ +public: + QDeclarativeError(); + QDeclarativeError(const QDeclarativeError &); + QDeclarativeError &operator=(const QDeclarativeError &); + ~QDeclarativeError(); + + bool isValid() const; + + QUrl url() const; + void setUrl(const QUrl &); + QString description() const; + void setDescription(const QString &); + int line() const; + void setLine(int); + int column() const; + void setColumn(int); + + QString toString() const; +private: + QDeclarativeErrorPrivate *d; +}; + +QDebug Q_DECLARATIVE_EXPORT operator<<(QDebug debug, const QDeclarativeError &error); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEERROR_H diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp new file mode 100644 index 00000000..bffa1681 --- /dev/null +++ b/src/declarative/qml/qdeclarativeexpression.cpp @@ -0,0 +1,875 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeexpression.h" +#include "private/qdeclarativeexpression_p.h" + +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativerewrite_p.h" +#include "private/qdeclarativecompiler_p.h" +#include "private/qdeclarativeglobalscriptclass_p.h" + +#include <QtCore/qdebug.h> +#include <QtScript/qscriptprogram.h> + +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e) +{ + if (!e) return false; + + if (e->inProgressCreations == 0) return false; // Not in construction + + if (prevError) return true; // Already in error chain + + prevError = &e->erroredBindings; + nextError = e->erroredBindings; + e->erroredBindings = this; + if (nextError) nextError->prevError = &nextError; + + return true; +} + +QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression() +: dataRef(0), expressionFunctionMode(ExplicitContext), scopeObject(0), trackChange(false), + guardList(0), guardListLength(0), guardObject(0), guardObjectNotifyIndex(-1), deleted(0) +{ +} + +QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression() +{ + if (guardList) { delete [] guardList; guardList = 0; } + if (dataRef) dataRef->release(); + if (deleted) *deleted = true; +} + +QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate() +: expressionFunctionValid(true), line(-1) +{ +} + +QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate() +{ +} + +void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, + QObject *me) +{ + expression = expr; + + QDeclarativeAbstractExpression::setContext(ctxt); + scopeObject = me; + expressionFunctionValid = false; +} + +void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QScriptValue &func, + QObject *me) +{ + expression = func.toString(); + + QDeclarativeAbstractExpression::setContext(ctxt); + scopeObject = me; + + expressionFunction = func; + expressionFunctionMode = ExplicitContext; + expressionFunctionValid = true; +} + +void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr, + QDeclarativeRefCount *rc, + QObject *me, const QString &srcUrl, int lineNumber) +{ + url = srcUrl; + line = lineNumber; + + if (dataRef) dataRef->release(); + dataRef = rc; + if (dataRef) dataRef->addref(); + + quint32 *exprData = (quint32 *)expr; + QDeclarativeCompiledData *dd = (QDeclarativeCompiledData *)rc; + + expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]); + + int progIdx = *(exprData); + bool isSharedProgram = progIdx & 0x80000000; + progIdx &= 0x7FFFFFFF; + + QDeclarativeEngine *engine = ctxt->engine; + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + if (isSharedProgram) { + + if (!dd->cachedClosures.at(progIdx)) { + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); + scriptContext->pushScope(ep->contextClass->newSharedContext()); + scriptContext->pushScope(ep->globalClass->staticGlobalObject()); + dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(expression, url, line)); + scriptEngine->popContext(); + } + + expressionFunction = *dd->cachedClosures.at(progIdx); + expressionFunctionMode = SharedContext; + expressionFunctionValid = true; + + } else { + + if (!dd->cachedPrograms.at(progIdx)) { + dd->cachedPrograms[progIdx] = new QScriptProgram(expression, url, line); + } + + expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx), + &expressionContext); + + expressionFunctionMode = ExplicitContext; + expressionFunctionValid = true; + } + + QDeclarativeAbstractExpression::setContext(ctxt); + scopeObject = me; +} + +QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, + const QString &program, const QString &fileName, + int lineNumber, QScriptValue *contextObject) +{ + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine); + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine); + if (contextObject) { + *contextObject = ep->contextClass->newContext(context, object); + scriptContext->pushScope(*contextObject); + } else { + scriptContext->pushScope(ep->contextClass->newContext(context, object)); + } + scriptContext->pushScope(ep->globalClass->staticGlobalObject()); + QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber); + ep->scriptEngine.popContext(); + return rv; +} + +QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, + const QScriptProgram &program, + QScriptValue *contextObject) +{ + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine); + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine); + if (contextObject) { + *contextObject = ep->contextClass->newContext(context, object); + scriptContext->pushScope(*contextObject); + } else { + scriptContext->pushScope(ep->contextClass->newContext(context, object)); + } + scriptContext->pushScope(ep->globalClass->staticGlobalObject()); + QScriptValue rv = ep->scriptEngine.evaluate(program); + ep->scriptEngine.popContext(); + return rv; +} + +/*! + \class QDeclarativeExpression + \since 4.7 + \brief The QDeclarativeExpression class evaluates JavaScript in a QML context. + + For example, given a file \c main.qml like this: + + \qml + import QtQuick 1.0 + + Item { + width: 200; height: 200 + } + \endqml + + The following code evaluates a JavaScript expression in the context of the + above QML: + + \code + QDeclarativeEngine *engine = new QDeclarativeEngine; + QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml")); + + QObject *myObject = component.create(); + QDeclarativeExpression *expr = new QDeclarativeExpression(engine->rootContext(), myObject, "width * 2"); + int result = expr->evaluate().toInt(); // result = 400 + \endcode +*/ + +static int QDeclarativeExpression_notifyIdx = -1; + +/*! + Create an invalid QDeclarativeExpression. + + As the expression will not have an associated QDeclarativeContext, this will be a + null expression object and its value will always be an invalid QVariant. + */ +QDeclarativeExpression::QDeclarativeExpression() +: QObject(*new QDeclarativeExpressionPrivate, 0) +{ + Q_D(QDeclarativeExpression); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); +} + +/*! \internal */ +QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, void *expr, + QDeclarativeRefCount *rc, QObject *me, + const QString &url, int lineNumber, + QDeclarativeExpressionPrivate &dd) +: QObject(dd, 0) +{ + Q_D(QDeclarativeExpression); + d->init(ctxt, expr, rc, me, url, lineNumber); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); +} + +/*! + Create a QDeclarativeExpression object that is a child of \a parent. + + The \a expression JavaScript will be executed in the \a ctxt QDeclarativeContext. + If specified, the \a scope object's properties will also be in scope during + the expression's execution. +*/ +QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContext *ctxt, + QObject *scope, + const QString &expression, + QObject *parent) +: QObject(*new QDeclarativeExpressionPrivate, parent) +{ + Q_D(QDeclarativeExpression); + d->init(QDeclarativeContextData::get(ctxt), expression, scope); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); +} + +/*! + \internal +*/ +QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, + const QString &expression) +: QObject(*new QDeclarativeExpressionPrivate, 0) +{ + Q_D(QDeclarativeExpression); + d->init(ctxt, expression, scope); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); +} + +/*! \internal */ +QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, + const QString &expression, QDeclarativeExpressionPrivate &dd) +: QObject(dd, 0) +{ + Q_D(QDeclarativeExpression); + d->init(ctxt, expression, scope); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); +} + +/*! \internal */ +QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, const QScriptValue &func, + QDeclarativeExpressionPrivate &dd) +: QObject(dd, 0) +{ + Q_D(QDeclarativeExpression); + d->init(ctxt, func, scope); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); +} + +/*! + Destroy the QDeclarativeExpression instance. +*/ +QDeclarativeExpression::~QDeclarativeExpression() +{ +} + +/*! + Returns the QDeclarativeEngine this expression is associated with, or 0 if there + is no association or the QDeclarativeEngine has been destroyed. +*/ +QDeclarativeEngine *QDeclarativeExpression::engine() const +{ + Q_D(const QDeclarativeExpression); + return d->context()?d->context()->engine:0; +} + +/*! + Returns the QDeclarativeContext this expression is associated with, or 0 if there + is no association or the QDeclarativeContext has been destroyed. +*/ +QDeclarativeContext *QDeclarativeExpression::context() const +{ + Q_D(const QDeclarativeExpression); + QDeclarativeContextData *data = d->context(); + return data?data->asQDeclarativeContext():0; +} + +/*! + Returns the expression string. +*/ +QString QDeclarativeExpression::expression() const +{ + Q_D(const QDeclarativeExpression); + return d->expression; +} + +/*! + Set the expression to \a expression. +*/ +void QDeclarativeExpression::setExpression(const QString &expression) +{ + Q_D(QDeclarativeExpression); + + d->resetNotifyOnChange(); + d->expression = expression; + d->expressionFunctionValid = false; + d->expressionFunction = QScriptValue(); +} + +void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine, + QDeclarativeError &error) +{ + if (scriptEngine->hasUncaughtException() && + scriptEngine->uncaughtException().isError()) { + + QString fileName; + int lineNumber = scriptEngine->uncaughtExceptionLineNumber(); + + QScriptValue exception = scriptEngine->uncaughtException(); + QLatin1String fileNameProp("fileName"); + + if (!exception.property(fileNameProp).toString().isEmpty()){ + fileName = exception.property(fileNameProp).toString(); + } else { + fileName = QLatin1String("<Unknown File>"); + } + + error.setUrl(QUrl(fileName)); + error.setLine(lineNumber); + error.setColumn(-1); + error.setDescription(exception.toString()); + } else { + error = QDeclarativeError(); + } +} + +bool QDeclarativeQtScriptExpression::notifyOnValueChange() const +{ + return trackChange; +} + +void QDeclarativeQtScriptExpression::setNotifyOnValueChange(bool notify) +{ + trackChange = notify; + if (!notify && guardList) + clearGuards(); +} + +void QDeclarativeQtScriptExpression::resetNotifyOnChange() +{ + clearGuards(); +} + +void QDeclarativeQtScriptExpression::setNotifyObject(QObject *object, int notifyIndex) +{ + if (guardList) clearGuards(); + + if (!object || notifyIndex == -1) { + guardObject = 0; + notifyIndex = -1; + } else { + guardObject = object; + guardObjectNotifyIndex = notifyIndex; + + } +} + +void QDeclarativeQtScriptExpression::setEvaluateFlags(EvaluateFlags flags) +{ + evalFlags = flags; +} + +QDeclarativeQtScriptExpression::EvaluateFlags QDeclarativeQtScriptExpression::evaluateFlags() const +{ + return evalFlags; +} + +QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope, bool *isUndefined) +{ + Q_ASSERT(context() && context()->engine); + Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1)); + + if (!expressionFunction.isValid()) { + if (isUndefined) *isUndefined = true; + return QScriptValue(); + } + + DeleteWatcher watcher(this); + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine); + + bool lastCaptureProperties = ep->captureProperties; + QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties; + ep->captureProperties = trackChange; + ep->capturedProperties.copyAndClear(lastCapturedProperties); + + QScriptValue value = eval(secondaryScope, isUndefined); + + if (!watcher.wasDeleted() && trackChange) { + if (ep->capturedProperties.count() == 0) { + + if (guardList) clearGuards(); + + } else { + + updateGuards(ep->capturedProperties); + + } + } + + lastCapturedProperties.copyAndClear(ep->capturedProperties); + ep->captureProperties = lastCaptureProperties; + + return value; +} + +QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined) +{ + Q_ASSERT(context() && context()->engine); + + DeleteWatcher watcher(this); + + QDeclarativeEngine *engine = context()->engine; + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + QDeclarativeContextData *oldSharedContext = 0; + QObject *oldSharedScope = 0; + QObject *oldOverride = 0; + bool isShared = (expressionFunctionMode == SharedContext); + + if (isShared) { + oldSharedContext = ep->sharedContext; + oldSharedScope = ep->sharedScope; + ep->sharedContext = context(); + ep->sharedScope = scopeObject; + } else { + oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope); + } + + QScriptValue thisObject; + if (evalFlags & RequiresThisObject) + thisObject = ep->objectClass->newQObject(scopeObject); + QScriptValue svalue = expressionFunction.call(thisObject); // This could cause this c++ object to be deleted + + if (isShared) { + ep->sharedContext = oldSharedContext; + ep->sharedScope = oldSharedScope; + } else if (!watcher.wasDeleted()) { + ep->contextClass->setOverrideObject(expressionContext, oldOverride); + } + + if (isUndefined) + *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException(); + + // Handle exception + if (scriptEngine->hasUncaughtException()) { + if (!watcher.wasDeleted()) + QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error); + + scriptEngine->clearExceptions(); + return QScriptValue(); + } else { + if (!watcher.wasDeleted()) + error = QDeclarativeError(); + + return svalue; + } +} + +void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties) +{ + Q_ASSERT(guardObject); + Q_ASSERT(guardObjectNotifyIndex != -1); + + if (properties.count() != guardListLength) { + QDeclarativeNotifierEndpoint *newGuardList = new QDeclarativeNotifierEndpoint[properties.count()]; + + for (int ii = 0; ii < qMin(guardListLength, properties.count()); ++ii) + guardList[ii].copyAndClear(newGuardList[ii]); + + delete [] guardList; + guardList = newGuardList; + guardListLength = properties.count(); + } + + bool outputWarningHeader = false; + bool noChanges = true; + for (int ii = 0; ii < properties.count(); ++ii) { + QDeclarativeNotifierEndpoint &guard = guardList[ii]; + const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii); + + guard.target = guardObject; + guard.targetMethod = guardObjectNotifyIndex; + + if (property.notifier != 0) { + + if (!noChanges && guard.isConnected(property.notifier)) { + // Nothing to do + + } else { + noChanges = false; + + bool existing = false; + for (int jj = 0; !existing && jj < ii; ++jj) + if (guardList[jj].isConnected(property.notifier)) + existing = true; + + if (existing) { + // duplicate + guard.disconnect(); + } else { + guard.connect(property.notifier); + } + } + + + } else if (property.notifyIndex != -1) { + + if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) { + // Nothing to do + + } else { + noChanges = false; + + bool existing = false; + for (int jj = 0; !existing && jj < ii; ++jj) + if (guardList[jj].isConnected(property.object, property.notifyIndex)) + existing = true; + + if (existing) { + // duplicate + guard.disconnect(); + } else { + guard.connect(property.object, property.notifyIndex); + } + } + + } else { + if (!outputWarningHeader) { + outputWarningHeader = true; + qWarning() << "QDeclarativeExpression: Expression" << expression + << "depends on non-NOTIFYable properties:"; + } + + const QMetaObject *metaObj = property.object->metaObject(); + QMetaProperty metaProp = metaObj->property(property.coreIndex); + + qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name(); + } + } +} + +QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined) +{ + if (!expressionFunctionValid) { + QDeclarativeEngine *engine = context()->engine; + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); + expressionContext = ep->contextClass->newContext(context(), scopeObject); + scriptContext->pushScope(expressionContext); + scriptContext->pushScope(ep->globalClass->staticGlobalObject()); + + QDeclarativeRewrite::RewriteBinding rewriteBinding; + rewriteBinding.setName(name); + bool ok = true; + const QString code = rewriteBinding(expression, &ok); + if (ok) + expressionFunction = scriptEngine->evaluate(code, url, line); + + scriptEngine->popContext(); + expressionFunctionMode = ExplicitContext; + expressionFunctionValid = true; + } + + return QDeclarativeQtScriptExpression::scriptValue(secondaryScope, isUndefined); +} + +QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) +{ + Q_Q(QDeclarativeExpression); + + if (!context() || !context()->isValid()) { + qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context"); + return QVariant(); + } + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine()); + + return ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >()); +} + +/*! + Evaulates the expression, returning the result of the evaluation, + or an invalid QVariant if the expression is invalid or has an error. + + \a valueIsUndefined is set to true if the expression resulted in an + undefined value. + + \sa hasError(), error() +*/ +QVariant QDeclarativeExpression::evaluate(bool *valueIsUndefined) +{ + Q_D(QDeclarativeExpression); + return d->value(0, valueIsUndefined); +} + +/*! +Returns true if the valueChanged() signal is emitted when the expression's evaluated +value changes. +*/ +bool QDeclarativeExpression::notifyOnValueChanged() const +{ + Q_D(const QDeclarativeExpression); + return d->notifyOnValueChange(); +} + +/*! + Sets whether the valueChanged() signal is emitted when the + expression's evaluated value changes. + + If \a notifyOnChange is true, the QDeclarativeExpression will + monitor properties involved in the expression's evaluation, and emit + QDeclarativeExpression::valueChanged() if they have changed. This + allows an application to ensure that any value associated with the + result of the expression remains up to date. + + If \a notifyOnChange is false (default), the QDeclarativeExpression + will not montitor properties involved in the expression's + evaluation, and QDeclarativeExpression::valueChanged() will never be + emitted. This is more efficient if an application wants a "one off" + evaluation of the expression. +*/ +void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange) +{ + Q_D(QDeclarativeExpression); + d->setNotifyOnValueChange(notifyOnChange); +} + +/*! + Returns the source file URL for this expression. The source location must + have been previously set by calling setSourceLocation(). +*/ +QString QDeclarativeExpression::sourceFile() const +{ + Q_D(const QDeclarativeExpression); + return d->url; +} + +/*! + Returns the source file line number for this expression. The source location + must have been previously set by calling setSourceLocation(). +*/ +int QDeclarativeExpression::lineNumber() const +{ + Q_D(const QDeclarativeExpression); + return d->line; +} + +/*! + Set the location of this expression to \a line of \a url. This information + is used by the script engine. +*/ +void QDeclarativeExpression::setSourceLocation(const QString &url, int line) +{ + Q_D(QDeclarativeExpression); + d->url = url; + d->line = line; +} + +/*! + Returns the expression's scope object, if provided, otherwise 0. + + In addition to data provided by the expression's QDeclarativeContext, the scope + object's properties are also in scope during the expression's evaluation. +*/ +QObject *QDeclarativeExpression::scopeObject() const +{ + Q_D(const QDeclarativeExpression); + return d->scopeObject; +} + +/*! + Returns true if the last call to evaluate() resulted in an error, + otherwise false. + + \sa error(), clearError() +*/ +bool QDeclarativeExpression::hasError() const +{ + Q_D(const QDeclarativeExpression); + return d->error.isValid(); +} + +/*! + Clear any expression errors. Calls to hasError() following this will + return false. + + \sa hasError(), error() +*/ +void QDeclarativeExpression::clearError() +{ + Q_D(QDeclarativeExpression); + d->error = QDeclarativeError(); +} + +/*! + Return any error from the last call to evaluate(). If there was no error, + this returns an invalid QDeclarativeError instance. + + \sa hasError(), clearError() +*/ + +QDeclarativeError QDeclarativeExpression::error() const +{ + Q_D(const QDeclarativeExpression); + return d->error; +} + +/*! \internal */ +void QDeclarativeExpressionPrivate::_q_notify() +{ + emitValueChanged(); +} + +void QDeclarativeQtScriptExpression::clearGuards() +{ + delete [] guardList; + guardList = 0; + guardListLength = 0; +} + +/*! + \fn void QDeclarativeExpression::valueChanged() + + Emitted each time the expression value changes from the last time it was + evaluated. The expression must have been evaluated at least once (by + calling QDeclarativeExpression::evaluate()) before this signal will be emitted. +*/ + +void QDeclarativeExpressionPrivate::emitValueChanged() +{ + Q_Q(QDeclarativeExpression); + emit q->valueChanged(); +} + +QDeclarativeAbstractExpression::QDeclarativeAbstractExpression() +: m_context(0), m_prevExpression(0), m_nextExpression(0) +{ +} + +QDeclarativeAbstractExpression::~QDeclarativeAbstractExpression() +{ + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + } +} + +QDeclarativeContextData *QDeclarativeAbstractExpression::context() const +{ + return m_context; +} + +void QDeclarativeAbstractExpression::setContext(QDeclarativeContextData *context) +{ + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + m_prevExpression = 0; + m_nextExpression = 0; + } + + m_context = context; + + if (m_context) { + m_nextExpression = m_context->expressions; + if (m_nextExpression) + m_nextExpression->m_prevExpression = &m_nextExpression; + m_prevExpression = &context->expressions; + m_context->expressions = this; + } +} + +void QDeclarativeAbstractExpression::refresh() +{ +} + +bool QDeclarativeAbstractExpression::isValid() const +{ + return m_context != 0; +} + +QT_END_NAMESPACE + +#include <moc_qdeclarativeexpression.cpp> diff --git a/src/declarative/qml/qdeclarativeexpression.h b/src/declarative/qml/qdeclarativeexpression.h new file mode 100644 index 00000000..732aa747 --- /dev/null +++ b/src/declarative/qml/qdeclarativeexpression.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEEXPRESSION_H +#define QDECLARATIVEEXPRESSION_H + +#include <QtDeclarative/qdeclarativeerror.h> + +#include <QtCore/qobject.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QString; +class QDeclarativeRefCount; +class QDeclarativeEngine; +class QDeclarativeContext; +class QDeclarativeExpressionPrivate; +class QDeclarativeContextData; +class QScriptValue; +class Q_DECLARATIVE_EXPORT QDeclarativeExpression : public QObject +{ + Q_OBJECT +public: + QDeclarativeExpression(); + QDeclarativeExpression(QDeclarativeContext *, QObject *, const QString &, QObject * = 0); + virtual ~QDeclarativeExpression(); + + QDeclarativeEngine *engine() const; + QDeclarativeContext *context() const; + + QString expression() const; + void setExpression(const QString &); + + bool notifyOnValueChanged() const; + void setNotifyOnValueChanged(bool); + + QString sourceFile() const; + int lineNumber() const; + void setSourceLocation(const QString &fileName, int line); + + QObject *scopeObject() const; + + bool hasError() const; + void clearError(); + QDeclarativeError error() const; + + QVariant evaluate(bool *valueIsUndefined = 0); + +Q_SIGNALS: + void valueChanged(); + +protected: + QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QString &, + QDeclarativeExpressionPrivate &dd); + QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QScriptValue &, + QDeclarativeExpressionPrivate &dd); + QDeclarativeExpression(QDeclarativeContextData *, void *, QDeclarativeRefCount *rc, + QObject *me, const QString &, int, QDeclarativeExpressionPrivate &dd); + +private: + QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QString &); + + Q_DISABLE_COPY(QDeclarativeExpression) + Q_DECLARE_PRIVATE(QDeclarativeExpression) + Q_PRIVATE_SLOT(d_func(), void _q_notify()) + friend class QDeclarativeDebugger; + friend class QDeclarativeContext; + friend class QDeclarativeVME; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEEXPRESSION_H + diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h new file mode 100644 index 00000000..bc47fb4b --- /dev/null +++ b/src/declarative/qml/qdeclarativeexpression_p.h @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEEXPRESSION_P_H +#define QDECLARATIVEEXPRESSION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativeexpression.h" + +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativeguard_p.h" + +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeAbstractExpression +{ +public: + QDeclarativeAbstractExpression(); + virtual ~QDeclarativeAbstractExpression(); + + bool isValid() const; + + QDeclarativeContextData *context() const; + void setContext(QDeclarativeContextData *); + + virtual void refresh(); + +private: + friend class QDeclarativeContext; + friend class QDeclarativeContextData; + friend class QDeclarativeContextPrivate; + QDeclarativeContextData *m_context; + QDeclarativeAbstractExpression **m_prevExpression; + QDeclarativeAbstractExpression *m_nextExpression; +}; + +class QDeclarativeDelayedError +{ +public: + inline QDeclarativeDelayedError() : nextError(0), prevError(0) {} + inline ~QDeclarativeDelayedError() { removeError(); } + + QDeclarativeError error; + + bool addError(QDeclarativeEnginePrivate *); + + inline void removeError() { + if (!prevError) return; + if (nextError) nextError->prevError = prevError; + *prevError = nextError; + nextError = 0; + prevError = 0; + } + +private: + QDeclarativeDelayedError *nextError; + QDeclarativeDelayedError **prevError; +}; + +class QDeclarativeQtScriptExpression : public QDeclarativeAbstractExpression, + public QDeclarativeDelayedError +{ +public: + enum Mode { SharedContext, ExplicitContext }; + + enum EvaluateFlag { RequiresThisObject = 0x01 }; + Q_DECLARE_FLAGS(EvaluateFlags, EvaluateFlag) + + QDeclarativeQtScriptExpression(); + virtual ~QDeclarativeQtScriptExpression(); + + QDeclarativeRefCount *dataRef; + + QString expression; + + Mode expressionFunctionMode; + QScriptValue expressionFunction; + + QScriptValue expressionContext; // Only used in ExplicitContext + QObject *scopeObject; // Only used in SharedContext + + bool notifyOnValueChange() const; + void setNotifyOnValueChange(bool); + void resetNotifyOnChange(); + void setNotifyObject(QObject *, int ); + + void setEvaluateFlags(EvaluateFlags flags); + EvaluateFlags evaluateFlags() const; + + QScriptValue scriptValue(QObject *secondaryScope, bool *isUndefined); + + class DeleteWatcher { + public: + inline DeleteWatcher(QDeclarativeQtScriptExpression *data); + inline ~DeleteWatcher(); + inline bool wasDeleted() const; + private: + bool *m_wasDeleted; + bool m_wasDeletedStorage; + QDeclarativeQtScriptExpression *m_d; + }; + +private: + void clearGuards(); + QScriptValue eval(QObject *secondaryScope, bool *isUndefined); + void updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties); + + bool trackChange; + + QDeclarativeNotifierEndpoint *guardList; + int guardListLength; + + QObject *guardObject; + int guardObjectNotifyIndex; + bool *deleted; + + EvaluateFlags evalFlags; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeQtScriptExpression::EvaluateFlags) + + +class QDeclarativeExpression; +class QString; +class QDeclarativeExpressionPrivate : public QObjectPrivate, public QDeclarativeQtScriptExpression +{ + Q_DECLARE_PUBLIC(QDeclarativeExpression) +public: + QDeclarativeExpressionPrivate(); + ~QDeclarativeExpressionPrivate(); + + void init(QDeclarativeContextData *, const QString &, QObject *); + void init(QDeclarativeContextData *, const QScriptValue &, QObject *); + void init(QDeclarativeContextData *, void *, QDeclarativeRefCount *, QObject *, const QString &, int); + + QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0); + QScriptValue scriptValue(QObject *secondaryScope = 0, bool *isUndefined = 0); + + static QDeclarativeExpressionPrivate *get(QDeclarativeExpression *expr) { + return static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr)); + } + static QDeclarativeExpression *get(QDeclarativeExpressionPrivate *expr) { + return expr->q_func(); + } + + void _q_notify(); + virtual void emitValueChanged(); + + static void exceptionToError(QScriptEngine *, QDeclarativeError &); + static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QString &, const QString &, + int, QScriptValue *); + static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QScriptProgram &, + QScriptValue *); + + bool expressionFunctionValid:1; + + QString url; // This is a QString for a reason. QUrls are slooooooow... + int line; + QByteArray name; //function name, hint for the debugger +}; + +QDeclarativeQtScriptExpression::DeleteWatcher::DeleteWatcher(QDeclarativeQtScriptExpression *data) +: m_wasDeletedStorage(false), m_d(data) +{ + if (!m_d->deleted) + m_d->deleted = &m_wasDeletedStorage; + m_wasDeleted = m_d->deleted; +} + +QDeclarativeQtScriptExpression::DeleteWatcher::~DeleteWatcher() +{ + if (false == *m_wasDeleted && m_wasDeleted == m_d->deleted) + m_d->deleted = 0; +} + +bool QDeclarativeQtScriptExpression::DeleteWatcher::wasDeleted() const +{ + return *m_wasDeleted; +} + +QT_END_NAMESPACE + +#endif // QDECLARATIVEEXPRESSION_P_H diff --git a/src/declarative/qml/qdeclarativeextensioninterface.h b/src/declarative/qml/qdeclarativeextensioninterface.h new file mode 100644 index 00000000..695d345f --- /dev/null +++ b/src/declarative/qml/qdeclarativeextensioninterface.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEEXTENSIONINTERFACE_H +#define QDECLARATIVEEXTENSIONINTERFACE_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeEngine; + +struct Q_DECLARATIVE_EXPORT QDeclarativeExtensionInterface +{ + virtual ~QDeclarativeExtensionInterface() {} + virtual void registerTypes(const char *uri) = 0; + virtual void initializeEngine(QDeclarativeEngine *engine, const char *uri) = 0; +}; + +Q_DECLARE_INTERFACE(QDeclarativeExtensionInterface, "com.trolltech.Qt.QDeclarativeExtensionInterface/1.0") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEEXTENSIONINTERFACE_H diff --git a/src/declarative/qml/qdeclarativeextensionplugin.cpp b/src/declarative/qml/qdeclarativeextensionplugin.cpp new file mode 100644 index 00000000..c93e4db6 --- /dev/null +++ b/src/declarative/qml/qdeclarativeextensionplugin.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeextensionplugin.h" + +QT_BEGIN_NAMESPACE + +/*! + \since 4.7 + \class QDeclarativeExtensionPlugin + \brief The QDeclarativeExtensionPlugin class provides an abstract base for custom QML extension plugins. + + \ingroup plugins + + QDeclarativeExtensionPlugin is a plugin interface that makes it possible to + create QML extensions that can be loaded dynamically into QML applications. + These extensions allow custom QML types to be made available to the QML engine. + + To write a QML extension plugin: + + \list + \o Subclass QDeclarativeExtensionPlugin, implement registerTypes() method + to register types using qmlRegisterType(), and export the class using the Q_EXPORT_PLUGIN2() macro + \o Write an appropriate project file for the plugin + \o Create a \l{Writing a qmldir file}{qmldir file} to describe the plugin + \endlist + + QML extension plugins can be used to provide either application-specific or + library-like plugins. Library plugins should limit themselves to registering types, + as any manipulation of the engine's root context may cause conflicts + or other issues in the library user's code. + + + \section1 An example + + Suppose there is a new \c TimeModel C++ class that should be made available + as a new QML element. It provides the current time through \c hour and \c minute + properties, like this: + + \snippet examples/declarative/cppextensions/plugins/plugin.cpp 0 + \dots + + To make this class available as a QML type, create a plugin that registers + this type with a specific \l {QML Modules}{module} using qmlRegisterType(). For this example the plugin + module will be named \c com.nokia.TimeExample (as defined in the project + file further below). + + \snippet examples/declarative/cppextensions/plugins/plugin.cpp plugin + \codeline + \snippet examples/declarative/cppextensions/plugins/plugin.cpp export + + This registers the \c TimeModel class with the 1.0 version of this + plugin library, as a QML type called \c Time. The Q_ASSERT statement + ensures the module is imported correctly by any QML components that use this plugin. + + The project file defines the project as a plugin library and specifies + it should be built into the \c com/nokia/TimeExample directory: + + \code + TEMPLATE = lib + CONFIG += qt plugin + QT += declarative + + DESTDIR = com/nokia/TimeExample + TARGET = qmlqtimeexampleplugin + ... + \endcode + + Finally, a \l{Writing a qmldir file}{qmldir file} is required in the \c com/nokia/TimeExample directory + that describes the plugin. This directory includes a \c Clock.qml file that + should be bundled with the plugin, so it needs to be specified in the \c qmldir + file: + + \quotefile examples/declarative/cppextensions/plugins/com/nokia/TimeExample/qmldir + + Once the project is built and installed, the new \c Time element can be + used by any QML component that imports the \c com.nokia.TimeExample module: + + \snippet examples/declarative/cppextensions/plugins/plugins.qml 0 + + The full source code is available in the \l {declarative/cppextensions/plugins}{plugins example}. + + The \l {Tutorial: Writing QML extensions with C++} also contains a chapter + on creating QML plugins. + + \sa QDeclarativeEngine::importPlugin(), {How to Create Qt Plugins} +*/ + +/*! + \fn void QDeclarativeExtensionPlugin::registerTypes(const char *uri) + + Registers the QML types in the given \a uri. Subclasses should implement + this to call qmlRegisterType() for all types which are provided by the extension + plugin. + + The \a uri is an identifier for the plugin generated by the QML engine + based on the name and path of the extension's plugin library. +*/ + +/*! + Constructs a QML extension plugin with the given \a parent. + + Note that this constructor is invoked automatically by the + Q_EXPORT_PLUGIN2() macro, so there is no need for calling it + explicitly. +*/ +QDeclarativeExtensionPlugin::QDeclarativeExtensionPlugin(QObject *parent) + : QObject(parent) +{ +} + +/*! + \internal + */ +QDeclarativeExtensionPlugin::~QDeclarativeExtensionPlugin() +{ +} + +/*! + \fn void QDeclarativeExtensionPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri) + + Initializes the extension from the \a uri using the \a engine. Here an application + plugin might, for example, expose some data or objects to QML, + as context properties on the engine's root context. +*/ + +void QDeclarativeExtensionPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri) +{ + Q_UNUSED(engine); + Q_UNUSED(uri); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeextensionplugin.h b/src/declarative/qml/qdeclarativeextensionplugin.h new file mode 100644 index 00000000..7ae49870 --- /dev/null +++ b/src/declarative/qml/qdeclarativeextensionplugin.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEEXTENSIONPLUGIN_H +#define QDECLARATIVEEXTENSIONPLUGIN_H + +#include <QtCore/qplugin.h> + +#include <QtDeclarative/qdeclarativeextensioninterface.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeEngine; + +class Q_DECLARATIVE_EXPORT QDeclarativeExtensionPlugin : public QObject, public QDeclarativeExtensionInterface +{ + Q_OBJECT + Q_INTERFACES(QDeclarativeExtensionInterface) +public: + explicit QDeclarativeExtensionPlugin(QObject *parent = 0); + ~QDeclarativeExtensionPlugin(); + + virtual void registerTypes(const char *uri) = 0; + virtual void initializeEngine(QDeclarativeEngine *engine, const char *uri); + +private: + Q_DISABLE_COPY(QDeclarativeExtensionPlugin) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEEXTENSIONPLUGIN_H diff --git a/src/declarative/qml/qdeclarativefastproperties.cpp b/src/declarative/qml/qdeclarativefastproperties.cpp new file mode 100644 index 00000000..2c4d6223 --- /dev/null +++ b/src/declarative/qml/qdeclarativefastproperties.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativefastproperties_p.h" + +#include <private/qdeclarativeitem_p.h> + +QT_BEGIN_NAMESPACE + +// Adding entries to the QDeclarativeFastProperties class allows the QML +// binding optimizer to bypass Qt's meta system and read and, more +// importantly, subscribe to properties directly. Any property that is +// primarily read from bindings is a candidate for inclusion as a fast +// property. + +static void QObject_objectName(QObject *object, void *output, QDeclarativeNotifierEndpoint *endpoint) +{ + if (endpoint) + endpoint->connect(QDeclarativeData::get(object, true)->objectNameNotifier()); + *((QString *)output) = object->objectName(); +} + +QDeclarativeFastProperties::QDeclarativeFastProperties() +{ + add(&QDeclarativeItem::staticMetaObject, QDeclarativeItem::staticMetaObject.indexOfProperty("parent"), + QDeclarativeItemPrivate::parentProperty); + add(&QObject::staticMetaObject, QObject::staticMetaObject.indexOfProperty("objectName"), + QObject_objectName); +} + +int QDeclarativeFastProperties::accessorIndexForProperty(const QMetaObject *metaObject, int propertyIndex) +{ + Q_ASSERT(metaObject); + Q_ASSERT(propertyIndex >= 0); + + // Find the "real" metaObject + while (metaObject->propertyOffset() > propertyIndex) + metaObject = metaObject->superClass(); + + QHash<QPair<const QMetaObject *, int>, int>::Iterator iter = + m_index.find(qMakePair(metaObject, propertyIndex)); + if (iter != m_index.end()) + return *iter; + else + return -1; +} + +void QDeclarativeFastProperties::add(const QMetaObject *metaObject, int propertyIndex, Accessor accessor) +{ + Q_ASSERT(metaObject); + Q_ASSERT(propertyIndex >= 0); + + // Find the "real" metaObject + while (metaObject->propertyOffset() > propertyIndex) + metaObject = metaObject->superClass(); + + QPair<const QMetaObject *, int> data = qMakePair(metaObject, propertyIndex); + int accessorIndex = m_accessors.count(); + m_accessors.append(accessor); + m_index.insert(data, accessorIndex); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativefastproperties_p.h b/src/declarative/qml/qdeclarativefastproperties_p.h new file mode 100644 index 00000000..e81f5642 --- /dev/null +++ b/src/declarative/qml/qdeclarativefastproperties_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEFASTPROPERTIES_P_H +#define QDECLARATIVEFASTPROPERTIES_P_H + +#include <QtCore/qvector.h> +#include <QtCore/qhash.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QObject; +class QDeclarativeNotifierEndpoint; +class QDeclarativeFastProperties +{ +public: + typedef void (*Accessor)(QObject *object, void *output, QDeclarativeNotifierEndpoint *endpoint); + + QDeclarativeFastProperties(); + + Accessor accessor(int index) const { return m_accessors.at(index); } + int accessorIndexForProperty(const QMetaObject *, int); + +private: + void add(const QMetaObject *, int, Accessor); + + QHash<QPair<const QMetaObject *, int>, int> m_index; + QVector<Accessor> m_accessors; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEFASTPROPERTIES_P_H diff --git a/src/declarative/qml/qdeclarativeglobal_p.h b/src/declarative/qml/qdeclarativeglobal_p.h new file mode 100644 index 00000000..f46f44e5 --- /dev/null +++ b/src/declarative/qml/qdeclarativeglobal_p.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEGLOBAL_H +#define QDECLARATIVEGLOBAL_H + +#include <QtCore/qglobal.h> +#include <QtCore/QObject> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +#define DEFINE_BOOL_CONFIG_OPTION(name, var) \ + static bool name() \ + { \ + static enum { Yes, No, Unknown } status = Unknown; \ + if (status == Unknown) { \ + QByteArray v = qgetenv(#var); \ + bool value = !v.isEmpty() && v != "0" && v != "false"; \ + if (value) status = Yes; \ + else status = No; \ + } \ + return status == Yes; \ + } + +#ifdef Q_OS_SYMBIAN +#define Q_DECLARATIVE_PRIVATE_EXPORT Q_AUTOTEST_EXPORT +#else +#define Q_DECLARATIVE_PRIVATE_EXPORT Q_DECLARATIVE_EXPORT +#endif + +struct QDeclarativeGraphics_DerivedObject : public QObject +{ + void setParent_noEvent(QObject *parent) { + bool sce = d_ptr->sendChildEvents; + d_ptr->sendChildEvents = false; + setParent(parent); + d_ptr->sendChildEvents = sce; + } +}; + +/*! + Returns true if the case of \a fileName is equivalent to the file case of + \a fileName on disk, and false otherwise. + + This is used to ensure that the behavior of QML on a case-insensitive file + system is the same as on a case-sensitive file system. This function + performs a "best effort" attempt to determine the real case of the file. + It may have false positives (say the case is correct when it isn't), but it + should never have a false negative (say the case is incorrect when it is + correct). +*/ +bool QDeclarative_isFileCaseCorrect(const QString &fileName); + +/*! + Makes the \a object a child of \a parent. Note that when using this method, + neither \a parent nor the object's previous parent (if it had one) will + receive ChildRemoved or ChildAdded events. +*/ +inline void QDeclarative_setParent_noEvent(QObject *object, QObject *parent) +{ + static_cast<QDeclarativeGraphics_DerivedObject *>(object)->setParent_noEvent(parent); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEGLOBAL_H diff --git a/src/declarative/qml/qdeclarativeglobalscriptclass.cpp b/src/declarative/qml/qdeclarativeglobalscriptclass.cpp new file mode 100644 index 00000000..724c36c3 --- /dev/null +++ b/src/declarative/qml/qdeclarativeglobalscriptclass.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativeglobalscriptclass_p.h" + +#include <QtCore/qstringlist.h> +#include <QtCore/qvector.h> +#include <QtScript/qscriptstring.h> +#include <QtScript/qscriptengine.h> +#include <QtScript/qscriptvalueiterator.h> + +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +/* + Used to prevent any writes to the global object. +*/ +QDeclarativeGlobalScriptClass::QDeclarativeGlobalScriptClass(QScriptEngine *engine) +: QScriptClass(engine) +{ + QString eval = QLatin1String("eval"); + QString version = QLatin1String("version"); + + QScriptValue originalGlobalObject = engine->globalObject(); + + QScriptValue newGlobalObject = engine->newObject(); + + { + QScriptValueIterator iter(originalGlobalObject); + QVector<QString> names; + QVector<QScriptValue> values; + QVector<QScriptValue::PropertyFlags> flags; + while (iter.hasNext()) { + iter.next(); + + QString name = iter.name(); + + if (name == version) + continue; + + if (name != eval) { + names.append(name); + values.append(iter.value()); + flags.append(iter.flags() | QScriptValue::Undeletable); + } + newGlobalObject.setProperty(iter.scriptName(), iter.value()); + + m_illegalNames.insert(name); + } + m_staticGlobalObject = QScriptDeclarativeClass::newStaticScopeObject( + engine, names.size(), names.constData(), values.constData(), flags.constData()); + } + + newGlobalObject.setScriptClass(this); + engine->setGlobalObject(newGlobalObject); +} + +QScriptClass::QueryFlags +QDeclarativeGlobalScriptClass::queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id) +{ + Q_UNUSED(object); + Q_UNUSED(name); + Q_UNUSED(flags); + Q_UNUSED(id); + return HandlesWriteAccess; +} + +void QDeclarativeGlobalScriptClass::setProperty(QScriptValue &object, + const QScriptString &name, + uint id, const QScriptValue &value) +{ + Q_UNUSED(object); + Q_UNUSED(id); + Q_UNUSED(value); + QString error = QLatin1String("Invalid write to global property \"") + + name.toString() + QLatin1Char('\"'); + engine()->currentContext()->throwError(error); +} + +/* This method is for the use of tst_qdeclarativeecmascript::callQtInvokables() only */ +void QDeclarativeGlobalScriptClass::explicitSetProperty(const QStringList &names, const QList<QScriptValue> &values) +{ + Q_ASSERT(names.count() == values.count()); + QScriptValue globalObject = engine()->globalObject(); + + QScriptValue v = engine()->newObject(); + + QScriptValueIterator iter(v); + while (iter.hasNext()) { + iter.next(); + v.setProperty(iter.scriptName(), iter.value()); + } + + for (int ii = 0; ii < names.count(); ++ii) { + const QString &name = names.at(ii); + const QScriptValue &value = values.at(ii); + v.setProperty(name, value); + } + + v.setScriptClass(this); + + engine()->setGlobalObject(v); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativeglobalscriptclass_p.h b/src/declarative/qml/qdeclarativeglobalscriptclass_p.h new file mode 100644 index 00000000..2e751e18 --- /dev/null +++ b/src/declarative/qml/qdeclarativeglobalscriptclass_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEGLOBALSCRIPTCLASS_P_H +#define QDECLARATIVEGLOBALSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtScript/qscriptclass.h> +#include <QtCore/qset.h> + +QT_BEGIN_NAMESPACE + +class Q_AUTOTEST_EXPORT QDeclarativeGlobalScriptClass : public QScriptClass +{ +public: + QDeclarativeGlobalScriptClass(QScriptEngine *); + + virtual QueryFlags queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id); + + virtual void setProperty(QScriptValue &object, const QScriptString &name, + uint id, const QScriptValue &value); + + void explicitSetProperty(const QStringList &, const QList<QScriptValue> &); + + const QScriptValue &staticGlobalObject() const { return m_staticGlobalObject; } + + const QSet<QString> &illegalNames() const { return m_illegalNames; } + +private: + QSet<QString> m_illegalNames; + QScriptValue m_staticGlobalObject; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEGLOBALSCRIPTCLASS_P_H diff --git a/src/declarative/qml/qdeclarativeguard_p.h b/src/declarative/qml/qdeclarativeguard_p.h new file mode 100644 index 00000000..0685ed2f --- /dev/null +++ b/src/declarative/qml/qdeclarativeguard_p.h @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEGUARD_P_H +#define QDECLARATIVEGUARD_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QtCore/qvariant.h> +#include <private/qdeclarativedata_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeGuardImpl +{ +public: + inline QDeclarativeGuardImpl(); + inline QDeclarativeGuardImpl(QObject *); + inline QDeclarativeGuardImpl(const QDeclarativeGuardImpl &); + inline ~QDeclarativeGuardImpl(); + + QObject *o; + QDeclarativeGuardImpl *next; + QDeclarativeGuardImpl **prev; + + inline void addGuard(); + inline void remGuard(); +}; + +class QObject; +template<class T> +class QDeclarativeGuard : private QDeclarativeGuardImpl +{ + friend class QDeclarativeData; +public: + inline QDeclarativeGuard(); + inline QDeclarativeGuard(T *); + inline QDeclarativeGuard(const QDeclarativeGuard<T> &); + inline virtual ~QDeclarativeGuard(); + + inline QDeclarativeGuard<T> &operator=(const QDeclarativeGuard<T> &o); + inline QDeclarativeGuard<T> &operator=(T *); + + inline T *object() const; + inline void setObject(T *g); + + inline bool isNull() const + { return !o; } + + inline T* operator->() const + { return static_cast<T*>(const_cast<QObject*>(o)); } + inline T& operator*() const + { return *static_cast<T*>(const_cast<QObject*>(o)); } + inline operator T*() const + { return static_cast<T*>(const_cast<QObject*>(o)); } + inline T* data() const + { return static_cast<T*>(const_cast<QObject*>(o)); } + +protected: + virtual void objectDestroyed(T *) {} +}; + +QDeclarativeGuardImpl::QDeclarativeGuardImpl() +: o(0), next(0), prev(0) +{ +} + +QDeclarativeGuardImpl::QDeclarativeGuardImpl(QObject *g) +: o(g), next(0), prev(0) +{ + if (o) addGuard(); +} + +QDeclarativeGuardImpl::QDeclarativeGuardImpl(const QDeclarativeGuardImpl &g) +: o(g.o), next(0), prev(0) +{ + if (o) addGuard(); +} + +QDeclarativeGuardImpl::~QDeclarativeGuardImpl() +{ + if (prev) remGuard(); + o = 0; +} + +void QDeclarativeGuardImpl::addGuard() +{ + Q_ASSERT(!prev); + + if (QObjectPrivate::get(o)->wasDeleted) + return; + + QDeclarativeData *data = QDeclarativeData::get(o, true); + next = data->guards; + if (next) next->prev = &next; + data->guards = this; + prev = &data->guards; +} + +void QDeclarativeGuardImpl::remGuard() +{ + Q_ASSERT(prev); + + if (next) next->prev = prev; + *prev = next; + next = 0; + prev = 0; +} + +template<class T> +QDeclarativeGuard<T>::QDeclarativeGuard() +{ +} + +template<class T> +QDeclarativeGuard<T>::QDeclarativeGuard(T *g) +: QDeclarativeGuardImpl(g) +{ +} + +template<class T> +QDeclarativeGuard<T>::QDeclarativeGuard(const QDeclarativeGuard<T> &g) +: QDeclarativeGuardImpl(g) +{ +} + +template<class T> +QDeclarativeGuard<T>::~QDeclarativeGuard() +{ +} + +template<class T> +QDeclarativeGuard<T> &QDeclarativeGuard<T>::operator=(const QDeclarativeGuard<T> &g) +{ + setObject(g.object()); + return *this; +} + +template<class T> +QDeclarativeGuard<T> &QDeclarativeGuard<T>::operator=(T *g) +{ + setObject(g); + return *this; +} + +template<class T> +T *QDeclarativeGuard<T>::object() const +{ + return static_cast<T *>(o); +}; + +template<class T> +void QDeclarativeGuard<T>::setObject(T *g) +{ + if (g != o) { + if (prev) remGuard(); + o = g; + if (o) addGuard(); + } +} + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDeclarativeGuard<QObject>) + +#endif // QDECLARATIVEGUARD_P_H diff --git a/src/declarative/qml/qdeclarativeimageprovider.cpp b/src/declarative/qml/qdeclarativeimageprovider.cpp new file mode 100644 index 00000000..8eb15d18 --- /dev/null +++ b/src/declarative/qml/qdeclarativeimageprovider.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeimageprovider.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativeImageProviderPrivate +{ +public: + QDeclarativeImageProvider::ImageType type; +}; + +/*! + \class QDeclarativeImageProvider + \since 4.7 + \brief The QDeclarativeImageProvider class provides an interface for supporting pixmaps and threaded image requests in QML. + + QDeclarativeImageProvider is used to provide advanced image loading features + in QML applications. It allows images in QML to be: + + \list + \o Loaded using QPixmaps rather than actual image files + \o Loaded asynchronously in a separate thread, if imageType() is \l{QDeclarativeImageProvider::ImageType}{ImageType::Image} + \endlist + + To specify that an image should be loaded by an image provider, use the + \bold {"image:"} scheme for the URL source of the image, followed by the + identifiers of the image provider and the requested image. For example: + + \qml + Image { source: "image://myimageprovider/image.png" } + \endqml + + This specifies that the image should be loaded by the image provider named + "myimageprovider", and the image to be loaded is named "image.png". The QML engine + invokes the appropriate image provider according to the providers that have + been registered through QDeclarativeEngine::addImageProvider(). + + Note that the identifiers are case-insensitive, but the rest of the URL will be passed on with + preserved case. For example, the below snippet would still specify that the image is loaded by the + image provider named "myimageprovider", but it would request a different image than the above snippet + ("Image.png" instead of "image.png"). + \qml + Image { source: "image://MyImageProvider/Image.png" } + \endqml + + If you want the rest of the URL to be case insensitive, you will have to take care + of that yourself inside your image provider. + + \section2 An example + + Here are two images. Their \c source values indicate they should be loaded by + an image provider named "colors", and the images to be loaded are "yellow" + and "red", respectively: + + \snippet examples/declarative/cppextensions/imageprovider/imageprovider-example.qml 0 + + When these images are loaded by QML, it looks for a matching image provider + and calls its requestImage() or requestPixmap() method (depending on its + imageType()) to load the image. The method is called with the \c id + parameter set to "yellow" for the first image, and "red" for the second. + + Here is an image provider implementation that can load the images + requested by the above QML. This implementation dynamically + generates QPixmap images that are filled with the requested color: + + \snippet examples/declarative/cppextensions/imageprovider/imageprovider.cpp 0 + \codeline + \snippet examples/declarative/cppextensions/imageprovider/imageprovider.cpp 1 + + To make this provider accessible to QML, it is registered with the QML engine + with a "colors" identifier: + + \code + int main(int argc, char *argv[]) + { + ... + + QDeclarativeEngine engine; + engine->addImageProvider(QLatin1String("colors"), new ColorPixmapProvider); + + ... + } + \endcode + + Now the images can be successfully loaded in QML: + + \image imageprovider.png + + A complete example is available in Qt's + \l {declarative/cppextensions/imageprovider}{examples/declarative/cppextensions/imageprovider} + directory. Note the example registers the provider via a \l{QDeclarativeExtensionPlugin}{plugin} + instead of registering it in the application \c main() function as shown above. + + + \section2 Asynchronous image loading + + Image providers that support QImage loading automatically include support + for asychronous loading of images. To enable asynchronous loading for an + image source, set the \c asynchronous property to \c true for the relevant + \l Image, \l BorderImage or \l AnimatedImage object. When this is enabled, + the image request to the provider is run in a low priority thread, + allowing image loading to be executed in the background, and reducing the + performance impact on the user interface. + + Asynchronous loading is not supported for image providers that provide + QPixmap rather than QImage values, as pixmaps can only be created in the + main thread. In this case, if \l {Image::}{asynchronous} is set to + \c true, the value is ignored and the image is loaded + synchronously. + + + \section2 Image caching + + Images returned by a QDeclarativeImageProvider are automatically cached, + similar to any image loaded by the QML engine. When an image with a + "image://" prefix is loaded from cache, requestImage() and requestPixmap() + will not be called for the relevant image provider. If an image should always + be fetched from the image provider, and should not be cached at all, set the + \c cache property to \c false for the relevant \l Image, \l BorderImage or + \l AnimatedImage object. + + \sa QDeclarativeEngine::addImageProvider() +*/ + +/*! + \enum QDeclarativeImageProvider::ImageType + + Defines the type of image supported by this image provider. + + \value Image The Image Provider provides QImage images. The + requestImage() method will be called for all image requests. + \value Pixmap The Image Provider provides QPixmap images. The + requestPixmap() method will be called for all image requests. +*/ + +/*! + Creates an image provider that will provide images of the given \a type. +*/ +QDeclarativeImageProvider::QDeclarativeImageProvider(ImageType type) + : d(new QDeclarativeImageProviderPrivate) +{ + d->type = type; +} + +/*! + Destroys the QDeclarativeImageProvider + + \note The destructor of your derived class need to be thread safe. +*/ +QDeclarativeImageProvider::~QDeclarativeImageProvider() +{ + delete d; +} + +/*! + Returns the image type supported by this provider. +*/ +QDeclarativeImageProvider::ImageType QDeclarativeImageProvider::imageType() const +{ + return d->type; +} + +/*! + Implement this method to return the image with \a id. The default + implementation returns an empty image. + + The \a id is the requested image source, with the "image:" scheme and + provider identifier removed. For example, if the image \l{Image::}{source} + was "image://myprovider/icons/home", the given \a id would be "icons/home". + + The \a requestedSize corresponds to the \l {Image::sourceSize} requested by + an Image element. If \a requestedSize is a valid size, the image + returned should be of that size. + + In all cases, \a size must be set to the original size of the image. This + is used to set the \l {Item::}{width} and \l {Item::}{height} of the + relevant \l Image if these values have not been set explicitly. + + \note this method may be called by multiple threads, so ensure the + implementation of this method is reentrant. +*/ +QImage QDeclarativeImageProvider::requestImage(const QString &id, QSize *size, const QSize& requestedSize) +{ + Q_UNUSED(id); + Q_UNUSED(size); + Q_UNUSED(requestedSize); + if (d->type == Image) + qWarning("ImageProvider supports Image type but has not implemented requestImage()"); + return QImage(); +} + +/*! + Implement this method to return the pixmap with \a id. The default + implementation returns an empty pixmap. + + The \a id is the requested image source, with the "image:" scheme and + provider identifier removed. For example, if the image \l{Image::}{source} + was "image://myprovider/icons/home", the given \a id would be "icons/home". + + The \a requestedSize corresponds to the \l {Image::sourceSize} requested by + an Image element. If \a requestedSize is a valid size, the image + returned should be of that size. + + In all cases, \a size must be set to the original size of the image. This + is used to set the \l {Item::}{width} and \l {Item::}{height} of the + relevant \l Image if these values have not been set explicitly. +*/ +QPixmap QDeclarativeImageProvider::requestPixmap(const QString &id, QSize *size, const QSize& requestedSize) +{ + Q_UNUSED(id); + Q_UNUSED(size); + Q_UNUSED(requestedSize); + if (d->type == Pixmap) + qWarning("ImageProvider supports Pixmap type but has not implemented requestPixmap()"); + return QPixmap(); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativeimageprovider.h b/src/declarative/qml/qdeclarativeimageprovider.h new file mode 100644 index 00000000..c1bfba0e --- /dev/null +++ b/src/declarative/qml/qdeclarativeimageprovider.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEIMAGEPROVIDER_H +#define QDECLARATIVEIMAGEPROVIDER_H + +#include <QtGui/qimage.h> +#include <QtGui/qpixmap.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeImageProviderPrivate; + +class Q_DECLARATIVE_EXPORT QDeclarativeImageProvider +{ +public: + enum ImageType { + Image, + Pixmap + }; + + QDeclarativeImageProvider(ImageType type); + virtual ~QDeclarativeImageProvider(); + + ImageType imageType() const; + + virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize); + virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize); + +private: + QDeclarativeImageProviderPrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEIMAGEPROVIDER diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp new file mode 100644 index 00000000..a3592f93 --- /dev/null +++ b/src/declarative/qml/qdeclarativeimport.cpp @@ -0,0 +1,1083 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeimport_p.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qdir.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qpluginloader.h> +#include <QtCore/qlibraryinfo.h> +#include <QtCore/qalgorithms.h> +#include <QtDeclarative/qdeclarativeextensioninterface.h> +#include <private/qdeclarativeglobal_p.h> +#include <private/qdeclarativetypenamecache_p.h> +#include <private/qdeclarativeengine_p.h> + +#ifdef Q_OS_SYMBIAN +#include "private/qcore_symbian_p.h" +#endif + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE) +DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES) + +static bool greaterThan(const QString &s1, const QString &s2) +{ + return s1 > s2; +} + +typedef QMap<QString, QString> StringStringMap; +Q_GLOBAL_STATIC(StringStringMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri + +class QDeclarativeImportedNamespace +{ +public: + QStringList uris; + QStringList urls; + QList<int> majversions; + QList<int> minversions; + QList<bool> isLibrary; + QList<QDeclarativeDirComponents> qmlDirComponents; + + + bool find_helper(QDeclarativeTypeLoader *typeLoader, int i, const QByteArray& type, int *vmajor, int *vminor, + QDeclarativeType** type_return, QUrl* url_return, + QUrl *base = 0, bool *typeRecursionDetected = 0); + bool find(QDeclarativeTypeLoader *typeLoader, const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return, + QUrl* url_return, QUrl *base = 0, QString *errorString = 0); +}; + +class QDeclarativeImportsPrivate { +public: + QDeclarativeImportsPrivate(QDeclarativeTypeLoader *loader); + ~QDeclarativeImportsPrivate(); + + bool importExtension(const QString &absoluteFilePath, const QString &uri, + QDeclarativeImportDatabase *database, QDeclarativeDirComponents* components, + QString *errorString); + + QString resolvedUri(const QString &dir_arg, QDeclarativeImportDatabase *database); + bool add(const QDeclarativeDirComponents &qmldircomponentsnetwork, + const QString& uri_arg, const QString& prefix, + int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType, + QDeclarativeImportDatabase *database, QString *errorString); + bool find(const QByteArray& type, int *vmajor, int *vminor, + QDeclarativeType** type_return, QUrl* url_return, QString *errorString); + + QDeclarativeImportedNamespace *findNamespace(const QString& type); + + QUrl base; + int ref; + + QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded; + QDeclarativeImportedNamespace unqualifiedset; + QHash<QString,QDeclarativeImportedNamespace* > set; + QDeclarativeTypeLoader *typeLoader; +}; + +/*! +\class QDeclarativeImports +\brief The QDeclarativeImports class encapsulates one QML document's import statements. +\internal +*/ +QDeclarativeImports::QDeclarativeImports(const QDeclarativeImports ©) +: d(copy.d) +{ + ++d->ref; +} + +QDeclarativeImports & +QDeclarativeImports::operator =(const QDeclarativeImports ©) +{ + ++copy.d->ref; + if (--d->ref == 0) + delete d; + d = copy.d; + return *this; +} + +QDeclarativeImports::QDeclarativeImports() + : d(new QDeclarativeImportsPrivate(0)){ +} + +QDeclarativeImports::QDeclarativeImports(QDeclarativeTypeLoader *typeLoader) + : d(new QDeclarativeImportsPrivate(typeLoader)){ +} + +QDeclarativeImports::~QDeclarativeImports() +{ + if (--d->ref == 0) + delete d; +} + +/*! + Sets the base URL to be used for all relative file imports added. +*/ +void QDeclarativeImports::setBaseUrl(const QUrl& url) +{ + d->base = url; +} + +/*! + Returns the base URL to be used for all relative file imports added. +*/ +QUrl QDeclarativeImports::baseUrl() const +{ + return d->base; +} + +static QDeclarativeTypeNameCache * +cacheForNamespace(QDeclarativeEngine *engine, const QDeclarativeImportedNamespace &set, + QDeclarativeTypeNameCache *cache) +{ + if (!cache) + cache = new QDeclarativeTypeNameCache(engine); + + QList<QDeclarativeType *> types = QDeclarativeMetaType::qmlTypes(); + + for (int ii = 0; ii < set.uris.count(); ++ii) { + QByteArray base = set.uris.at(ii).toUtf8() + '/'; + int major = set.majversions.at(ii); + int minor = set.minversions.at(ii); + + foreach (QDeclarativeType *type, types) { + if (type->qmlTypeName().startsWith(base) && + type->qmlTypeName().lastIndexOf('/') == (base.length() - 1) && + type->availableInVersion(major,minor)) + { + QString name = QString::fromUtf8(type->qmlTypeName().mid(base.length())); + + cache->add(name, type); + } + } + } + + return cache; +} + +void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDeclarativeEngine *engine) const +{ + const QDeclarativeImportedNamespace &set = d->unqualifiedset; + + for (QHash<QString,QDeclarativeImportedNamespace* >::ConstIterator iter = d->set.begin(); + iter != d->set.end(); ++iter) { + + QDeclarativeTypeNameCache::Data *d = cache->data(iter.key()); + if (d) { + if (!d->typeNamespace) + cacheForNamespace(engine, *(*iter), d->typeNamespace); + } else { + QDeclarativeTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0); + cache->add(iter.key(), nc); + nc->release(); + } + } + + cacheForNamespace(engine, set, cache); +} + +/*! + \internal + + The given (namespace qualified) \a type is resolved to either + \list + \o a QDeclarativeImportedNamespace stored at \a ns_return, + \o a QDeclarativeType stored at \a type_return, or + \o a component located at \a url_return. + \endlist + + If any return pointer is 0, the corresponding search is not done. + + \sa addImport() +*/ +bool QDeclarativeImports::resolveType(const QByteArray& type, + QDeclarativeType** type_return, QUrl* url_return, int *vmaj, int *vmin, + QDeclarativeImportedNamespace** ns_return, QString *errorString) const +{ + QDeclarativeImportedNamespace* ns = d->findNamespace(QString::fromUtf8(type)); + if (ns) { + if (ns_return) + *ns_return = ns; + return true; + } + if (type_return || url_return) { + if (d->find(type,vmaj,vmin,type_return,url_return, errorString)) { + if (qmlImportTrace()) { + if (type_return && *type_return && url_return && !url_return->isEmpty()) + qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: " + << type << " => " << (*type_return)->typeName() << " " << *url_return; + if (type_return && *type_return) + qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: " + << type << " => " << (*type_return)->typeName(); + if (url_return && !url_return->isEmpty()) + qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: " + << type << " => " << *url_return; + } + return true; + } + } + return false; +} + +/*! + \internal + + Searching \e only in the namespace \a ns (previously returned in a call to + resolveType(), \a type is found and returned to either + a QDeclarativeType stored at \a type_return, or + a component located at \a url_return. + + If either return pointer is 0, the corresponding search is not done. +*/ +bool QDeclarativeImports::resolveType(QDeclarativeImportedNamespace* ns, const QByteArray& type, + QDeclarativeType** type_return, QUrl* url_return, + int *vmaj, int *vmin) const +{ + Q_ASSERT(d->typeLoader); + return ns->find(d->typeLoader,type,vmaj,vmin,type_return,url_return); +} + +bool QDeclarativeImportedNamespace::find_helper(QDeclarativeTypeLoader *typeLoader, int i, const QByteArray& type, int *vmajor, int *vminor, + QDeclarativeType** type_return, QUrl* url_return, + QUrl *base, bool *typeRecursionDetected) +{ + int vmaj = majversions.at(i); + int vmin = minversions.at(i); + + QByteArray qt = uris.at(i).toUtf8(); + qt += '/'; + qt += type; + + QDeclarativeType *t = QDeclarativeMetaType::qmlType(qt,vmaj,vmin); + if (t) { + if (vmajor) *vmajor = vmaj; + if (vminor) *vminor = vmin; + if (type_return) + *type_return = t; + return true; + } + + QDeclarativeDirComponents qmldircomponents = qmlDirComponents.at(i); + + bool typeWasDeclaredInQmldir = false; + if (!qmldircomponents.isEmpty()) { + const QString typeName = QString::fromUtf8(type); + foreach (const QDeclarativeDirParser::Component &c, qmldircomponents) { + if (c.typeName == typeName) { + typeWasDeclaredInQmldir = true; + + // importing version -1 means import ALL versions + if ((vmaj == -1) || (c.majorVersion < vmaj || (c.majorVersion == vmaj && vmin >= c.minorVersion))) { + QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml")); + QUrl candidate = url.resolved(QUrl(c.fileName)); + if (c.internal && base) { + if (base->resolved(QUrl(c.fileName)) != candidate) + continue; // failed attempt to access an internal type + } + if (base && *base == candidate) { + if (typeRecursionDetected) + *typeRecursionDetected = true; + continue; // no recursion + } + if (url_return) + *url_return = candidate; + return true; + } + } + } + } + + if (!typeWasDeclaredInQmldir && !isLibrary.at(i)) { + // XXX search non-files too! (eg. zip files, see QT-524) + QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml")); + QString file = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url); + if (!typeLoader->absoluteFilePath(file).isEmpty()) { + if (base && *base == url) { // no recursion + if (typeRecursionDetected) + *typeRecursionDetected = true; + } else { + if (url_return) + *url_return = url; + return true; + } + } + } + return false; +} + +QDeclarativeImportsPrivate::QDeclarativeImportsPrivate(QDeclarativeTypeLoader *loader) + : ref(1), typeLoader(loader){ +} + +QDeclarativeImportsPrivate::~QDeclarativeImportsPrivate() +{ + foreach (QDeclarativeImportedNamespace* s, set.values()) + delete s; +} + +bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath, const QString &uri, + QDeclarativeImportDatabase *database, + QDeclarativeDirComponents* components, QString *errorString) +{ + Q_ASSERT(typeLoader); + const QDeclarativeDirParser *qmldirParser = typeLoader->qmlDirParser(absoluteFilePath); + if (qmldirParser->hasError()) { + if (errorString) { + const QList<QDeclarativeError> qmldirErrors = qmldirParser->errors(uri); + for (int i = 0; i < qmldirErrors.size(); ++i) + *errorString += qmldirErrors.at(i).description(); + } + return false; + } + + if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) { + qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath); + + QDir dir = QFileInfo(absoluteFilePath).dir(); + foreach (const QDeclarativeDirParser::Plugin &plugin, qmldirParser->plugins()) { + + QString resolvedFilePath = database->resolvePlugin(dir, plugin.path, plugin.name); +#if defined(QT_LIBINFIX) && defined(Q_OS_SYMBIAN) + if (resolvedFilePath.isEmpty()) { + // In case of libinfixed build, attempt to load libinfixed version, too. + QString infixedPluginName = plugin.name + QLatin1String(QT_LIBINFIX); + resolvedFilePath = database->resolvePlugin(dir, plugin.path, infixedPluginName); + } +#endif + if (!resolvedFilePath.isEmpty()) { + if (!database->importPlugin(resolvedFilePath, uri, errorString)) { + if (errorString) + *errorString = QDeclarativeImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(*errorString); + return false; + } + } else { + if (errorString) + *errorString = QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name); + return false; + } + } + } + + if (components) + *components = qmldirParser->components(); + + return true; +} + +QString QDeclarativeImportsPrivate::resolvedUri(const QString &dir_arg, QDeclarativeImportDatabase *database) +{ + QString dir = dir_arg; + if (dir.endsWith(QLatin1Char('/')) || dir.endsWith(QLatin1Char('\\'))) + dir.chop(1); + + QStringList paths = database->fileImportPath; + qSort(paths.begin(), paths.end(), greaterThan); // Ensure subdirs preceed their parents. + + QString stableRelativePath = dir; + foreach(const QString &path, paths) { + if (dir.startsWith(path)) { + stableRelativePath = dir.mid(path.length()+1); + break; + } + } + + stableRelativePath.replace(QLatin1Char('\\'), QLatin1Char('/')); + + // remove optional versioning in dot notation from uri + int lastSlash = stableRelativePath.lastIndexOf(QLatin1Char('/')); + if (lastSlash >= 0) { + int versionDot = stableRelativePath.indexOf(QLatin1Char('.'), lastSlash); + if (versionDot >= 0) + stableRelativePath = stableRelativePath.left(versionDot); + } + + stableRelativePath.replace(QLatin1Char('/'), QLatin1Char('.')); + return stableRelativePath; +} + +bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomponentsnetwork, + const QString& uri_arg, const QString& prefix, int vmaj, int vmin, + QDeclarativeScriptParser::Import::Type importType, + QDeclarativeImportDatabase *database, QString *errorString) +{ + Q_ASSERT(typeLoader); + QDeclarativeDirComponents qmldircomponents = qmldircomponentsnetwork; + QString uri = uri_arg; + QDeclarativeImportedNamespace *s; + if (prefix.isEmpty()) { + s = &unqualifiedset; + } else { + s = set.value(prefix); + if (!s) + set.insert(prefix,(s=new QDeclarativeImportedNamespace)); + } + + QString url = uri; + bool versionFound = false; + if (importType == QDeclarativeScriptParser::Import::Library) { + url.replace(QLatin1Char('.'), QLatin1Char('/')); + bool found = false; + QString dir; + QString qmldir; + + // step 1: search for extension with fully encoded version number + if (vmaj >= 0 && vmin >= 0) { + foreach (const QString &p, database->fileImportPath) { + dir = p+QLatin1Char('/')+url; + qmldir = dir+QString(QLatin1String(".%1.%2")).arg(vmaj).arg(vmin)+QLatin1String("/qmldir"); + + QString absoluteFilePath = typeLoader->absoluteFilePath(qmldir); + if (!absoluteFilePath.isEmpty()) { + found = true; + + QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(QLatin1Char('/'))); + url = QUrl::fromLocalFile(absolutePath).toString(); + uri = resolvedUri(dir, database); + if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString)) + return false; + break; + } + } + } + // step 2: search for extension with encoded version major + if (vmaj >= 0 && vmin >= 0) { + foreach (const QString &p, database->fileImportPath) { + dir = p+QLatin1Char('/')+url; + qmldir = dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir"); + + QString absoluteFilePath = typeLoader->absoluteFilePath(qmldir); + if (!absoluteFilePath.isEmpty()) { + found = true; + + QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(QLatin1Char('/'))); + url = QUrl::fromLocalFile(absolutePath).toString(); + uri = resolvedUri(dir, database); + if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString)) + return false; + break; + } + } + } + if (!found) { + // step 3: search for extension without version number + + foreach (const QString &p, database->fileImportPath) { + dir = p+QLatin1Char('/')+url; + qmldir = dir+QLatin1String("/qmldir"); + + QString absoluteFilePath = typeLoader->absoluteFilePath(qmldir); + if (!absoluteFilePath.isEmpty()) { + found = true; + + QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(QLatin1Char('/'))); + url = QUrl::fromLocalFile(absolutePath).toString(); + uri = resolvedUri(dir, database); + if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString)) + return false; + break; + } + } + } + + if (QDeclarativeMetaType::isModule(uri.toUtf8(), vmaj, vmin)) + versionFound = true; + + if (!versionFound && qmldircomponents.isEmpty()) { + if (errorString) { + bool anyversion = QDeclarativeMetaType::isModule(uri.toUtf8(), -1, -1); + if (anyversion) + *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin); + else + *errorString = QDeclarativeImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg); + } + return false; + } + } else { + + if (importType == QDeclarativeScriptParser::Import::File && qmldircomponents.isEmpty()) { + QUrl importUrl = base.resolved(QUrl(uri + QLatin1String("/qmldir"))); + QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl); + if (!localFileOrQrc.isEmpty()) { + QString dir = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri))); + QFileInfo dirinfo(dir); + if (dir.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) { + if (errorString) + *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri_arg); + return false; // local import dirs must exist + } + uri = resolvedUri(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri))), database); + if (uri.endsWith(QLatin1Char('/'))) + uri.chop(1); + if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) { + if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,errorString)) + return false; + } + } else { + if (prefix.isEmpty()) { + // directory must at least exist for valid import + QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri))); + QFileInfo dirinfo(localFileOrQrc); + if (localFileOrQrc.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) { + if (errorString) { + if (localFileOrQrc.isEmpty()) + *errorString = QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri); + else + *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri); + } + return false; + } + } + } + } + + url = base.resolved(QUrl(url)).toString(); + if (url.endsWith(QLatin1Char('/'))) + url.chop(1); + } + + if (!versionFound && vmaj > -1 && vmin > -1 && !qmldircomponents.isEmpty()) { + QList<QDeclarativeDirParser::Component>::ConstIterator it = qmldircomponents.begin(); + int lowest_maj = INT_MAX; + int lowest_min = INT_MAX; + int highest_maj = INT_MIN; + int highest_min = INT_MIN; + for (; it != qmldircomponents.end(); ++it) { + if (it->majorVersion > highest_maj || (it->majorVersion == highest_maj && it->minorVersion > highest_min)) { + highest_maj = it->majorVersion; + highest_min = it->minorVersion; + } + if (it->majorVersion < lowest_maj || (it->majorVersion == lowest_maj && it->minorVersion < lowest_min)) { + lowest_maj = it->majorVersion; + lowest_min = it->minorVersion; + } + } + if (lowest_maj > vmaj || (lowest_maj == vmaj && lowest_min > vmin) + || highest_maj < vmaj || (highest_maj == vmaj && highest_min < vmin)) + { + *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin); + return false; + } + } + + s->uris.prepend(uri); + s->urls.prepend(url); + s->majversions.prepend(vmaj); + s->minversions.prepend(vmin); + s->isLibrary.prepend(importType == QDeclarativeScriptParser::Import::Library); + s->qmlDirComponents.prepend(qmldircomponents); + return true; +} + +bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return, + QUrl* url_return, QString *errorString) +{ + Q_ASSERT(typeLoader); + QDeclarativeImportedNamespace *s = 0; + int slash = type.indexOf('/'); + if (slash >= 0) { + QString namespaceName = QString::fromUtf8(type.left(slash)); + s = set.value(namespaceName); + if (!s) { + if (errorString) + *errorString = QDeclarativeImportDatabase::tr("- %1 is not a namespace").arg(namespaceName); + return false; + } + int nslash = type.indexOf('/',slash+1); + if (nslash > 0) { + if (errorString) + *errorString = QDeclarativeImportDatabase::tr("- nested namespaces not allowed"); + return false; + } + } else { + s = &unqualifiedset; + } + QByteArray unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower) + if (s) { + if (s->find(typeLoader, unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errorString)) + return true; + if (s->urls.count() == 1 && !s->isLibrary[0] && url_return && s != &unqualifiedset) { + // qualified, and only 1 url + *url_return = QUrl(s->urls[0]+QLatin1Char('/')).resolved(QUrl(QString::fromUtf8(unqualifiedtype) + QLatin1String(".qml"))); + return true; + } + } + + return false; +} + +QDeclarativeImportedNamespace *QDeclarativeImportsPrivate::findNamespace(const QString& type) +{ + return set.value(type); +} + +bool QDeclarativeImportedNamespace::find(QDeclarativeTypeLoader *typeLoader, const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return, + QUrl* url_return, QUrl *base, QString *errorString) +{ + bool typeRecursionDetected = false; + for (int i=0; i<urls.count(); ++i) { + if (find_helper(typeLoader, i, type, vmajor, vminor, type_return, url_return, base, &typeRecursionDetected)) { + if (qmlCheckTypes()) { + // check for type clashes + for (int j = i+1; j<urls.count(); ++j) { + if (find_helper(typeLoader, j, type, vmajor, vminor, 0, 0, base)) { + if (errorString) { + QString u1 = urls.at(i); + QString u2 = urls.at(j); + if (base) { + QString b = base->toString(); + int slash = b.lastIndexOf(QLatin1Char('/')); + if (slash >= 0) { + b = b.left(slash+1); + QString l = b.left(slash); + if (u1.startsWith(b)) + u1 = u1.mid(b.count()); + else if (u1 == l) + u1 = QDeclarativeImportDatabase::tr("local directory"); + if (u2.startsWith(b)) + u2 = u2.mid(b.count()); + else if (u2 == l) + u2 = QDeclarativeImportDatabase::tr("local directory"); + } + } + + if (u1 != u2) + *errorString + = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 and in %2") + .arg(u1).arg(u2); + else + *errorString + = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5") + .arg(u1) + .arg(majversions.at(i)).arg(minversions.at(i)) + .arg(majversions.at(j)).arg(minversions.at(j)); + } + return false; + } + } + } + return true; + } + } + if (errorString) { + if (typeRecursionDetected) + *errorString = QDeclarativeImportDatabase::tr("is instantiated recursively"); + else + *errorString = QDeclarativeImportDatabase::tr("is not a type"); + } + return false; +} + +/*! +\class QDeclarativeImportDatabase +\brief The QDeclarativeImportDatabase class manages the QML imports for a QDeclarativeEngine. +\internal +*/ +QDeclarativeImportDatabase::QDeclarativeImportDatabase(QDeclarativeEngine *e) +: engine(e) +{ + filePluginPath << QLatin1String("."); + + // Search order is applicationDirPath(), $QML_IMPORT_PATH, QLibraryInfo::ImportsPath + +#ifndef QT_NO_SETTINGS + QString installImportsPath = QLibraryInfo::location(QLibraryInfo::ImportsPath); + +#if defined(Q_OS_SYMBIAN) + // Append imports path for all available drives in Symbian + if (installImportsPath.at(1) != QChar(QLatin1Char(':'))) { + QString tempPath = installImportsPath; + if (tempPath.at(tempPath.length() - 1) != QDir::separator()) { + tempPath += QDir::separator(); + } + RFs& fs = qt_s60GetRFs(); + TPtrC tempPathPtr(reinterpret_cast<const TText*> (tempPath.constData())); + // Symbian searches should start from Y:. Fix start drive otherwise TFindFile starts from the session drive + _LIT(KStartDir, "Y:"); + TFileName dirPath(KStartDir); + dirPath.Append(tempPathPtr); + TFindFile finder(fs); + TInt err = finder.FindByDir(tempPathPtr, dirPath); + while (err == KErrNone) { + QString foundDir(reinterpret_cast<const QChar *>(finder.File().Ptr()), + finder.File().Length()); + foundDir = QDir(foundDir).canonicalPath(); + addImportPath(foundDir); + err = finder.Find(); + } + // TFindFile found the directories in the order we want, but addImportPath reverses it. + // Reverse the order again to get it right. + QAlgorithmsPrivate::qReverse(fileImportPath.begin(), fileImportPath.end()); + } else { + addImportPath(installImportsPath); + } +#else + addImportPath(installImportsPath); +#endif + +#endif // QT_NO_SETTINGS + + // env import paths + QByteArray envImportPath = qgetenv("QML_IMPORT_PATH"); + if (!envImportPath.isEmpty()) { +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + QLatin1Char pathSep(';'); +#else + QLatin1Char pathSep(':'); +#endif + QStringList paths = QString::fromLatin1(envImportPath).split(pathSep, QString::SkipEmptyParts); + for (int ii = paths.count() - 1; ii >= 0; --ii) + addImportPath(paths.at(ii)); + } + + addImportPath(QCoreApplication::applicationDirPath()); +} + +QDeclarativeImportDatabase::~QDeclarativeImportDatabase() +{ +} + +/*! + \internal + + Adds information to \a imports such that subsequent calls to resolveType() + will resolve types qualified by \a prefix by considering types found at the given \a uri. + + The uri is either a directory (if importType is FileImport), or a URI resolved using paths + added via addImportPath() (if importType is LibraryImport). + + The \a prefix may be empty, in which case the import location is considered for + unqualified types. + + The base URL must already have been set with Import::setBaseUrl(). +*/ +bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb, + const QString& uri, const QString& prefix, int vmaj, int vmin, + QDeclarativeScriptParser::Import::Type importType, + const QDeclarativeDirComponents &qmldircomponentsnetwork, + QString *errorString) +{ + if (qmlImportTrace()) + qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::addImport: " + << uri << " " << vmaj << '.' << vmin << " " + << (importType==QDeclarativeScriptParser::Import::Library? "Library" : "File") + << " as " << prefix; + + return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errorString); +} + +/*! + \internal + + Returns the result of the merge of \a baseName with \a path, \a suffixes, and \a prefix. + The \a prefix must contain the dot. + + \a qmldirPath is the location of the qmldir file. + */ +QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, + const QString &baseName, const QStringList &suffixes, + const QString &prefix) +{ + QStringList searchPaths = filePluginPath; + bool qmldirPluginPathIsRelative = QDir::isRelativePath(qmldirPluginPath); + if (!qmldirPluginPathIsRelative) + searchPaths.prepend(qmldirPluginPath); + + foreach (const QString &pluginPath, searchPaths) { + + QString resolvedPath; + + if (pluginPath == QLatin1String(".")) { + if (qmldirPluginPathIsRelative) + resolvedPath = qmldirPath.absoluteFilePath(qmldirPluginPath); + else + resolvedPath = qmldirPath.absolutePath(); + } else { + resolvedPath = pluginPath; + } + + // hack for resources, should probably go away + if (resolvedPath.startsWith(QLatin1Char(':'))) + resolvedPath = QCoreApplication::applicationDirPath(); + + QDir dir(resolvedPath); + foreach (const QString &suffix, suffixes) { + QString pluginFileName = prefix; + + pluginFileName += baseName; + pluginFileName += suffix; + + QFileInfo fileInfo(dir, pluginFileName); + + if (fileInfo.exists()) + return fileInfo.absoluteFilePath(); + } + } + + if (qmlImportTrace()) + qDebug() << "QDeclarativeImportDatabase::resolvePlugin: Could not resolve plugin" << baseName + << "in" << qmldirPath.absolutePath(); + + return QString(); +} + +/*! + \internal + + Returns the result of the merge of \a baseName with \a dir and the platform suffix. + + \table + \header \i Platform \i Valid suffixes + \row \i Windows \i \c .dll + \row \i Unix/Linux \i \c .so + \row \i AIX \i \c .a + \row \i HP-UX \i \c .sl, \c .so (HP-UXi) + \row \i Mac OS X \i \c .dylib, \c .bundle, \c .so + \row \i Symbian \i \c .dll + \endtable + + Version number on unix are ignored. +*/ +QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, + const QString &baseName) +{ +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) + return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, + QStringList() +# ifdef QT_DEBUG + << QLatin1String("d.dll") // try a qmake-style debug build first +# endif + << QLatin1String(".dll")); +#elif defined(Q_OS_SYMBIAN) + return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, + QStringList() + << QLatin1String(".dll") + << QLatin1String(".qtplugin")); +#else + +# if defined(Q_OS_DARWIN) + + return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, + QStringList() +# ifdef QT_DEBUG + << QLatin1String("_debug.dylib") // try a qmake-style debug build first + << QLatin1String(".dylib") +# else + << QLatin1String(".dylib") + << QLatin1String("_debug.dylib") // try a qmake-style debug build after +# endif + << QLatin1String(".so") + << QLatin1String(".bundle"), + QLatin1String("lib")); +# else // Generic Unix + QStringList validSuffixList; + +# if defined(Q_OS_HPUX) +/* + See "HP-UX Linker and Libraries User's Guide", section "Link-time Differences between PA-RISC and IPF": + "In PA-RISC (PA-32 and PA-64) shared libraries are suffixed with .sl. In IPF (32-bit and 64-bit), + the shared libraries are suffixed with .so. For compatibility, the IPF linker also supports the .sl suffix." + */ + validSuffixList << QLatin1String(".sl"); +# if defined __ia64 + validSuffixList << QLatin1String(".so"); +# endif +# elif defined(Q_OS_AIX) + validSuffixList << QLatin1String(".a") << QLatin1String(".so"); +# elif defined(Q_OS_UNIX) + validSuffixList << QLatin1String(".so"); +# endif + + // Examples of valid library names: + // libfoo.so + + return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, validSuffixList, QLatin1String("lib")); +# endif + +#endif +} + +/*! + \internal +*/ +QStringList QDeclarativeImportDatabase::pluginPathList() const +{ + return filePluginPath; +} + +/*! + \internal +*/ +void QDeclarativeImportDatabase::setPluginPathList(const QStringList &paths) +{ + filePluginPath = paths; +} + +/*! + \internal +*/ +void QDeclarativeImportDatabase::addPluginPath(const QString& path) +{ + if (qmlImportTrace()) + qDebug().nospace() << "QDeclarativeImportDatabase::addPluginPath: " << path; + + QUrl url = QUrl(path); + if (url.isRelative() || url.scheme() == QLatin1String("file") + || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path + QDir dir = QDir(path); + filePluginPath.prepend(dir.canonicalPath()); + } else { + filePluginPath.prepend(path); + } +} + +/*! + \internal +*/ +void QDeclarativeImportDatabase::addImportPath(const QString& path) +{ + if (qmlImportTrace()) + qDebug().nospace() << "QDeclarativeImportDatabase::addImportPath: " << path; + + if (path.isEmpty()) + return; + + QUrl url = QUrl(path); + QString cPath; + + if (url.isRelative() || url.scheme() == QLatin1String("file") + || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path + QDir dir = QDir(path); + cPath = dir.canonicalPath(); + } else { + cPath = path; + cPath.replace(QLatin1Char('\\'), QLatin1Char('/')); + } + + if (!cPath.isEmpty() + && !fileImportPath.contains(cPath)) + fileImportPath.prepend(cPath); +} + +/*! + \internal +*/ +QStringList QDeclarativeImportDatabase::importPathList() const +{ + return fileImportPath; +} + +/*! + \internal +*/ +void QDeclarativeImportDatabase::setImportPathList(const QStringList &paths) +{ + fileImportPath = paths; +} + +/*! + \internal +*/ +bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QString &uri, QString *errorString) +{ + if (qmlImportTrace()) + qDebug().nospace() << "QDeclarativeImportDatabase::importPlugin: " << uri << " from " << filePath; + +#ifndef QT_NO_LIBRARY + QFileInfo fileInfo(filePath); + const QString absoluteFilePath = fileInfo.absoluteFilePath(); + + bool engineInitialized = initializedPlugins.contains(absoluteFilePath); + bool typesRegistered = qmlEnginePluginsWithRegisteredTypes()->contains(absoluteFilePath); + + if (typesRegistered) { + Q_ASSERT_X(qmlEnginePluginsWithRegisteredTypes()->value(absoluteFilePath) == uri, + "QDeclarativeImportDatabase::importExtension", + "Internal error: Plugin imported previously with different uri"); + } + + if (!engineInitialized || !typesRegistered) { + if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) { + if (errorString) + *errorString = tr("File name case mismatch for \"%1\"").arg(absoluteFilePath); + return false; + } + QPluginLoader loader(absoluteFilePath); + + if (!loader.load()) { + if (errorString) + *errorString = loader.errorString(); + return false; + } + + if (QDeclarativeExtensionInterface *iface = qobject_cast<QDeclarativeExtensionInterface *>(loader.instance())) { + + const QByteArray bytes = uri.toUtf8(); + const char *moduleId = bytes.constData(); + if (!typesRegistered) { + + // ### this code should probably be protected with a mutex. + qmlEnginePluginsWithRegisteredTypes()->insert(absoluteFilePath, uri); + iface->registerTypes(moduleId); + } + if (!engineInitialized) { + // things on the engine (eg. adding new global objects) have to be done for every engine. + + // protect against double initialization + initializedPlugins.insert(absoluteFilePath); + iface->initializeEngine(engine, moduleId); + } + } else { + if (errorString) + *errorString = loader.errorString(); + return false; + } + } + + return true; +#else + return false; +#endif +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeimport_p.h b/src/declarative/qml/qdeclarativeimport_p.h new file mode 100644 index 00000000..33061d6a --- /dev/null +++ b/src/declarative/qml/qdeclarativeimport_p.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEIMPORT_P_H +#define QDECLARATIVEIMPORT_P_H + +#include <QtCore/qurl.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qset.h> +#include <private/qdeclarativedirparser_p.h> +#include <private/qdeclarativescriptparser_p.h> +#include <private/qdeclarativemetatype_p.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QDeclarativeTypeNameCache; +class QDeclarativeEngine; +class QDir; +class QDeclarativeImportedNamespace; +class QDeclarativeImportsPrivate; +class QDeclarativeImportDatabase; +class QDeclarativeTypeLoader; + +class QDeclarativeImports +{ +public: + QDeclarativeImports(); + QDeclarativeImports(QDeclarativeTypeLoader *); + QDeclarativeImports(const QDeclarativeImports &); + ~QDeclarativeImports(); + QDeclarativeImports &operator=(const QDeclarativeImports &); + + void setBaseUrl(const QUrl &url); + QUrl baseUrl() const; + + bool resolveType(const QByteArray& type, + QDeclarativeType** type_return, QUrl* url_return, + int *version_major, int *version_minor, + QDeclarativeImportedNamespace** ns_return, + QString *errorString = 0) const; + bool resolveType(QDeclarativeImportedNamespace*, + const QByteArray& type, + QDeclarativeType** type_return, QUrl* url_return, + int *version_major, int *version_minor) const; + + bool addImport(QDeclarativeImportDatabase *, + const QString& uri, const QString& prefix, int vmaj, int vmin, + QDeclarativeScriptParser::Import::Type importType, + const QDeclarativeDirComponents &qmldircomponentsnetwork, + QString *errorString); + + void populateCache(QDeclarativeTypeNameCache *cache, QDeclarativeEngine *) const; + +private: + friend class QDeclarativeImportDatabase; + QDeclarativeImportsPrivate *d; +}; + +class QDeclarativeImportDatabase +{ + Q_DECLARE_TR_FUNCTIONS(QDeclarativeImportDatabase) +public: + QDeclarativeImportDatabase(QDeclarativeEngine *); + ~QDeclarativeImportDatabase(); + + bool importPlugin(const QString &filePath, const QString &uri, QString *errorString); + + QStringList importPathList() const; + void setImportPathList(const QStringList &paths); + void addImportPath(const QString& dir); + + QStringList pluginPathList() const; + void setPluginPathList(const QStringList &paths); + void addPluginPath(const QString& path); + +private: + friend class QDeclarativeImportsPrivate; + QString resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, + const QString &baseName, const QStringList &suffixes, + const QString &prefix = QString()); + QString resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, + const QString &baseName); + + + QStringList filePluginPath; + QStringList fileImportPath; + + QSet<QString> initializedPlugins; + QDeclarativeEngine *engine; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEIMPORT_P_H + diff --git a/src/declarative/qml/qdeclarativeinclude.cpp b/src/declarative/qml/qdeclarativeinclude.cpp new file mode 100644 index 00000000..d02143bc --- /dev/null +++ b/src/declarative/qml/qdeclarativeinclude.cpp @@ -0,0 +1,310 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeinclude_p.h" + +#include <QtScript/qscriptengine.h> +#include <QtNetwork/qnetworkrequest.h> +#include <QtNetwork/qnetworkreply.h> +#include <QtCore/qfile.h> + +#include <private/qdeclarativeengine_p.h> +#include <private/qdeclarativeglobalscriptclass_p.h> + +QT_BEGIN_NAMESPACE + +QDeclarativeInclude::QDeclarativeInclude(const QUrl &url, + QDeclarativeEngine *engine, + QScriptContext *ctxt) +: QObject(engine), m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0) +{ + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + m_context = ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3)); + + m_scope[0] = QScriptDeclarativeClass::scopeChainValue(ctxt, -4); + m_scope[1] = QScriptDeclarativeClass::scopeChainValue(ctxt, -5); + + m_scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + m_network = QDeclarativeScriptEngine::get(m_scriptEngine)->networkAccessManager(); + + m_result = resultValue(m_scriptEngine); + + QNetworkRequest request; + request.setUrl(url); + + m_reply = m_network->get(request); + QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished())); +} + +QDeclarativeInclude::~QDeclarativeInclude() +{ + delete m_reply; +} + +QScriptValue QDeclarativeInclude::resultValue(QScriptEngine *engine, Status status) +{ + QScriptValue result = engine->newObject(); + result.setProperty(QLatin1String("OK"), QScriptValue(engine, Ok)); + result.setProperty(QLatin1String("LOADING"), QScriptValue(engine, Loading)); + result.setProperty(QLatin1String("NETWORK_ERROR"), QScriptValue(engine, NetworkError)); + result.setProperty(QLatin1String("EXCEPTION"), QScriptValue(engine, Exception)); + + result.setProperty(QLatin1String("status"), QScriptValue(engine, status)); + return result; +} + +QScriptValue QDeclarativeInclude::result() const +{ + return m_result; +} + +void QDeclarativeInclude::setCallback(const QScriptValue &c) +{ + m_callback = c; +} + +QScriptValue QDeclarativeInclude::callback() const +{ + return m_callback; +} + +#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15 +void QDeclarativeInclude::finished() +{ + m_redirectCount++; + + if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) { + QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (redirect.isValid()) { + m_url = m_url.resolved(redirect.toUrl()); + delete m_reply; + + QNetworkRequest request; + request.setUrl(m_url); + + m_reply = m_network->get(request); + QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished())); + return; + } + } + + if (m_reply->error() == QNetworkReply::NoError) { + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine); + + QByteArray data = m_reply->readAll(); + + QString code = QString::fromUtf8(data); + + QString urlString = m_url.toString(); + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(m_scriptEngine); + scriptContext->pushScope(ep->contextClass->newUrlContext(m_context, 0, urlString)); + scriptContext->pushScope(m_scope[0]); + + scriptContext->pushScope(m_scope[1]); + scriptContext->setActivationObject(m_scope[1]); + QDeclarativeScriptParser::extractPragmas(code); + + m_scriptEngine->evaluate(code, urlString, 1); + + m_scriptEngine->popContext(); + + if (m_scriptEngine->hasUncaughtException()) { + m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, Exception)); + m_result.setProperty(QLatin1String("exception"), m_scriptEngine->uncaughtException()); + m_scriptEngine->clearExceptions(); + } else { + m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, Ok)); + } + } else { + m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, NetworkError)); + } + + callback(m_scriptEngine, m_callback, m_result); + + disconnect(); + deleteLater(); +} + +void QDeclarativeInclude::callback(QScriptEngine *engine, QScriptValue &callback, QScriptValue &status) +{ + if (callback.isValid()) { + QScriptValue args = engine->newArray(1); + args.setProperty(0, status); + callback.call(QScriptValue(), args); + } +} + +/* + Documented in qdeclarativeengine.cpp +*/ +QScriptValue QDeclarativeInclude::include(QScriptContext *ctxt, QScriptEngine *engine) +{ + if (ctxt->argumentCount() == 0) + return engine->undefinedValue(); + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + + QUrl contextUrl = ep->contextClass->urlFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3)); + if (contextUrl.isEmpty()) + return ctxt->throwError(QLatin1String("Qt.include(): Can only be called from JavaScript files")); + + QString urlString = ctxt->argument(0).toString(); + QUrl url(urlString); + if (url.isRelative()) { + url = QUrl(contextUrl).resolved(url); + urlString = url.toString(); + } + + QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url); + + QScriptValue func = ctxt->argument(1); + if (!func.isFunction()) + func = QScriptValue(); + + QScriptValue result; + if (localFile.isEmpty()) { + QDeclarativeInclude *i = + new QDeclarativeInclude(url, QDeclarativeEnginePrivate::getEngine(engine), ctxt); + + if (func.isValid()) + i->setCallback(func); + + result = i->result(); + } else { + + QFile f(localFile); + if (f.open(QIODevice::ReadOnly)) { + QByteArray data = f.readAll(); + QString code = QString::fromUtf8(data); + + QDeclarativeContextData *context = + ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3)); + + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine); + scriptContext->pushScope(ep->contextClass->newUrlContext(context, 0, urlString)); + scriptContext->pushScope(ep->globalClass->staticGlobalObject()); + QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -5); + scriptContext->pushScope(scope); + scriptContext->setActivationObject(scope); + QDeclarativeScriptParser::extractPragmas(code); + + engine->evaluate(code, urlString, 1); + + engine->popContext(); + + if (engine->hasUncaughtException()) { + result = resultValue(engine, Exception); + result.setProperty(QLatin1String("exception"), engine->uncaughtException()); + engine->clearExceptions(); + } else { + result = resultValue(engine, Ok); + } + callback(engine, func, result); + } else { + result = resultValue(engine, NetworkError); + callback(engine, func, result); + } + } + + return result; +} + +QScriptValue QDeclarativeInclude::worker_include(QScriptContext *ctxt, QScriptEngine *engine) +{ + if (ctxt->argumentCount() == 0) + return engine->undefinedValue(); + + QString urlString = ctxt->argument(0).toString(); + QUrl url(ctxt->argument(0).toString()); + if (url.isRelative()) { + QString contextUrl = QScriptDeclarativeClass::scopeChainValue(ctxt, -3).data().toString(); + Q_ASSERT(!contextUrl.isEmpty()); + + url = QUrl(contextUrl).resolved(url); + urlString = url.toString(); + } + + QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url); + + QScriptValue func = ctxt->argument(1); + if (!func.isFunction()) + func = QScriptValue(); + + QScriptValue result; + if (!localFile.isEmpty()) { + + QFile f(localFile); + if (f.open(QIODevice::ReadOnly)) { + QByteArray data = f.readAll(); + QString code = QString::fromUtf8(data); + + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine); + QScriptValue urlContext = engine->newObject(); + urlContext.setData(QScriptValue(engine, urlString)); + scriptContext->pushScope(urlContext); + + QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -4); + scriptContext->pushScope(scope); + scriptContext->setActivationObject(scope); + QDeclarativeScriptParser::extractPragmas(code); + + engine->evaluate(code, urlString, 1); + + engine->popContext(); + + if (engine->hasUncaughtException()) { + result = resultValue(engine, Exception); + result.setProperty(QLatin1String("exception"), engine->uncaughtException()); + engine->clearExceptions(); + } else { + result = resultValue(engine, Ok); + } + callback(engine, func, result); + } else { + result = resultValue(engine, NetworkError); + callback(engine, func, result); + } + } + + return result; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeinclude_p.h b/src/declarative/qml/qdeclarativeinclude_p.h new file mode 100644 index 00000000..d92a9dda --- /dev/null +++ b/src/declarative/qml/qdeclarativeinclude_p.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEINCLUDE_P_H +#define QDECLARATIVEINCLUDE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include <QtScript/qscriptvalue.h> + +#include <private/qdeclarativecontext_p.h> +#include <private/qdeclarativeguard_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeEngine; +class QScriptContext; +class QScriptEngine; +class QNetworkAccessManager; +class QNetworkReply; +class QDeclarativeInclude : public QObject +{ + Q_OBJECT +public: + enum Status { + Ok = 0, + Loading = 1, + NetworkError = 2, + Exception = 3 + }; + + QDeclarativeInclude(const QUrl &, QDeclarativeEngine *, QScriptContext *ctxt); + ~QDeclarativeInclude(); + + void setCallback(const QScriptValue &); + QScriptValue callback() const; + + QScriptValue result() const; + + static QScriptValue resultValue(QScriptEngine *, Status status = Loading); + static void callback(QScriptEngine *, QScriptValue &callback, QScriptValue &status); + + static QScriptValue include(QScriptContext *ctxt, QScriptEngine *engine); + static QScriptValue worker_include(QScriptContext *ctxt, QScriptEngine *engine); + +public slots: + void finished(); + +private: + QDeclarativeEngine *m_engine; + QScriptEngine *m_scriptEngine; + QNetworkAccessManager *m_network; + QDeclarativeGuard<QNetworkReply> m_reply; + + QUrl m_url; + int m_redirectCount; + QScriptValue m_callback; + QScriptValue m_result; + QDeclarativeGuardedContextData m_context; + QScriptValue m_scope[2]; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEINCLUDE_P_H + diff --git a/src/declarative/qml/qdeclarativeinfo.cpp b/src/declarative/qml/qdeclarativeinfo.cpp new file mode 100644 index 00000000..52268b79 --- /dev/null +++ b/src/declarative/qml/qdeclarativeinfo.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeinfo.h" + +#include "private/qdeclarativedata_p.h" +#include "qdeclarativecontext.h" +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativemetatype_p.h" +#include "private/qdeclarativeengine_p.h" + +#include <QCoreApplication> + +QT_BEGIN_NAMESPACE + +/*! + \fn QDeclarativeInfo qmlInfo(const QObject *object) + \relates QDeclarativeEngine + + Prints warning messages that include the file and line number for the + specified QML \a object. + + When QML types display warning messages, it improves traceability + if they include the QML file and line number on which the + particular instance was instantiated. + + To include the file and line number, an object must be passed. If + the file and line number is not available for that instance + (either it was not instantiated by the QML engine or location + information is disabled), "unknown location" will be used instead. + + For example, + + \code + qmlInfo(object) << tr("component property is a write-once property"); + \endcode + + prints + + \code + QML MyCustomType (unknown location): component property is a write-once property + \endcode +*/ + +class QDeclarativeInfoPrivate +{ +public: + QDeclarativeInfoPrivate() : ref (1), object(0) {} + + int ref; + const QObject *object; + QString buffer; + QList<QDeclarativeError> errors; +}; + +QDeclarativeInfo::QDeclarativeInfo(QDeclarativeInfoPrivate *p) +: QDebug(&p->buffer), d(p) +{ + nospace(); +} + +QDeclarativeInfo::QDeclarativeInfo(const QDeclarativeInfo &other) +: QDebug(other), d(other.d) +{ + d->ref++; +} + +QDeclarativeInfo::~QDeclarativeInfo() +{ + if (0 == --d->ref) { + QList<QDeclarativeError> errors = d->errors; + + QDeclarativeEngine *engine = 0; + + if (!d->buffer.isEmpty()) { + QDeclarativeError error; + + QObject *object = const_cast<QObject *>(d->object); + + if (object) { + engine = qmlEngine(d->object); + QString typeName; + QDeclarativeType *type = QDeclarativeMetaType::qmlType(object->metaObject()); + if (type) { + typeName = QLatin1String(type->qmlTypeName()); + int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); + if (lastSlash != -1) + typeName = typeName.mid(lastSlash+1); + } else { + typeName = QString::fromUtf8(object->metaObject()->className()); + int marker = typeName.indexOf(QLatin1String("_QMLTYPE_")); + if (marker != -1) + typeName = typeName.left(marker); + } + + d->buffer.prepend(QLatin1String("QML ") + typeName + QLatin1String(": ")); + + QDeclarativeData *ddata = QDeclarativeData::get(object, false); + if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) { + error.setUrl(ddata->outerContext->url); + error.setLine(ddata->lineNumber); + error.setColumn(ddata->columnNumber); + } + } + + error.setDescription(d->buffer); + + errors.prepend(error); + } + + QDeclarativeEnginePrivate::warning(engine, errors); + + delete d; + } +} + +QDeclarativeInfo qmlInfo(const QObject *me) +{ + QDeclarativeInfoPrivate *d = new QDeclarativeInfoPrivate; + d->object = me; + return QDeclarativeInfo(d); +} + +QDeclarativeInfo qmlInfo(const QObject *me, const QDeclarativeError &error) +{ + QDeclarativeInfoPrivate *d = new QDeclarativeInfoPrivate; + d->object = me; + d->errors << error; + return QDeclarativeInfo(d); +} + +QDeclarativeInfo qmlInfo(const QObject *me, const QList<QDeclarativeError> &errors) +{ + QDeclarativeInfoPrivate *d = new QDeclarativeInfoPrivate; + d->object = me; + d->errors = errors; + return QDeclarativeInfo(d); +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeinfo.h b/src/declarative/qml/qdeclarativeinfo.h new file mode 100644 index 00000000..e97d8412 --- /dev/null +++ b/src/declarative/qml/qdeclarativeinfo.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEINFO_H +#define QDECLARATIVEINFO_H + +#include <QtCore/qdebug.h> +#include <QtCore/qurl.h> +#include <QtDeclarative/qdeclarativeerror.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeInfoPrivate; +class Q_DECLARATIVE_EXPORT QDeclarativeInfo : public QDebug +{ +public: + QDeclarativeInfo(const QDeclarativeInfo &); + ~QDeclarativeInfo(); + + inline QDeclarativeInfo &operator<<(QChar t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(QBool t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(bool t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(char t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(signed short t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(unsigned short t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(signed int t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(unsigned int t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(signed long t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(unsigned long t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(qint64 t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(quint64 t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(float t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(double t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(const char* t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(const QString & t) { QDebug::operator<<(t.toLocal8Bit().constData()); return *this; } + inline QDeclarativeInfo &operator<<(const QStringRef & t) { return operator<<(t.toString()); } + inline QDeclarativeInfo &operator<<(const QLatin1String &t) { QDebug::operator<<(t.latin1()); return *this; } + inline QDeclarativeInfo &operator<<(const QByteArray & t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(const void * t) { QDebug::operator<<(t); return *this; } + inline QDeclarativeInfo &operator<<(QTextStreamFunction f) { QDebug::operator<<(f); return *this; } + inline QDeclarativeInfo &operator<<(QTextStreamManipulator m) { QDebug::operator<<(m); return *this; } +#ifndef QT_NO_DEBUG_STREAM + inline QDeclarativeInfo &operator<<(const QUrl &t) { static_cast<QDebug &>(*this) << t; return *this; } +#endif + +private: + friend Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me); + friend Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me, const QDeclarativeError &error); + friend Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me, const QList<QDeclarativeError> &errors); + + QDeclarativeInfo(QDeclarativeInfoPrivate *); + QDeclarativeInfoPrivate *d; +}; + +Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me); +Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me, const QDeclarativeError &error); +Q_DECLARATIVE_EXPORT QDeclarativeInfo qmlInfo(const QObject *me, const QList<QDeclarativeError> &errors); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEINFO_H diff --git a/src/declarative/qml/qdeclarativeinstruction.cpp b/src/declarative/qml/qdeclarativeinstruction.cpp new file mode 100644 index 00000000..aaa87981 --- /dev/null +++ b/src/declarative/qml/qdeclarativeinstruction.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativeinstruction_p.h" + +#include "private/qdeclarativecompiler_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +void QDeclarativeCompiledData::dump(QDeclarativeInstruction *instr, int idx) +{ +#ifdef QT_NO_DEBUG_STREAM + Q_UNUSED(instr) + Q_UNUSED(idx) +#else + QByteArray lineNumber = QByteArray::number(instr->line); + if (instr->line == (unsigned short)-1) + lineNumber = "NA"; + const char *line = lineNumber.constData(); + + switch(instr->type) { + case QDeclarativeInstruction::Init: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "INIT\t\t\t" << instr->init.bindingsSize << "\t" << instr->init.parserStatusSize << "\t" << instr->init.contextCache << "\t" << instr->init.compiledBinding; + break; + case QDeclarativeInstruction::CreateObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t" << instr->create.bindingBits << "\t\t" << types.at(instr->create.type).className; + break; + case QDeclarativeInstruction::CreateSimpleObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE_SIMPLE\t\t" << instr->createSimple.typeSize; + break; + case QDeclarativeInstruction::SetId: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t" << primitives.at(instr->setId.value); + break; + case QDeclarativeInstruction::SetDefault: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "SET_DEFAULT"; + break; + case QDeclarativeInstruction::CreateComponent: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "CREATE_COMPONENT\t" << instr->createComponent.count; + break; + case QDeclarativeInstruction::StoreMetaObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data; + break; + + case QDeclarativeInstruction::StoreFloat: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value; + break; + case QDeclarativeInstruction::StoreDouble: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value; + break; + case QDeclarativeInstruction::StoreInteger: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value; + break; + case QDeclarativeInstruction::StoreBool: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value; + break; + case QDeclarativeInstruction::StoreString: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); + break; + case QDeclarativeInstruction::StoreUrl: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_URL\t\t" << instr->storeUrl.propertyIndex << "\t" << instr->storeUrl.value << "\t\t" << urls.at(instr->storeUrl.value); + break; + case QDeclarativeInstruction::StoreColor: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t\t\t" << QString::number(instr->storeColor.value, 16); + break; + case QDeclarativeInstruction::StoreDate: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DATE\t\t" << instr->storeDate.propertyIndex << "\t" << instr->storeDate.value; + break; + case QDeclarativeInstruction::StoreTime: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_TIME\t\t" << instr->storeTime.propertyIndex << "\t" << instr->storeTime.valueIndex; + break; + case QDeclarativeInstruction::StoreDateTime: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_DATETIME\t\t" << instr->storeDateTime.propertyIndex << "\t" << instr->storeDateTime.valueIndex; + break; + case QDeclarativeInstruction::StorePoint: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_POINT\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QDeclarativeInstruction::StorePointF: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_POINTF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QDeclarativeInstruction::StoreSize: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIZE\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QDeclarativeInstruction::StoreSizeF: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIZEF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QDeclarativeInstruction::StoreRect: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_RECT\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex; + break; + case QDeclarativeInstruction::StoreRectF: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_RECTF\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex; + break; + case QDeclarativeInstruction::StoreVector3D: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VECTOR3D\t\t" << instr->storeVector3D.propertyIndex << "\t" << instr->storeVector3D.valueIndex; + break; + case QDeclarativeInstruction::StoreVariant: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); + break; + case QDeclarativeInstruction::StoreVariantInteger: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value; + break; + case QDeclarativeInstruction::StoreVariantDouble: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_DOUBLE\t\t" << instr->storeDouble.propertyIndex << "\t" << instr->storeDouble.value; + break; + case QDeclarativeInstruction::StoreVariantBool: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value; + break; + case QDeclarativeInstruction::StoreObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex; + break; + case QDeclarativeInstruction::StoreVariantObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VARIANT_OBJECT\t" << instr->storeObject.propertyIndex; + break; + case QDeclarativeInstruction::StoreInterface: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_INTERFACE\t\t" << instr->storeObject.propertyIndex; + break; + + case QDeclarativeInstruction::StoreSignal: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value); + break; + case QDeclarativeInstruction::StoreImportedScript: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_IMPORTED_SCRIPT\t" << instr->storeScript.value; + break; + case QDeclarativeInstruction::StoreScriptString: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_SCRIPT_STRING\t" << instr->storeScriptString.propertyIndex << "\t" << instr->storeScriptString.value << "\t" << instr->storeScriptString.scope; + break; + + case QDeclarativeInstruction::AssignSignalObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal); + break; + case QDeclarativeInstruction::AssignCustomType: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex; + break; + + case QDeclarativeInstruction::StoreBinding: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; + break; + case QDeclarativeInstruction::StoreBindingOnAlias: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_BINDING_ALIAS\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; + break; + case QDeclarativeInstruction::StoreCompiledBinding: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context; + break; + case QDeclarativeInstruction::StoreValueSource: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property << "\t" << instr->assignValueSource.castValue; + break; + case QDeclarativeInstruction::StoreValueInterceptor: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_VALUE_INTERCEPTOR\t" << instr->assignValueInterceptor.property << "\t" << instr->assignValueInterceptor.castValue; + break; + + case QDeclarativeInstruction::BeginObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "BEGIN\t\t\t" << instr->begin.castValue; + break; + case QDeclarativeInstruction::StoreObjectQList: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "STORE_OBJECT_QLIST"; + break; + case QDeclarativeInstruction::AssignObjectList: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "ASSIGN_OBJECT_LIST"; + break; + case QDeclarativeInstruction::FetchAttached: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_ATTACHED\t\t" << instr->fetchAttached.id; + break; + case QDeclarativeInstruction::FetchQList: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_QLIST\t\t" << instr->fetch.property; + break; + case QDeclarativeInstruction::FetchObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH\t\t\t" << instr->fetch.property; + break; + case QDeclarativeInstruction::FetchValueType: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "FETCH_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type << "\t" << instr->fetchValue.bindingSkipList; + break; + case QDeclarativeInstruction::PopFetchedObject: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP"; + break; + case QDeclarativeInstruction::PopQList: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP_QLIST"; + break; + case QDeclarativeInstruction::PopValueType: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "POP_VALUE\t\t" << instr->fetchValue.property << "\t" << instr->fetchValue.type; + break; + case QDeclarativeInstruction::Defer: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "DEFER" << "\t\t\t" << instr->defer.deferCount; + break; + default: + qWarning().nospace() << idx << "\t\t" << line << "\t" << "XXX UNKNOWN INSTRUCTION" << "\t" << instr->type; + break; + } +#endif // QT_NO_DEBUG_STREAM +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h new file mode 100644 index 00000000..34de1116 --- /dev/null +++ b/src/declarative/qml/qdeclarativeinstruction_p.h @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEINSTRUCTION_P_H +#define QDECLARATIVEINSTRUCTION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeCompiledData; +class Q_AUTOTEST_EXPORT QDeclarativeInstruction +{ +public: + enum Type { + // + // Object Creation + // + // CreateObject - Create a new object instance and push it on the + // object stack + // SetId - Set the id of the object on the top of the object stack + // SetDefault - Sets the instance on the top of the object stack to + // be the context's default object. + // StoreMetaObject - Assign the dynamic metaobject to object on the + // top of the stack. + Init, /* init */ + CreateObject, /* create */ + CreateSimpleObject, /* createSimple */ + SetId, /* setId */ + SetDefault, + CreateComponent, /* createComponent */ + StoreMetaObject, /* storeMeta */ + + // + // Precomputed single assignment + // + // StoreFloat - Store a float in a core property + // StoreDouble - Store a double in a core property + // StoreInteger - Store a int or uint in a core property + // StoreBool - Store a bool in a core property + // StoreString - Store a QString in a core property + // StoreUrl - Store a QUrl in a core property + // StoreColor - Store a QColor in a core property + // StoreDate - Store a QDate in a core property + // StoreTime - Store a QTime in a core property + // StoreDateTime - Store a QDateTime in a core property + // StoreVariant - Store a QVariant in a core property + // StoreObject - Pop the object on the top of the object stack and + // store it in a core property + StoreFloat, /* storeFloat */ + StoreDouble, /* storeDouble */ + StoreInteger, /* storeInteger */ + StoreBool, /* storeBool */ + StoreString, /* storeString */ + StoreUrl, /* storeUrl */ + StoreColor, /* storeColor */ + StoreDate, /* storeDate */ + StoreTime, /* storeTime */ + StoreDateTime, /* storeDateTime */ + StorePoint, /* storeRealPair */ + StorePointF, /* storeRealPair */ + StoreSize, /* storeRealPair */ + StoreSizeF, /* storeRealPair */ + StoreRect, /* storeRect */ + StoreRectF, /* storeRect */ + StoreVector3D, /* storeVector3D */ + StoreVariant, /* storeString */ + StoreVariantInteger, /* storeInteger */ + StoreVariantDouble, /* storeDouble */ + StoreVariantBool, /* storeBool */ + StoreObject, /* storeObject */ + StoreVariantObject, /* storeObject */ + StoreInterface, /* storeObject */ + + StoreSignal, /* storeSignal */ + StoreImportedScript, /* storeScript */ + StoreScriptString, /* storeScriptString */ + + // + // Unresolved single assignment + // + AssignSignalObject, /* assignSignalObject */ + AssignCustomType, /* assignCustomType */ + + StoreBinding, /* assignBinding */ + StoreBindingOnAlias, /* assignBinding */ + StoreCompiledBinding, /* assignBinding */ + StoreValueSource, /* assignValueSource */ + StoreValueInterceptor, /* assignValueInterceptor */ + + BeginObject, /* begin */ + + StoreObjectQList, /* NA */ + AssignObjectList, /* NA */ + + FetchAttached, /* fetchAttached */ + FetchQList, /* fetch */ + FetchObject, /* fetch */ + FetchValueType, /* fetchValue */ + + // + // Stack manipulation + // + // PopFetchedObject - Remove an object from the object stack + // PopQList - Remove a list from the list stack + PopFetchedObject, + PopQList, + PopValueType, /* fetchValue */ + + // + // Deferred creation + // + Defer /* defer */ + }; + QDeclarativeInstruction() + : line(0) {} + + Type type; + unsigned short line; + + struct InitInstruction { + int bindingsSize; + int parserStatusSize; + int contextCache; + int compiledBinding; + }; + struct CreateInstruction { + int type; + int data; + int bindingBits; + ushort column; + }; + struct CreateSimpleInstruction { + void (*create)(void *); + int typeSize; + int type; + ushort column; + }; + struct StoreMetaInstruction { + int data; + int aliasData; + int propertyCache; + }; + struct SetIdInstruction { + int value; + int index; + }; + struct AssignValueSourceInstruction { + int property; + int owner; + int castValue; + }; + struct AssignValueInterceptorInstruction { + int property; + int owner; + int castValue; + }; + struct AssignBindingInstruction { + unsigned int property; + int value; + short context; + short owner; + }; + struct FetchInstruction { + int property; + }; + struct FetchValueInstruction { + int property; + int type; + quint32 bindingSkipList; + }; + struct FetchQmlListInstruction { + int property; + int type; + }; + struct BeginInstruction { + int castValue; + }; + struct StoreFloatInstruction { + int propertyIndex; + float value; + }; + struct StoreDoubleInstruction { + int propertyIndex; + double value; + }; + struct StoreIntegerInstruction { + int propertyIndex; + int value; + }; + struct StoreBoolInstruction { + int propertyIndex; + bool value; + }; + struct StoreStringInstruction { + int propertyIndex; + int value; + }; + struct StoreScriptStringInstruction { + int propertyIndex; + int value; + int scope; + }; + struct StoreScriptInstruction { + int value; + }; + struct StoreUrlInstruction { + int propertyIndex; + int value; + }; + struct StoreColorInstruction { + int propertyIndex; + unsigned int value; + }; + struct StoreDateInstruction { + int propertyIndex; + int value; + }; + struct StoreTimeInstruction { + int propertyIndex; + int valueIndex; + }; + struct StoreDateTimeInstruction { + int propertyIndex; + int valueIndex; + }; + struct StoreRealPairInstruction { + int propertyIndex; + int valueIndex; + }; + struct StoreRectInstruction { + int propertyIndex; + int valueIndex; + }; + struct StoreVector3DInstruction { + int propertyIndex; + int valueIndex; + }; + struct StoreObjectInstruction { + int propertyIndex; + }; + struct AssignCustomTypeInstruction { + int propertyIndex; + int valueIndex; + }; + struct StoreSignalInstruction { + int signalIndex; + int value; + short context; + int name; + }; + struct AssignSignalObjectInstruction { + int signal; + }; + struct CreateComponentInstruction { + int count; + ushort column; + int endLine; + int metaObject; + }; + struct FetchAttachedInstruction { + int id; + }; + struct DeferInstruction { + int deferCount; + }; + + union { + InitInstruction init; + CreateInstruction create; + CreateSimpleInstruction createSimple; + StoreMetaInstruction storeMeta; + SetIdInstruction setId; + AssignValueSourceInstruction assignValueSource; + AssignValueInterceptorInstruction assignValueInterceptor; + AssignBindingInstruction assignBinding; + FetchInstruction fetch; + FetchValueInstruction fetchValue; + FetchQmlListInstruction fetchQmlList; + BeginInstruction begin; + StoreFloatInstruction storeFloat; + StoreDoubleInstruction storeDouble; + StoreIntegerInstruction storeInteger; + StoreBoolInstruction storeBool; + StoreStringInstruction storeString; + StoreScriptStringInstruction storeScriptString; + StoreScriptInstruction storeScript; + StoreUrlInstruction storeUrl; + StoreColorInstruction storeColor; + StoreDateInstruction storeDate; + StoreTimeInstruction storeTime; + StoreDateTimeInstruction storeDateTime; + StoreRealPairInstruction storeRealPair; + StoreRectInstruction storeRect; + StoreVector3DInstruction storeVector3D; + StoreObjectInstruction storeObject; + AssignCustomTypeInstruction assignCustomType; + StoreSignalInstruction storeSignal; + AssignSignalObjectInstruction assignSignalObject; + CreateComponentInstruction createComponent; + FetchAttachedInstruction fetchAttached; + DeferInstruction defer; + }; + + void dump(QDeclarativeCompiledData *); +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEINSTRUCTION_P_H diff --git a/src/declarative/qml/qdeclarativeintegercache.cpp b/src/declarative/qml/qdeclarativeintegercache.cpp new file mode 100644 index 00000000..feb39fef --- /dev/null +++ b/src/declarative/qml/qdeclarativeintegercache.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativeintegercache_p.h" + +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativemetatype_p.h" + +QT_BEGIN_NAMESPACE + +QDeclarativeIntegerCache::QDeclarativeIntegerCache(QDeclarativeEngine *e) +: QDeclarativeCleanup(e), engine(e) +{ +} + +QDeclarativeIntegerCache::~QDeclarativeIntegerCache() +{ + clear(); +} + +void QDeclarativeIntegerCache::clear() +{ + qDeleteAll(stringCache); + stringCache.clear(); + identifierCache.clear(); + engine = 0; +} + +QString QDeclarativeIntegerCache::findId(int value) const +{ + for (StringCache::ConstIterator iter = stringCache.begin(); + iter != stringCache.end(); ++iter) { + if (iter.value() && iter.value()->value == value) + return iter.key(); + } + return QString(); +} + +void QDeclarativeIntegerCache::add(const QString &id, int value) +{ + Q_ASSERT(!stringCache.contains(id)); + + QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); + + // ### use contextClass + Data *d = new Data(enginePriv->objectClass->createPersistentIdentifier(id), value); + + stringCache.insert(id, d); + identifierCache.insert(d->identifier, d); +} + +int QDeclarativeIntegerCache::value(const QString &id) +{ + Data *d = stringCache.value(id); + return d?d->value:-1; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeintegercache_p.h b/src/declarative/qml/qdeclarativeintegercache_p.h new file mode 100644 index 00000000..148f44e2 --- /dev/null +++ b/src/declarative/qml/qdeclarativeintegercache_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEINTEGERCACHE_P_H +#define QDECLARATIVEINTEGERCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativerefcount_p.h" +#include "private/qdeclarativecleanup_p.h" + +#include <QtCore/qhash.h> + +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeType; +class QDeclarativeEngine; +class QDeclarativeIntegerCache : public QDeclarativeRefCount, public QDeclarativeCleanup +{ +public: + QDeclarativeIntegerCache(QDeclarativeEngine *); + virtual ~QDeclarativeIntegerCache(); + + inline int count() const; + void add(const QString &, int); + int value(const QString &); + QString findId(int value) const; + inline int value(const QScriptDeclarativeClass::Identifier &id) const; + +protected: + virtual void clear(); + +private: + struct Data : public QScriptDeclarativeClass::PersistentIdentifier { + Data(const QScriptDeclarativeClass::PersistentIdentifier &i, int v) + : QScriptDeclarativeClass::PersistentIdentifier(i), value(v) {} + + int value; + }; + + typedef QHash<QString, Data *> StringCache; + typedef QHash<QScriptDeclarativeClass::Identifier, Data *> IdentifierCache; + + StringCache stringCache; + IdentifierCache identifierCache; + QDeclarativeEngine *engine; +}; + +int QDeclarativeIntegerCache::value(const QScriptDeclarativeClass::Identifier &id) const +{ + Data *d = identifierCache.value(id); + return d?d->value:-1; +} + +int QDeclarativeIntegerCache::count() const +{ + return stringCache.count(); +} + +QT_END_NAMESPACE + +#endif // QDECLARATIVEINTEGERCACHE_P_H + diff --git a/src/declarative/qml/qdeclarativelist.cpp b/src/declarative/qml/qdeclarativelist.cpp new file mode 100644 index 00000000..a9124c7d --- /dev/null +++ b/src/declarative/qml/qdeclarativelist.cpp @@ -0,0 +1,417 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativelist.h" +#include "private/qdeclarativelist_p.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativeproperty_p.h" + +QT_BEGIN_NAMESPACE + +QDeclarativeListReferencePrivate::QDeclarativeListReferencePrivate() +: propertyType(-1), refCount(1) +{ +} + +QDeclarativeListReference QDeclarativeListReferencePrivate::init(const QDeclarativeListProperty<QObject> &prop, int propType, QDeclarativeEngine *engine) +{ + QDeclarativeListReference rv; + + if (!prop.object) return rv; + + QDeclarativeEnginePrivate *p = engine?QDeclarativeEnginePrivate::get(engine):0; + + int listType = p?p->listType(propType):QDeclarativeMetaType::listType(propType); + if (listType == -1) return rv; + + rv.d = new QDeclarativeListReferencePrivate; + rv.d->object = prop.object; + rv.d->elementType = p?p->rawMetaObjectForType(listType):QDeclarativeMetaType::qmlType(listType)->baseMetaObject(); + rv.d->property = prop; + rv.d->propertyType = propType; + + return rv; +} + +void QDeclarativeListReferencePrivate::addref() +{ + Q_ASSERT(refCount > 0); + ++refCount; +} + +void QDeclarativeListReferencePrivate::release() +{ + Q_ASSERT(refCount > 0); + --refCount; + if (!refCount) + delete this; +} + +/*! +\class QDeclarativeListReference +\since 4.7 +\module QtDeclarative +\brief The QDeclarativeListReference class allows the manipulation of QDeclarativeListProperty properties. + +QDeclarativeListReference allows C++ programs to read from, and assign values to a QML list property in a +simple and type safe way. A QDeclarativeListReference can be created by passing an object and property +name or through a QDeclarativeProperty instance. These two are equivalant: + +\code +QDeclarativeListReference ref1(object, "children"); + +QDeclarativeProperty ref2(object, "children"); +QDeclarativeListReference ref2 = qvariant_cast<QDeclarativeListReference>(ref2.read()); +\endcode + +Not all QML list properties support all operations. A set of methods, canAppend(), canAt(), canClear() and +canCount() allow programs to query whether an operation is supported on a given property. + +QML list properties are typesafe. Only QObject's that derive from the correct base class can be assigned to +the list. The listElementType() method can be used to query the QMetaObject of the QObject type supported. +Attempting to add objects of the incorrect type to a list property will fail. + +Like with normal lists, when accessing a list element by index, it is the callers responsibility to ensure +that it does not request an out of range element using the count() method before calling at(). +*/ + +/*! +Constructs an invalid instance. +*/ +QDeclarativeListReference::QDeclarativeListReference() +: d(0) +{ +} + +/*! +Constructs a QDeclarativeListReference for \a object's \a property. If \a property is not a list +property, an invalid QDeclarativeListReference is created. If \a object is destroyed after +the reference is constructed, it will automatically become invalid. That is, it is safe to hold +QDeclarativeListReference instances even after \a object is deleted. + +Passing \a engine is required to access some QML created list properties. If in doubt, and an engine +is available, pass it. +*/ +QDeclarativeListReference::QDeclarativeListReference(QObject *object, const char *property, QDeclarativeEngine *engine) +: d(0) +{ + if (!object || !property) return; + + QDeclarativePropertyCache::Data local; + QDeclarativePropertyCache::Data *data = + QDeclarativePropertyCache::property(engine, object, QLatin1String(property), local); + + if (!data || !(data->flags & QDeclarativePropertyCache::Data::IsQList)) return; + + QDeclarativeEnginePrivate *p = engine?QDeclarativeEnginePrivate::get(engine):0; + + int listType = p?p->listType(data->propType):QDeclarativeMetaType::listType(data->propType); + if (listType == -1) return; + + d = new QDeclarativeListReferencePrivate; + d->object = object; + d->elementType = p?p->rawMetaObjectForType(listType):QDeclarativeMetaType::qmlType(listType)->baseMetaObject(); + d->propertyType = data->propType; + + void *args[] = { &d->property, 0 }; + QMetaObject::metacall(object, QMetaObject::ReadProperty, data->coreIndex, args); +} + +/*! \internal */ +QDeclarativeListReference::QDeclarativeListReference(const QDeclarativeListReference &o) +: d(o.d) +{ + if (d) d->addref(); +} + +/*! \internal */ +QDeclarativeListReference &QDeclarativeListReference::operator=(const QDeclarativeListReference &o) +{ + if (o.d) o.d->addref(); + if (d) d->release(); + d = o.d; + return *this; +} + +/*! \internal */ +QDeclarativeListReference::~QDeclarativeListReference() +{ + if (d) d->release(); +} + +/*! +Returns true if the instance refers to a valid list property, otherwise false. +*/ +bool QDeclarativeListReference::isValid() const +{ + return d && d->object; +} + +/*! +Returns the list property's object. Returns 0 if the reference is invalid. +*/ +QObject *QDeclarativeListReference::object() const +{ + if (isValid()) return d->object; + else return 0; +} + +/*! +Returns the QMetaObject for the elements stored in the list property. Returns 0 if the reference +is invalid. + +The QMetaObject can be used ahead of time to determine whether a given instance can be added +to a list. +*/ +const QMetaObject *QDeclarativeListReference::listElementType() const +{ + if (isValid()) return d->elementType; + else return 0; +} + +/*! +Returns true if the list property can be appended to, otherwise false. Returns false if the +reference is invalid. + +\sa append() +*/ +bool QDeclarativeListReference::canAppend() const +{ + return (isValid() && d->property.append); +} + +/*! +Returns true if the list property can queried by index, otherwise false. Returns false if the +reference is invalid. + +\sa at() +*/ +bool QDeclarativeListReference::canAt() const +{ + return (isValid() && d->property.at); +} + +/*! +Returns true if the list property can be cleared, otherwise false. Returns false if the +reference is invalid. + +\sa clear() +*/ +bool QDeclarativeListReference::canClear() const +{ + return (isValid() && d->property.clear); +} + +/*! +Returns true if the list property can be queried for its element count, otherwise false. +Returns false if the reference is invalid. + +\sa count() +*/ +bool QDeclarativeListReference::canCount() const +{ + return (isValid() && d->property.count); +} + +/*! +Appends \a object to the list. Returns true if the operation succeeded, otherwise false. + +\sa canAppend() +*/ +bool QDeclarativeListReference::append(QObject *object) const +{ + if (!canAppend()) return false; + + if (object && !QDeclarativePropertyPrivate::canConvert(object->metaObject(), d->elementType)) + return false; + + d->property.append(&d->property, object); + + return true; +} + +/*! +Returns the list element at \a index, or 0 if the operation failed. + +\sa canAt() +*/ +QObject *QDeclarativeListReference::at(int index) const +{ + if (!canAt()) return 0; + + return d->property.at(&d->property, index); +} + +/*! +Clears the list. Returns true if the operation succeeded, otherwise false. + +\sa canClear() +*/ +bool QDeclarativeListReference::clear() const +{ + if (!canClear()) return false; + + d->property.clear(&d->property); + + return true; +} + +/*! +Returns the number of objects in the list, or 0 if the operation failed. +*/ +int QDeclarativeListReference::count() const +{ + if (!canCount()) return 0; + + return d->property.count(&d->property); +} + +/*! +\class QDeclarativeListProperty +\since 4.7 +\brief The QDeclarativeListProperty class allows applications to expose list-like +properties to QML. + +QML has many list properties, where more than one object value can be assigned. +The use of a list property from QML looks like this: + +\code +FruitBasket { + fruit: [ + Apple {}, + Orange{}, + Banana{} + ] +} +\endcode + +The QDeclarativeListProperty encapsulates a group of function pointers that represet the +set of actions QML can perform on the list - adding items, retrieving items and +clearing the list. In the future, additional operations may be supported. All +list properties must implement the append operation, but the rest are optional. + +To provide a list property, a C++ class must implement the operation callbacks, +and then return an appropriate QDeclarativeListProperty value from the property getter. +List properties should have no setter. In the example above, the Q_PROPERTY() +declarative will look like this: + +\code +Q_PROPERTY(QDeclarativeListProperty<Fruit> fruit READ fruit); +\endcode + +QML list properties are typesafe - in this case \c {Fruit} is a QObject type that +\c {Apple}, \c {Orange} and \c {Banana} all derive from. + +\note QDeclarativeListProperty can only be used for lists of QObject-derived object pointers. + +\sa {Object and List Property Types} + +*/ + +/*! +\fn QDeclarativeListProperty::QDeclarativeListProperty() +\internal +*/ + +/*! +\fn QDeclarativeListProperty::QDeclarativeListProperty(QObject *object, QList<T *> &list) + +Convenience constructor for making a QDeclarativeListProperty value from an existing +QList \a list. The \a list reference must remain valid for as long as \a object +exists. \a object must be provided. + +Generally this constructor should not be used in production code, as a +writable QList violates QML's memory management rules. However, this constructor +can very useful while prototyping. +*/ + +/*! +\fn QDeclarativeListProperty::QDeclarativeListProperty(QObject *object, void *data, AppendFunction append, + CountFunction count = 0, AtFunction at = 0, + ClearFunction clear = 0) + +Construct a QDeclarativeListProperty from a set of operation functions. An opaque \a data handle +may be passed which can be accessed from within the operation functions. The list property +remains valid while \a object exists. + +The \a append operation is compulsory and must be provided, while the \a count, \a at and +\a clear methods are optional. +*/ + +/*! +\typedef QDeclarativeListProperty::AppendFunction + +Synonym for \c {void (*)(QDeclarativeListProperty<T> *property, T *value)}. + +Append the \a value to the list \a property. +*/ + +/*! +\typedef QDeclarativeListProperty::CountFunction + +Synonym for \c {int (*)(QDeclarativeListProperty<T> *property)}. + +Return the number of elements in the list \a property. +*/ + +/*! +\fn bool QDeclarativeListProperty::operator==(const QDeclarativeListProperty &other) const + +Returns true if this QDeclarativeListProperty is equal to \a other, otherwise false. +*/ + +/*! +\typedef QDeclarativeListProperty::AtFunction + +Synonym for \c {T *(*)(QDeclarativeListProperty<T> *property, int index)}. + +Return the element at position \a index in the list \a property. +*/ + +/*! +\typedef QDeclarativeListProperty::ClearFunction + +Synonym for \c {void (*)(QDeclarativeListProperty<T> *property)}. + +Clear the list \a property. +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativelist.h b/src/declarative/qml/qdeclarativelist.h new file mode 100644 index 00000000..5b2d5b4e --- /dev/null +++ b/src/declarative/qml/qdeclarativelist.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELIST_H +#define QDECLARATIVELIST_H + +#include <QtCore/qglobal.h> +#include <QtCore/qlist.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QObject; +struct QMetaObject; + +#ifndef QDECLARATIVELISTPROPERTY +#define QDECLARATIVELISTPROPERTY +template<typename T> +class QDeclarativeListProperty { +public: + typedef void (*AppendFunction)(QDeclarativeListProperty<T> *, T*); + typedef int (*CountFunction)(QDeclarativeListProperty<T> *); + typedef T *(*AtFunction)(QDeclarativeListProperty<T> *, int); + typedef void (*ClearFunction)(QDeclarativeListProperty<T> *); + + QDeclarativeListProperty() + : object(0), data(0), append(0), count(0), at(0), clear(0), dummy1(0), dummy2(0) {} + QDeclarativeListProperty(QObject *o, QList<T *> &list) + : object(o), data(&list), append(qlist_append), count(qlist_count), at(qlist_at), + clear(qlist_clear), dummy1(0), dummy2(0) {} + QDeclarativeListProperty(QObject *o, void *d, AppendFunction a, CountFunction c = 0, AtFunction t = 0, + ClearFunction r = 0) + : object(o), data(d), append(a), count(c), at(t), clear(r), dummy1(0), dummy2(0) {} + + bool operator==(const QDeclarativeListProperty &o) const { + return object == o.object && + data == o.data && + append == o.append && + count == o.count && + at == o.at && + clear == o.clear; + } + + QObject *object; + void *data; + + AppendFunction append; + + CountFunction count; + AtFunction at; + + ClearFunction clear; + + void *dummy1; + void *dummy2; + +private: + static void qlist_append(QDeclarativeListProperty *p, T *v) { + reinterpret_cast<QList<T *> *>(p->data)->append(v); + } + static int qlist_count(QDeclarativeListProperty *p) { + return reinterpret_cast<QList<T *> *>(p->data)->count(); + } + static T *qlist_at(QDeclarativeListProperty *p, int idx) { + return reinterpret_cast<QList<T *> *>(p->data)->at(idx); + } + static void qlist_clear(QDeclarativeListProperty *p) { + return reinterpret_cast<QList<T *> *>(p->data)->clear(); + } +}; +#endif + +class QDeclarativeEngine; +class QDeclarativeListReferencePrivate; +class Q_DECLARATIVE_EXPORT QDeclarativeListReference +{ +public: + QDeclarativeListReference(); + QDeclarativeListReference(QObject *, const char *property, QDeclarativeEngine * = 0); + QDeclarativeListReference(const QDeclarativeListReference &); + QDeclarativeListReference &operator=(const QDeclarativeListReference &); + ~QDeclarativeListReference(); + + bool isValid() const; + + QObject *object() const; + const QMetaObject *listElementType() const; + + bool canAppend() const; + bool canAt() const; + bool canClear() const; + bool canCount() const; + + bool append(QObject *) const; + QObject *at(int) const; + bool clear() const; + int count() const; + +private: + friend class QDeclarativeListReferencePrivate; + QDeclarativeListReferencePrivate* d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDeclarativeListReference) + +QT_END_HEADER + +#endif // QDECLARATIVELIST_H diff --git a/src/declarative/qml/qdeclarativelist_p.h b/src/declarative/qml/qdeclarativelist_p.h new file mode 100644 index 00000000..76ac83f0 --- /dev/null +++ b/src/declarative/qml/qdeclarativelist_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELIST_P_H +#define QDECLARATIVELIST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativelist.h" +#include "private/qdeclarativeguard_p.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativeListReferencePrivate +{ +public: + QDeclarativeListReferencePrivate(); + + static QDeclarativeListReference init(const QDeclarativeListProperty<QObject> &, int, QDeclarativeEngine *); + + QDeclarativeGuard<QObject> object; + const QMetaObject *elementType; + QDeclarativeListProperty<QObject> property; + int propertyType; + + void addref(); + void release(); + int refCount; + + static inline QDeclarativeListReferencePrivate *get(QDeclarativeListReference *ref) { + return ref->d; + } +}; + + +QT_END_NAMESPACE + +#endif // QDECLARATIVELIST_P_H diff --git a/src/declarative/qml/qdeclarativelistscriptclass.cpp b/src/declarative/qml/qdeclarativelistscriptclass.cpp new file mode 100644 index 00000000..4bebd7af --- /dev/null +++ b/src/declarative/qml/qdeclarativelistscriptclass.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativelistscriptclass_p.h" + +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativeguard_p.h" +#include "private/qdeclarativelist_p.h" + +QT_BEGIN_NAMESPACE + +struct ListData : public QScriptDeclarativeClass::Object { + QDeclarativeGuard<QObject> object; + QDeclarativeListProperty<QObject> property; + int propertyType; +}; + +QDeclarativeListScriptClass::QDeclarativeListScriptClass(QDeclarativeEngine *e) +: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(e)), engine(e) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + Q_UNUSED(scriptEngine); + + m_lengthId = createPersistentIdentifier(QLatin1String("length")); +} + +QDeclarativeListScriptClass::~QDeclarativeListScriptClass() +{ +} + +QScriptValue QDeclarativeListScriptClass::newList(QObject *object, int propId, int propType) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + if (!object || propId == -1) + return scriptEngine->nullValue(); + + ListData *data = new ListData; + data->object = object; + data->propertyType = propType; + void *args[] = { &data->property, 0 }; + QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args); + + return newObject(scriptEngine, this, data); +} + +QScriptValue QDeclarativeListScriptClass::newList(const QDeclarativeListProperty<QObject> &prop, int propType) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + ListData *data = new ListData; + data->object = prop.object; + data->property = prop; + data->propertyType = propType; + + return newObject(scriptEngine, this, data); +} + +QScriptClass::QueryFlags +QDeclarativeListScriptClass::queryProperty(Object *object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(object); + Q_UNUSED(flags); + if (name == m_lengthId.identifier) + return QScriptClass::HandlesReadAccess; + + bool ok = false; + quint32 idx = toArrayIndex(name, &ok); + + if (ok) { + lastIndex = idx; + return QScriptClass::HandlesReadAccess; + } else { + return 0; + } +} + +QDeclarativeListScriptClass::Value QDeclarativeListScriptClass::property(Object *obj, const Identifier &name) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); + + ListData *data = (ListData *)obj; + if (!data->object) + return Value(); + + quint32 count = data->property.count?data->property.count(&data->property):0; + + if (name == m_lengthId.identifier) + return Value(scriptEngine, count); + else if (lastIndex < count && data->property.at) + return Value(scriptEngine, enginePriv->objectClass->newQObject(data->property.at(&data->property, lastIndex))); + else + return Value(); +} + +QVariant QDeclarativeListScriptClass::toVariant(Object *obj, bool *ok) +{ + ListData *data = (ListData *)obj; + + if (!data->object) { + if (ok) *ok = false; + return QVariant(); + } + + return QVariant::fromValue(QDeclarativeListReferencePrivate::init(data->property, data->propertyType, engine)); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativelistscriptclass_p.h b/src/declarative/qml/qdeclarativelistscriptclass_p.h new file mode 100644 index 00000000..b545014f --- /dev/null +++ b/src/declarative/qml/qdeclarativelistscriptclass_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVELISTSCRIPTCLASS_P_H +#define QDECLARATIVELISTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qscriptdeclarativeclass_p.h> +#include "qdeclarativelist.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativeEngine; +class QDeclarativeListScriptClass : public QScriptDeclarativeClass +{ +public: + QDeclarativeListScriptClass(QDeclarativeEngine *); + ~QDeclarativeListScriptClass(); + + QScriptValue newList(QObject *, int, int); + QScriptValue newList(const QDeclarativeListProperty<QObject> &, int); + +protected: + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + virtual Value property(Object *, const Identifier &); + virtual QVariant toVariant(Object *, bool *ok); + +private: + PersistentIdentifier m_lengthId; + QDeclarativeEngine *engine; + + quint32 lastIndex; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVELISTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp new file mode 100644 index 00000000..d46eb78b --- /dev/null +++ b/src/declarative/qml/qdeclarativemetatype.cpp @@ -0,0 +1,1536 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtDeclarative/qdeclarativeprivate.h> +#include "private/qdeclarativemetatype_p.h" + +#include "private/qdeclarativeproxymetaobject_p.h" +#include "private/qdeclarativecustomparser_p.h" +#include "private/qdeclarativeguard_p.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qbitarray.h> +#include <QtCore/qreadwritelock.h> +#include <qmetatype.h> +#include <qobjectdefs.h> +#include <qdatetime.h> +#include <qbytearray.h> +#include <qreadwritelock.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qvector.h> +#include <qlocale.h> +#include <QtCore/qcryptographichash.h> +#include <QtScript/qscriptvalue.h> + +#include <ctype.h> + +#ifdef QT_BOOTSTRAPPED +# ifndef QT_NO_GEOM_VARIANT +# define QT_NO_GEOM_VARIANT +# endif +#else +# include <qbitarray.h> +# include <qurl.h> +# include <qvariant.h> +#endif + +#ifndef QT_NO_GEOM_VARIANT +# include <qsize.h> +# include <qpoint.h> +# include <qrect.h> +# include <qline.h> +# include <qvector3d.h> +#endif +#define NS(x) QT_PREPEND_NAMESPACE(x) + +QT_BEGIN_NAMESPACE + +struct QDeclarativeMetaTypeData +{ + ~QDeclarativeMetaTypeData(); + QList<QDeclarativeType *> types; + typedef QHash<int, QDeclarativeType *> Ids; + Ids idToType; + typedef QHash<QByteArray, QDeclarativeType *> Names; + Names nameToType; + typedef QHash<const QMetaObject *, QDeclarativeType *> MetaObjects; + MetaObjects metaObjectToType; + typedef QHash<int, QDeclarativeMetaType::StringConverter> StringConverters; + StringConverters stringConverters; + + struct ModuleInfo { + ModuleInfo(int major, int minor) + : vmajor_min(major), vminor_min(minor), vmajor_max(major), vminor_max(minor) {} + ModuleInfo(int major_min, int minor_min, int major_max, int minor_max) + : vmajor_min(major_min), vminor_min(minor_min), vmajor_max(major_max), vminor_max(minor_max) {} + int vmajor_min, vminor_min; + int vmajor_max, vminor_max; + }; + typedef QHash<QByteArray, ModuleInfo> ModuleInfoHash; + ModuleInfoHash modules; + + QBitArray objects; + QBitArray interfaces; + QBitArray lists; + + QList<QDeclarativePrivate::AutoParentFunction> parentFunctions; +}; +Q_GLOBAL_STATIC(QDeclarativeMetaTypeData, metaTypeData) +Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock) + +QDeclarativeMetaTypeData::~QDeclarativeMetaTypeData() +{ + for (int i = 0; i < types.count(); ++i) + delete types.at(i); +} + +class QDeclarativeTypePrivate +{ +public: + QDeclarativeTypePrivate(); + + void init() const; + + bool m_isInterface : 1; + const char *m_iid; + QByteArray m_module; + QByteArray m_name; + int m_version_maj; + int m_version_min; + int m_typeId; int m_listId; + int m_revision; + mutable bool m_containsRevisionedAttributes; + mutable QDeclarativeType *m_superType; + + int m_allocationSize; + void (*m_newFunc)(void *); + QString m_noCreationReason; + + const QMetaObject *m_baseMetaObject; + QDeclarativeAttachedPropertiesFunc m_attachedPropertiesFunc; + const QMetaObject *m_attachedPropertiesType; + int m_attachedPropertiesId; + int m_parserStatusCast; + int m_propertyValueSourceCast; + int m_propertyValueInterceptorCast; + QObject *(*m_extFunc)(QObject *); + const QMetaObject *m_extMetaObject; + int m_index; + QDeclarativeCustomParser *m_customParser; + mutable volatile bool m_isSetup:1; + mutable bool m_haveSuperType : 1; + mutable QList<QDeclarativeProxyMetaObject::ProxyData> m_metaObjects; + + static QHash<const QMetaObject *, int> m_attachedPropertyIds; +}; + +QHash<const QMetaObject *, int> QDeclarativeTypePrivate::m_attachedPropertyIds; + +QDeclarativeTypePrivate::QDeclarativeTypePrivate() +: m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_containsRevisionedAttributes(false), + m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), + m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1), + m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), + m_isSetup(false), m_haveSuperType(false) +{ +} + + +QDeclarativeType::QDeclarativeType(int index, const QDeclarativePrivate::RegisterInterface &interface) +: d(new QDeclarativeTypePrivate) +{ + d->m_isInterface = true; + d->m_iid = interface.iid; + d->m_typeId = interface.typeId; + d->m_listId = interface.listId; + d->m_newFunc = 0; + d->m_index = index; + d->m_isSetup = true; + d->m_version_maj = 0; + d->m_version_min = 0; +} + +QDeclarativeType::QDeclarativeType(int index, const QDeclarativePrivate::RegisterType &type) +: d(new QDeclarativeTypePrivate) +{ + QByteArray name = type.uri; + if (type.uri) name += '/'; + name += type.elementName; + + d->m_module = type.uri; + d->m_name = name; + d->m_version_maj = type.versionMajor; + d->m_version_min = type.versionMinor; + if (type.version >= 1) // revisions added in version 1 + d->m_revision = type.revision; + d->m_typeId = type.typeId; + d->m_listId = type.listId; + d->m_allocationSize = type.objectSize; + d->m_newFunc = type.create; + d->m_noCreationReason = type.noCreationReason; + d->m_baseMetaObject = type.metaObject; + d->m_attachedPropertiesFunc = type.attachedPropertiesFunction; + d->m_attachedPropertiesType = type.attachedPropertiesMetaObject; + if (d->m_attachedPropertiesType) { + QHash<const QMetaObject *, int>::Iterator iter = d->m_attachedPropertyIds.find(d->m_baseMetaObject); + if (iter == d->m_attachedPropertyIds.end()) + iter = d->m_attachedPropertyIds.insert(d->m_baseMetaObject, index); + d->m_attachedPropertiesId = *iter; + } else { + d->m_attachedPropertiesId = -1; + } + d->m_parserStatusCast = type.parserStatusCast; + d->m_propertyValueSourceCast = type.valueSourceCast; + d->m_propertyValueInterceptorCast = type.valueInterceptorCast; + d->m_extFunc = type.extensionObjectCreate; + d->m_index = index; + d->m_customParser = type.customParser; + + if (type.extensionMetaObject) + d->m_extMetaObject = type.extensionMetaObject; +} + +QDeclarativeType::~QDeclarativeType() +{ + delete d->m_customParser; + delete d; +} + +QByteArray QDeclarativeType::module() const +{ + return d->m_module; +} + +int QDeclarativeType::majorVersion() const +{ + return d->m_version_maj; +} + +int QDeclarativeType::minorVersion() const +{ + return d->m_version_min; +} + +bool QDeclarativeType::availableInVersion(int vmajor, int vminor) const +{ + return vmajor > d->m_version_maj || (vmajor == d->m_version_maj && vminor >= d->m_version_min); +} + +bool QDeclarativeType::availableInVersion(const QByteArray &module, int vmajor, int vminor) const +{ + return module == d->m_module && (vmajor > d->m_version_maj || (vmajor == d->m_version_maj && vminor >= d->m_version_min)); +} + +// returns the nearest _registered_ super class +QDeclarativeType *QDeclarativeType::superType() const +{ + if (!d->m_haveSuperType) { + const QMetaObject *mo = d->m_baseMetaObject->superClass(); + while (mo && !d->m_superType) { + d->m_superType = QDeclarativeMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min); + mo = mo->superClass(); + } + d->m_haveSuperType = true; + } + + return d->m_superType; +} + +static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, + const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd) +{ + // Clone Q_CLASSINFO + for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) { + QMetaClassInfo info = mo->classInfo(ii); + + int otherIndex = ignoreEnd->indexOfClassInfo(info.name()); + if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) { + // Skip + } else { + builder.addClassInfo(info.name(), info.value()); + } + } + + // Clone Q_PROPERTY + for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) { + QMetaProperty property = mo->property(ii); + + int otherIndex = ignoreEnd->indexOfProperty(property.name()); + if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) { + builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void")); + // Skip + } else { + builder.addProperty(property); + } + } + + // Clone Q_METHODS + for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) { + QMetaMethod method = mo->method(ii); + + // More complex - need to search name + QByteArray name = method.signature(); + int parenIdx = name.indexOf('('); + if (parenIdx != -1) name = name.left(parenIdx); + + + bool found = false; + + for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount(); + !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount(); + ++ii) { + + QMetaMethod other = ignoreEnd->method(ii); + QByteArray othername = other.signature(); + int parenIdx = othername.indexOf('('); + if (parenIdx != -1) othername = othername.left(parenIdx); + + found = name == othername; + } + + QMetaMethodBuilder m = builder.addMethod(method); + if (found) // SKIP + m.setAccess(QMetaMethod::Private); + } + + // Clone Q_ENUMS + for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) { + QMetaEnum enumerator = mo->enumerator(ii); + + int otherIndex = ignoreEnd->indexOfEnumerator(enumerator.name()); + if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) { + // Skip + } else { + builder.addEnumerator(enumerator); + } + } +} + +void QDeclarativeTypePrivate::init() const +{ + if (m_isSetup) return; + + QWriteLocker lock(metaTypeDataLock()); + if (m_isSetup) + return; + + // Setup extended meta object + // XXX - very inefficient + const QMetaObject *mo = m_baseMetaObject; + if (m_extFunc) { + QMetaObject *mmo = new QMetaObject; + *mmo = *m_extMetaObject; + mmo->d.superdata = mo; + QDeclarativeProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0, 0 }; + m_metaObjects << data; + } + + mo = mo->d.superdata; + while(mo) { + QDeclarativeType *t = metaTypeData()->metaObjectToType.value(mo); + if (t) { + if (t->d->m_extFunc) { + QMetaObjectBuilder builder; + clone(builder, t->d->m_extMetaObject, t->d->m_baseMetaObject, m_baseMetaObject); + QMetaObject *mmo = builder.toMetaObject(); + mmo->d.superdata = m_baseMetaObject; + if (!m_metaObjects.isEmpty()) + m_metaObjects.last().metaObject->d.superdata = mmo; + QDeclarativeProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0, 0 }; + m_metaObjects << data; + } + } + mo = mo->d.superdata; + } + + for (int ii = 0; ii < m_metaObjects.count(); ++ii) { + m_metaObjects[ii].propertyOffset = + m_metaObjects.at(ii).metaObject->propertyOffset(); + m_metaObjects[ii].methodOffset = + m_metaObjects.at(ii).metaObject->methodOffset(); + } + + // Check for revisioned details + { + const QMetaObject *mo = 0; + if (m_metaObjects.isEmpty()) + mo = m_baseMetaObject; + else + mo = m_metaObjects.first().metaObject; + + for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) { + if (mo->property(ii).revision() != 0) + m_containsRevisionedAttributes = true; + } + + for (int ii = 0; !m_containsRevisionedAttributes && ii < mo->methodCount(); ++ii) { + if (mo->method(ii).revision() != 0) + m_containsRevisionedAttributes = true; + } + } + + m_isSetup = true; + lock.unlock(); +} + +QByteArray QDeclarativeType::typeName() const +{ + if (d->m_baseMetaObject) + return d->m_baseMetaObject->className(); + else + return QByteArray(); +} + +QByteArray QDeclarativeType::qmlTypeName() const +{ + return d->m_name; +} + +QObject *QDeclarativeType::create() const +{ + d->init(); + + QObject *rv = (QObject *)operator new(d->m_allocationSize); + d->m_newFunc(rv); + + if (rv && !d->m_metaObjects.isEmpty()) + (void *)new QDeclarativeProxyMetaObject(rv, &d->m_metaObjects); + + return rv; +} + +void QDeclarativeType::create(QObject **out, void **memory, size_t additionalMemory) const +{ + d->init(); + + QObject *rv = (QObject *)operator new(d->m_allocationSize + additionalMemory); + d->m_newFunc(rv); + + if (rv && !d->m_metaObjects.isEmpty()) + (void *)new QDeclarativeProxyMetaObject(rv, &d->m_metaObjects); + + *out = rv; + *memory = ((char *)rv) + d->m_allocationSize; +} + +QDeclarativeCustomParser *QDeclarativeType::customParser() const +{ + return d->m_customParser; +} + +QDeclarativeType::CreateFunc QDeclarativeType::createFunction() const +{ + return d->m_newFunc; +} + +QString QDeclarativeType::noCreationReason() const +{ + return d->m_noCreationReason; +} + +int QDeclarativeType::createSize() const +{ + return d->m_allocationSize; +} + +bool QDeclarativeType::isCreatable() const +{ + return d->m_newFunc != 0; +} + +bool QDeclarativeType::isExtendedType() const +{ + d->init(); + + return !d->m_metaObjects.isEmpty(); +} + +bool QDeclarativeType::isInterface() const +{ + return d->m_isInterface; +} + +int QDeclarativeType::typeId() const +{ + return d->m_typeId; +} + +int QDeclarativeType::qListTypeId() const +{ + return d->m_listId; +} + +const QMetaObject *QDeclarativeType::metaObject() const +{ + d->init(); + + if (d->m_metaObjects.isEmpty()) + return d->m_baseMetaObject; + else + return d->m_metaObjects.first().metaObject; + +} + +const QMetaObject *QDeclarativeType::baseMetaObject() const +{ + return d->m_baseMetaObject; +} + +bool QDeclarativeType::containsRevisionedAttributes() const +{ + d->init(); + + return d->m_containsRevisionedAttributes; +} + +int QDeclarativeType::metaObjectRevision() const +{ + return d->m_revision; +} + +QDeclarativeAttachedPropertiesFunc QDeclarativeType::attachedPropertiesFunction() const +{ + return d->m_attachedPropertiesFunc; +} + +const QMetaObject *QDeclarativeType::attachedPropertiesType() const +{ + return d->m_attachedPropertiesType; +} + +/* +This is the id passed to qmlAttachedPropertiesById(). This is different from the index +for the case that a single class is registered under two or more names (eg. Item in +Qt 4.7 and QtQuick 1.0). +*/ +int QDeclarativeType::attachedPropertiesId() const +{ + return d->m_attachedPropertiesId; +} + +int QDeclarativeType::parserStatusCast() const +{ + return d->m_parserStatusCast; +} + +int QDeclarativeType::propertyValueSourceCast() const +{ + return d->m_propertyValueSourceCast; +} + +int QDeclarativeType::propertyValueInterceptorCast() const +{ + return d->m_propertyValueInterceptorCast; +} + +const char *QDeclarativeType::interfaceIId() const +{ + return d->m_iid; +} + +int QDeclarativeType::index() const +{ + return d->m_index; +} + +int registerAutoParentFunction(QDeclarativePrivate::RegisterAutoParent &autoparent) +{ + QWriteLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + + data->parentFunctions.append(autoparent.function); + + return data->parentFunctions.count() - 1; +} + +int registerInterface(const QDeclarativePrivate::RegisterInterface &interface) +{ + if (interface.version > 0) + qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); + + QWriteLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + + int index = data->types.count(); + + QDeclarativeType *type = new QDeclarativeType(index, interface); + + data->types.append(type); + data->idToType.insert(type->typeId(), type); + data->idToType.insert(type->qListTypeId(), type); + // XXX No insertMulti, so no multi-version interfaces? + if (!type->qmlTypeName().isEmpty()) + data->nameToType.insert(type->qmlTypeName(), type); + + if (data->interfaces.size() <= interface.typeId) + data->interfaces.resize(interface.typeId + 16); + if (data->lists.size() <= interface.listId) + data->lists.resize(interface.listId + 16); + data->interfaces.setBit(interface.typeId, true); + data->lists.setBit(interface.listId, true); + + return index; +} + +int registerType(const QDeclarativePrivate::RegisterType &type) +{ + if (type.elementName) { + for (int ii = 0; type.elementName[ii]; ++ii) { + if (!isalnum(type.elementName[ii])) { + qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName); + return -1; + } + } + } + + QWriteLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + int index = data->types.count(); + + QDeclarativeType *dtype = new QDeclarativeType(index, type); + + data->types.append(dtype); + data->idToType.insert(dtype->typeId(), dtype); + if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype); + + if (!dtype->qmlTypeName().isEmpty()) + data->nameToType.insertMulti(dtype->qmlTypeName(), dtype); + + data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype); + + if (data->objects.size() <= type.typeId) + data->objects.resize(type.typeId + 16); + if (data->lists.size() <= type.listId) + data->lists.resize(type.listId + 16); + data->objects.setBit(type.typeId, true); + if (type.listId) data->lists.setBit(type.listId, true); + + if (type.uri) { + QByteArray mod(type.uri); + QDeclarativeMetaTypeData::ModuleInfoHash::Iterator it = data->modules.find(mod); + if (it == data->modules.end()) { + // New module + data->modules.insert(mod, QDeclarativeMetaTypeData::ModuleInfo(type.versionMajor,type.versionMinor)); + } else if ((*it).vmajor_max < type.versionMajor || ((*it).vmajor_max == type.versionMajor && (*it).vminor_max < type.versionMinor)) { + // Newer module + data->modules.insert(mod, QDeclarativeMetaTypeData::ModuleInfo((*it).vmajor_min, (*it).vminor_min, type.versionMajor, type.versionMinor)); + } else if ((*it).vmajor_min > type.versionMajor || ((*it).vmajor_min == type.versionMajor && (*it).vminor_min > type.versionMinor)) { + // Older module + data->modules.insert(mod, QDeclarativeMetaTypeData::ModuleInfo(type.versionMajor, type.versionMinor, (*it).vmajor_min, (*it).vminor_min)); + } + } + + return index; +} + +/* +This method is "over generalized" to allow us to (potentially) register more types of things in +the future without adding exported symbols. +*/ +int QDeclarativePrivate::qmlregister(RegistrationType type, void *data) +{ + if (type == TypeRegistration) { + return registerType(*reinterpret_cast<RegisterType *>(data)); + } else if (type == InterfaceRegistration) { + return registerInterface(*reinterpret_cast<RegisterInterface *>(data)); + } else if (type == AutoParentRegistration) { + return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data)); + } + return -1; +} + +/* + Have any types been registered for \a module with at least versionMajor.versionMinor, and types + for \a module with at most versionMajor.versionMinor. + + So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10. + + Passing -1 for both \a versionMajor \a versionMinor will return true if any version is installed. +*/ +bool QDeclarativeMetaType::isModule(const QByteArray &module, int versionMajor, int versionMinor) +{ + QDeclarativeMetaTypeData *data = metaTypeData(); + QDeclarativeMetaTypeData::ModuleInfoHash::Iterator it = data->modules.find(module); + return it != data->modules.end() + && ((versionMajor<0 && versionMinor<0) || + (((*it).vmajor_max > versionMajor || + ((*it).vmajor_max == versionMajor && (*it).vminor_max >= versionMinor)) + && ((*it).vmajor_min < versionMajor || + ((*it).vmajor_min == versionMajor && (*it).vminor_min <= versionMinor)))); +} + +QList<QDeclarativePrivate::AutoParentFunction> QDeclarativeMetaType::parentFunctions() +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + return data->parentFunctions; +} + +QObject *QDeclarativeMetaType::toQObject(const QVariant &v, bool *ok) +{ + if (!isQObject(v.userType())) { + if (ok) *ok = false; + return 0; + } + + if (ok) *ok = true; + + return *(QObject **)v.constData(); +} + +bool QDeclarativeMetaType::isQObject(int userType) +{ + if (userType == QMetaType::QObjectStar) + return true; + + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType); +} + +/* + Returns the item type for a list of type \a id. + */ +int QDeclarativeMetaType::listType(int id) +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + QDeclarativeType *type = data->idToType.value(id); + if (type && type->qListTypeId() == id) + return type->typeId(); + else + return 0; +} + +int QDeclarativeMetaType::attachedPropertiesFuncId(const QMetaObject *mo) +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + + QDeclarativeType *type = data->metaObjectToType.value(mo); + if (type && type->attachedPropertiesFunction()) + return type->attachedPropertiesId(); + else + return -1; +} + +QDeclarativeAttachedPropertiesFunc QDeclarativeMetaType::attachedPropertiesFuncById(int id) +{ + if (id < 0) + return 0; + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + return data->types.at(id)->attachedPropertiesFunction(); +} + +QMetaProperty QDeclarativeMetaType::defaultProperty(const QMetaObject *metaObject) +{ + int idx = metaObject->indexOfClassInfo("DefaultProperty"); + if (-1 == idx) + return QMetaProperty(); + + QMetaClassInfo info = metaObject->classInfo(idx); + if (!info.value()) + return QMetaProperty(); + + idx = metaObject->indexOfProperty(info.value()); + if (-1 == idx) + return QMetaProperty(); + + return metaObject->property(idx); +} + +QMetaProperty QDeclarativeMetaType::defaultProperty(QObject *obj) +{ + if (!obj) + return QMetaProperty(); + + const QMetaObject *metaObject = obj->metaObject(); + return defaultProperty(metaObject); +} + +QMetaMethod QDeclarativeMetaType::defaultMethod(const QMetaObject *metaObject) +{ + int idx = metaObject->indexOfClassInfo("DefaultMethod"); + if (-1 == idx) + return QMetaMethod(); + + QMetaClassInfo info = metaObject->classInfo(idx); + if (!info.value()) + return QMetaMethod(); + + idx = metaObject->indexOfMethod(info.value()); + if (-1 == idx) + return QMetaMethod(); + + return metaObject->method(idx); +} + +QMetaMethod QDeclarativeMetaType::defaultMethod(QObject *obj) +{ + if (!obj) + return QMetaMethod(); + + const QMetaObject *metaObject = obj->metaObject(); + return defaultMethod(metaObject); +} + +QDeclarativeMetaType::TypeCategory QDeclarativeMetaType::typeCategory(int userType) +{ + if (userType < 0) + return Unknown; + if (userType == QMetaType::QObjectStar) + return Object; + + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + if (userType < data->objects.size() && data->objects.testBit(userType)) + return Object; + else if (userType < data->lists.size() && data->lists.testBit(userType)) + return List; + else + return Unknown; +} + +bool QDeclarativeMetaType::isInterface(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType); +} + +const char *QDeclarativeMetaType::interfaceIId(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + QDeclarativeType *type = data->idToType.value(userType); + lock.unlock(); + if (type && type->isInterface() && type->typeId() == userType) + return type->interfaceIId(); + else + return 0; +} + +bool QDeclarativeMetaType::isList(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType); +} + +/*! + A custom string convertor allows you to specify a function pointer that + returns a variant of \a type. For example, if you have written your own icon + class that you want to support as an object property assignable in QML: + + \code + int type = qRegisterMetaType<SuperIcon>("SuperIcon"); + QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString); + \endcode + + The function pointer must be of the form: + \code + QVariant (*StringConverter)(const QString &); + \endcode + */ +void QDeclarativeMetaType::registerCustomStringConverter(int type, StringConverter converter) +{ + QWriteLocker lock(metaTypeDataLock()); + + QDeclarativeMetaTypeData *data = metaTypeData(); + if (data->stringConverters.contains(type)) + return; + data->stringConverters.insert(type, converter); +} + +/*! + Return the custom string converter for \a type, previously installed through + registerCustomStringConverter() + */ +QDeclarativeMetaType::StringConverter QDeclarativeMetaType::customStringConverter(int type) +{ + QReadLocker lock(metaTypeDataLock()); + + QDeclarativeMetaTypeData *data = metaTypeData(); + return data->stringConverters.value(type); +} + +/*! + Returns the type (if any) of URI-qualified named \a name in version specified + by \a version_major and \a version_minor. +*/ +QDeclarativeType *QDeclarativeMetaType::qmlType(const QByteArray &name, int version_major, int version_minor) +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + + QList<QDeclarativeType*> types = data->nameToType.values(name); + foreach (QDeclarativeType *t, types) { + // XXX version_major<0 just a kludge for QDeclarativePropertyPrivate::initProperty + if (version_major<0 || t->availableInVersion(version_major,version_minor)) + return t; + } + return 0; +} + +/*! + Returns the type (if any) that corresponds to the \a metaObject. Returns null if no + type is registered. +*/ +QDeclarativeType *QDeclarativeMetaType::qmlType(const QMetaObject *metaObject) +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + + return data->metaObjectToType.value(metaObject); +} + +/*! + Returns the type (if any) that corresponds to the \a metaObject in version specified + by \a version_major and \a version_minor in module specified by \a uri. Returns null if no + type is registered. +*/ +QDeclarativeType *QDeclarativeMetaType::qmlType(const QMetaObject *metaObject, const QByteArray &module, int version_major, int version_minor) +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + + QDeclarativeMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject); + while (it != data->metaObjectToType.end() && it.key() == metaObject) { + QDeclarativeType *t = *it; + if (version_major < 0 || t->availableInVersion(module, version_major,version_minor)) + return t; + ++it; + } + + return 0; +} + +/*! + Returns the type (if any) that corresponds to the QVariant::Type \a userType. + Returns null if no type is registered. +*/ +QDeclarativeType *QDeclarativeMetaType::qmlType(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + + QDeclarativeType *type = data->idToType.value(userType); + if (type && type->typeId() == userType) + return type; + else + return 0; +} + +/*! + Returns the list of registered QML type names. +*/ +QList<QByteArray> QDeclarativeMetaType::qmlTypeNames() +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + + return data->nameToType.keys(); +} + +/*! + Returns the list of registered QML types. +*/ +QList<QDeclarativeType*> QDeclarativeMetaType::qmlTypes() +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + + return data->nameToType.values(); +} + +QT_END_NAMESPACE + +#include <QtGui/qfont.h> +#include <QtGui/qpixmap.h> +#include <QtGui/qbrush.h> +#include <QtGui/qcolor.h> +#include <QtGui/qpalette.h> +#include <QtGui/qicon.h> +#include <QtGui/qimage.h> +#include <QtGui/qpolygon.h> +#include <QtGui/qregion.h> +#include <QtGui/qbitmap.h> +#include <QtGui/qcursor.h> +#include <QtGui/qsizepolicy.h> +#include <QtGui/qkeysequence.h> +#include <QtGui/qpen.h> + +//#include <QtGui/qtextlength.h> +#include <QtGui/qtextformat.h> +#include <QtGui/qmatrix.h> +#include <QtGui/qtransform.h> +#include <QtGui/qmatrix4x4.h> +#include <QtGui/qvector2d.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qvector4d.h> +#include <QtGui/qquaternion.h> + +Q_DECLARE_METATYPE(QScriptValue); + +QT_BEGIN_NAMESPACE + +bool QDeclarativeMetaType::canCopy(int type) +{ + switch(type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + case QMetaType::Long: + case QMetaType::Int: + case QMetaType::Short: + case QMetaType::Char: + case QMetaType::ULong: + case QMetaType::UInt: + case QMetaType::LongLong: + case QMetaType::ULongLong: + case QMetaType::UShort: + case QMetaType::UChar: + case QMetaType::Bool: + case QMetaType::Float: + case QMetaType::Double: + case QMetaType::QChar: + case QMetaType::QVariantMap: + case QMetaType::QVariantHash: + case QMetaType::QVariantList: + case QMetaType::QByteArray: + case QMetaType::QString: + case QMetaType::QStringList: + case QMetaType::QBitArray: + case QMetaType::QDate: + case QMetaType::QTime: + case QMetaType::QDateTime: + case QMetaType::QUrl: + case QMetaType::QLocale: + case QMetaType::QRect: + case QMetaType::QRectF: + case QMetaType::QSize: + case QMetaType::QSizeF: + case QMetaType::QLine: + case QMetaType::QLineF: + case QMetaType::QPoint: + case QMetaType::QPointF: + case QMetaType::QVector3D: +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: +#endif + case QMetaType::Void: +#ifdef QT3_SUPPORT + case QMetaType::QColorGroup: +#endif + case QMetaType::QFont: + case QMetaType::QPixmap: + case QMetaType::QBrush: + case QMetaType::QColor: + case QMetaType::QPalette: + case QMetaType::QIcon: + case QMetaType::QImage: + case QMetaType::QPolygon: + case QMetaType::QRegion: + case QMetaType::QBitmap: +#ifndef QT_NO_CURSOR + case QMetaType::QCursor: +#endif + case QMetaType::QSizePolicy: + case QMetaType::QKeySequence: + case QMetaType::QPen: + case QMetaType::QTextLength: + case QMetaType::QTextFormat: + case QMetaType::QMatrix: + case QMetaType::QTransform: + case QMetaType::QMatrix4x4: + case QMetaType::QVector2D: + case QMetaType::QVector4D: + case QMetaType::QQuaternion: + return true; + + default: + if (type == qMetaTypeId<QVariant>() || + type == qMetaTypeId<QScriptValue>() || + typeCategory(type) != Unknown) { + return true; + } + break; + } + + return false; +} + +/*! + Copies \a copy into \a data, assuming they both are of type \a type. If + \a copy is zero, a default type is copied. Returns true if the copy was + successful and false if not. + + \note This should move into QMetaType once complete + +*/ +bool QDeclarativeMetaType::copy(int type, void *data, const void *copy) +{ + if (copy) { + switch(type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + *static_cast<void **>(data) = *static_cast<void* const *>(copy); + return true; + case QMetaType::Long: + *static_cast<long *>(data) = *static_cast<const long*>(copy); + return true; + case QMetaType::Int: + *static_cast<int *>(data) = *static_cast<const int*>(copy); + return true; + case QMetaType::Short: + *static_cast<short *>(data) = *static_cast<const short*>(copy); + return true; + case QMetaType::Char: + *static_cast<char *>(data) = *static_cast<const char*>(copy); + return true; + case QMetaType::ULong: + *static_cast<ulong *>(data) = *static_cast<const ulong*>(copy); + return true; + case QMetaType::UInt: + *static_cast<uint *>(data) = *static_cast<const uint*>(copy); + return true; + case QMetaType::LongLong: + *static_cast<qlonglong *>(data) = *static_cast<const qlonglong*>(copy); + return true; + case QMetaType::ULongLong: + *static_cast<qulonglong *>(data) = *static_cast<const qulonglong*>(copy); + return true; + case QMetaType::UShort: + *static_cast<ushort *>(data) = *static_cast<const ushort*>(copy); + return true; + case QMetaType::UChar: + *static_cast<uchar *>(data) = *static_cast<const uchar*>(copy); + return true; + case QMetaType::Bool: + *static_cast<bool *>(data) = *static_cast<const bool*>(copy); + return true; + case QMetaType::Float: + *static_cast<float *>(data) = *static_cast<const float*>(copy); + return true; + case QMetaType::Double: + *static_cast<double *>(data) = *static_cast<const double*>(copy); + return true; + case QMetaType::QChar: + *static_cast<NS(QChar) *>(data) = *static_cast<const NS(QChar)*>(copy); + return true; + case QMetaType::QVariantMap: + *static_cast<NS(QVariantMap) *>(data) = *static_cast<const NS(QVariantMap)*>(copy); + return true; + case QMetaType::QVariantHash: + *static_cast<NS(QVariantHash) *>(data) = *static_cast<const NS(QVariantHash)*>(copy); + return true; + case QMetaType::QVariantList: + *static_cast<NS(QVariantList) *>(data) = *static_cast<const NS(QVariantList)*>(copy); + return true; + case QMetaType::QByteArray: + *static_cast<NS(QByteArray) *>(data) = *static_cast<const NS(QByteArray)*>(copy); + return true; + case QMetaType::QString: + *static_cast<NS(QString) *>(data) = *static_cast<const NS(QString)*>(copy); + return true; + case QMetaType::QStringList: + *static_cast<NS(QStringList) *>(data) = *static_cast<const NS(QStringList)*>(copy); + return true; + case QMetaType::QBitArray: + *static_cast<NS(QBitArray) *>(data) = *static_cast<const NS(QBitArray)*>(copy); + return true; + case QMetaType::QDate: + *static_cast<NS(QDate) *>(data) = *static_cast<const NS(QDate)*>(copy); + return true; + case QMetaType::QTime: + *static_cast<NS(QTime) *>(data) = *static_cast<const NS(QTime)*>(copy); + return true; + case QMetaType::QDateTime: + *static_cast<NS(QDateTime) *>(data) = *static_cast<const NS(QDateTime)*>(copy); + return true; + case QMetaType::QUrl: + *static_cast<NS(QUrl) *>(data) = *static_cast<const NS(QUrl)*>(copy); + return true; + case QMetaType::QLocale: + *static_cast<NS(QLocale) *>(data) = *static_cast<const NS(QLocale)*>(copy); + return true; + case QMetaType::QRect: + *static_cast<NS(QRect) *>(data) = *static_cast<const NS(QRect)*>(copy); + return true; + case QMetaType::QRectF: + *static_cast<NS(QRectF) *>(data) = *static_cast<const NS(QRectF)*>(copy); + return true; + case QMetaType::QSize: + *static_cast<NS(QSize) *>(data) = *static_cast<const NS(QSize)*>(copy); + return true; + case QMetaType::QSizeF: + *static_cast<NS(QSizeF) *>(data) = *static_cast<const NS(QSizeF)*>(copy); + return true; + case QMetaType::QLine: + *static_cast<NS(QLine) *>(data) = *static_cast<const NS(QLine)*>(copy); + return true; + case QMetaType::QLineF: + *static_cast<NS(QLineF) *>(data) = *static_cast<const NS(QLineF)*>(copy); + return true; + case QMetaType::QPoint: + *static_cast<NS(QPoint) *>(data) = *static_cast<const NS(QPoint)*>(copy); + return true; + case QMetaType::QPointF: + *static_cast<NS(QPointF) *>(data) = *static_cast<const NS(QPointF)*>(copy); + return true; + case QMetaType::QVector3D: + *static_cast<NS(QVector3D) *>(data) = *static_cast<const NS(QVector3D)*>(copy); + return true; +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + *static_cast<NS(QRegExp) *>(data) = *static_cast<const NS(QRegExp)*>(copy); + return true; +#endif + case QMetaType::Void: + return true; + + +#ifdef QT3_SUPPORT + case QMetaType::QColorGroup: + *static_cast<NS(QColorGroup) *>(data) = *static_cast<const NS(QColorGroup)*>(copy); + return true; +#endif + + case QMetaType::QFont: + *static_cast<NS(QFont) *>(data) = *static_cast<const NS(QFont)*>(copy); + return true; + case QMetaType::QPixmap: + *static_cast<NS(QPixmap) *>(data) = *static_cast<const NS(QPixmap)*>(copy); + return true; + case QMetaType::QBrush: + *static_cast<NS(QBrush) *>(data) = *static_cast<const NS(QBrush)*>(copy); + return true; + case QMetaType::QColor: + *static_cast<NS(QColor) *>(data) = *static_cast<const NS(QColor)*>(copy); + return true; + case QMetaType::QPalette: + *static_cast<NS(QPalette) *>(data) = *static_cast<const NS(QPalette)*>(copy); + return true; + case QMetaType::QIcon: + *static_cast<NS(QIcon) *>(data) = *static_cast<const NS(QIcon)*>(copy); + return true; + case QMetaType::QImage: + *static_cast<NS(QImage) *>(data) = *static_cast<const NS(QImage)*>(copy); + return true; + case QMetaType::QPolygon: + *static_cast<NS(QPolygon) *>(data) = *static_cast<const NS(QPolygon)*>(copy); + return true; + case QMetaType::QRegion: + *static_cast<NS(QRegion) *>(data) = *static_cast<const NS(QRegion)*>(copy); + return true; + case QMetaType::QBitmap: + *static_cast<NS(QBitmap) *>(data) = *static_cast<const NS(QBitmap)*>(copy); + return true; +#ifndef QT_NO_CURSOR + case QMetaType::QCursor: + *static_cast<NS(QCursor) *>(data) = *static_cast<const NS(QCursor)*>(copy); + return true; +#endif + case QMetaType::QSizePolicy: + *static_cast<NS(QSizePolicy) *>(data) = *static_cast<const NS(QSizePolicy)*>(copy); + return true; + case QMetaType::QKeySequence: + *static_cast<NS(QKeySequence) *>(data) = *static_cast<const NS(QKeySequence)*>(copy); + return true; + case QMetaType::QPen: + *static_cast<NS(QPen) *>(data) = *static_cast<const NS(QPen)*>(copy); + return true; + case QMetaType::QTextLength: + *static_cast<NS(QTextLength) *>(data) = *static_cast<const NS(QTextLength)*>(copy); + return true; + case QMetaType::QTextFormat: + *static_cast<NS(QTextFormat) *>(data) = *static_cast<const NS(QTextFormat)*>(copy); + return true; + case QMetaType::QMatrix: + *static_cast<NS(QMatrix) *>(data) = *static_cast<const NS(QMatrix)*>(copy); + return true; + case QMetaType::QTransform: + *static_cast<NS(QTransform) *>(data) = *static_cast<const NS(QTransform)*>(copy); + return true; + case QMetaType::QMatrix4x4: + *static_cast<NS(QMatrix4x4) *>(data) = *static_cast<const NS(QMatrix4x4)*>(copy); + return true; + case QMetaType::QVector2D: + *static_cast<NS(QVector2D) *>(data) = *static_cast<const NS(QVector2D)*>(copy); + return true; + case QMetaType::QVector4D: + *static_cast<NS(QVector4D) *>(data) = *static_cast<const NS(QVector4D)*>(copy); + return true; + case QMetaType::QQuaternion: + *static_cast<NS(QQuaternion) *>(data) = *static_cast<const NS(QQuaternion)*>(copy); + return true; + + default: + if (type == qMetaTypeId<QVariant>()) { + *static_cast<NS(QVariant) *>(data) = *static_cast<const NS(QVariant)*>(copy); + return true; + } else if (type == qMetaTypeId<QScriptValue>()) { + *static_cast<NS(QScriptValue) *>(data) = *static_cast<const NS(QScriptValue)*>(copy); + return true; + } else if (typeCategory(type) != Unknown) { + *static_cast<void **>(data) = *static_cast<void* const *>(copy); + return true; + } + break; + } + } else { + switch(type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + *static_cast<void **>(data) = 0; + return true; + case QMetaType::Long: + *static_cast<long *>(data) = long(0); + return true; + case QMetaType::Int: + *static_cast<int *>(data) = int(0); + return true; + case QMetaType::Short: + *static_cast<short *>(data) = short(0); + return true; + case QMetaType::Char: + *static_cast<char *>(data) = char(0); + return true; + case QMetaType::ULong: + *static_cast<ulong *>(data) = ulong(0); + return true; + case QMetaType::UInt: + *static_cast<uint *>(data) = uint(0); + return true; + case QMetaType::LongLong: + *static_cast<qlonglong *>(data) = qlonglong(0); + return true; + case QMetaType::ULongLong: + *static_cast<qulonglong *>(data) = qulonglong(0); + return true; + case QMetaType::UShort: + *static_cast<ushort *>(data) = ushort(0); + return true; + case QMetaType::UChar: + *static_cast<uchar *>(data) = uchar(0); + return true; + case QMetaType::Bool: + *static_cast<bool *>(data) = bool(false); + return true; + case QMetaType::Float: + *static_cast<float *>(data) = float(0); + return true; + case QMetaType::Double: + *static_cast<double *>(data) = double(0); + return true; + case QMetaType::QChar: + *static_cast<NS(QChar) *>(data) = NS(QChar)(); + return true; + case QMetaType::QVariantMap: + *static_cast<NS(QVariantMap) *>(data) = NS(QVariantMap)(); + return true; + case QMetaType::QVariantHash: + *static_cast<NS(QVariantHash) *>(data) = NS(QVariantHash)(); + return true; + case QMetaType::QVariantList: + *static_cast<NS(QVariantList) *>(data) = NS(QVariantList)(); + return true; + case QMetaType::QByteArray: + *static_cast<NS(QByteArray) *>(data) = NS(QByteArray)(); + return true; + case QMetaType::QString: + *static_cast<NS(QString) *>(data) = NS(QString)(); + return true; + case QMetaType::QStringList: + *static_cast<NS(QStringList) *>(data) = NS(QStringList)(); + return true; + case QMetaType::QBitArray: + *static_cast<NS(QBitArray) *>(data) = NS(QBitArray)(); + return true; + case QMetaType::QDate: + *static_cast<NS(QDate) *>(data) = NS(QDate)(); + return true; + case QMetaType::QTime: + *static_cast<NS(QTime) *>(data) = NS(QTime)(); + return true; + case QMetaType::QDateTime: + *static_cast<NS(QDateTime) *>(data) = NS(QDateTime)(); + return true; + case QMetaType::QUrl: + *static_cast<NS(QUrl) *>(data) = NS(QUrl)(); + return true; + case QMetaType::QLocale: + *static_cast<NS(QLocale) *>(data) = NS(QLocale)(); + return true; + case QMetaType::QRect: + *static_cast<NS(QRect) *>(data) = NS(QRect)(); + return true; + case QMetaType::QRectF: + *static_cast<NS(QRectF) *>(data) = NS(QRectF)(); + return true; + case QMetaType::QSize: + *static_cast<NS(QSize) *>(data) = NS(QSize)(); + return true; + case QMetaType::QSizeF: + *static_cast<NS(QSizeF) *>(data) = NS(QSizeF)(); + return true; + case QMetaType::QLine: + *static_cast<NS(QLine) *>(data) = NS(QLine)(); + return true; + case QMetaType::QLineF: + *static_cast<NS(QLineF) *>(data) = NS(QLineF)(); + return true; + case QMetaType::QPoint: + *static_cast<NS(QPoint) *>(data) = NS(QPoint)(); + return true; + case QMetaType::QPointF: + *static_cast<NS(QPointF) *>(data) = NS(QPointF)(); + return true; + case QMetaType::QVector3D: + *static_cast<NS(QVector3D) *>(data) = NS(QVector3D)(); + return true; +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + *static_cast<NS(QRegExp) *>(data) = NS(QRegExp)(); + return true; +#endif + case QMetaType::Void: + return true; + +#ifdef QT3_SUPPORT + case QMetaType::QColorGroup: + *static_cast<NS(QColorGroup) *>(data) = NS(QColorGroup)(); + return true; +#endif + + case QMetaType::QFont: + *static_cast<NS(QFont) *>(data) = NS(QFont)(); + return true; + case QMetaType::QPixmap: + *static_cast<NS(QPixmap) *>(data) = NS(QPixmap)(); + return true; + case QMetaType::QBrush: + *static_cast<NS(QBrush) *>(data) = NS(QBrush)(); + return true; + case QMetaType::QColor: + *static_cast<NS(QColor) *>(data) = NS(QColor)(); + return true; + case QMetaType::QPalette: + *static_cast<NS(QPalette) *>(data) = NS(QPalette)(); + return true; + case QMetaType::QIcon: + *static_cast<NS(QIcon) *>(data) = NS(QIcon)(); + return true; + case QMetaType::QImage: + *static_cast<NS(QImage) *>(data) = NS(QImage)(); + return true; + case QMetaType::QPolygon: + *static_cast<NS(QPolygon) *>(data) = NS(QPolygon)(); + return true; + case QMetaType::QRegion: + *static_cast<NS(QRegion) *>(data) = NS(QRegion)(); + return true; + case QMetaType::QBitmap: + *static_cast<NS(QBitmap) *>(data) = NS(QBitmap)(); + return true; +#ifndef QT_NO_CURSOR + case QMetaType::QCursor: + *static_cast<NS(QCursor) *>(data) = NS(QCursor)(); + return true; +#endif + case QMetaType::QSizePolicy: + *static_cast<NS(QSizePolicy) *>(data) = NS(QSizePolicy)(); + return true; + case QMetaType::QKeySequence: + *static_cast<NS(QKeySequence) *>(data) = NS(QKeySequence)(); + return true; + case QMetaType::QPen: + *static_cast<NS(QPen) *>(data) = NS(QPen)(); + return true; + case QMetaType::QTextLength: + *static_cast<NS(QTextLength) *>(data) = NS(QTextLength)(); + return true; + case QMetaType::QTextFormat: + *static_cast<NS(QTextFormat) *>(data) = NS(QTextFormat)(); + return true; + case QMetaType::QMatrix: + *static_cast<NS(QMatrix) *>(data) = NS(QMatrix)(); + return true; + case QMetaType::QTransform: + *static_cast<NS(QTransform) *>(data) = NS(QTransform)(); + return true; + case QMetaType::QMatrix4x4: + *static_cast<NS(QMatrix4x4) *>(data) = NS(QMatrix4x4)(); + return true; + case QMetaType::QVector2D: + *static_cast<NS(QVector2D) *>(data) = NS(QVector2D)(); + return true; + case QMetaType::QVector4D: + *static_cast<NS(QVector4D) *>(data) = NS(QVector4D)(); + return true; + case QMetaType::QQuaternion: + *static_cast<NS(QQuaternion) *>(data) = NS(QQuaternion)(); + return true; + default: + if (type == qMetaTypeId<QVariant>()) { + *static_cast<NS(QVariant) *>(data) = NS(QVariant)(); + return true; + } else if (type == qMetaTypeId<QScriptValue>()) { + *static_cast<NS(QScriptValue) *>(data) = NS(QScriptValue)(); + return true; + } else if (typeCategory(type) != Unknown) { + *static_cast<void **>(data) = 0; + return true; + } + break; + } + } + + return false; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h new file mode 100644 index 00000000..8af72737 --- /dev/null +++ b/src/declarative/qml/qdeclarativemetatype_p.h @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEMETATYPE_P_H +#define QDECLARATIVEMETATYPE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarative.h" + +#include <QtCore/qglobal.h> +#include <QtCore/qvariant.h> +#include <QtCore/qbitarray.h> +#include <private/qdeclarativeglobal_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeType; +class QDeclarativeCustomParser; +class QDeclarativeTypePrivate; + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeMetaType +{ +public: + static bool canCopy(int type); + static bool copy(int type, void *data, const void *copy = 0); + + static QList<QByteArray> qmlTypeNames(); + static QList<QDeclarativeType*> qmlTypes(); + + static QDeclarativeType *qmlType(const QByteArray &, int, int); + static QDeclarativeType *qmlType(const QMetaObject *); + static QDeclarativeType *qmlType(const QMetaObject *metaObject, const QByteArray &module, int version_major, int version_minor); + static QDeclarativeType *qmlType(int); + + static QMetaProperty defaultProperty(const QMetaObject *); + static QMetaProperty defaultProperty(QObject *); + static QMetaMethod defaultMethod(const QMetaObject *); + static QMetaMethod defaultMethod(QObject *); + + static bool isQObject(int); + static QObject *toQObject(const QVariant &, bool *ok = 0); + + static int listType(int); + static int attachedPropertiesFuncId(const QMetaObject *); + static QDeclarativeAttachedPropertiesFunc attachedPropertiesFuncById(int); + + enum TypeCategory { Unknown, Object, List }; + static TypeCategory typeCategory(int); + + static bool isInterface(int); + static const char *interfaceIId(int); + static bool isList(int); + + typedef QVariant (*StringConverter)(const QString &); + static void registerCustomStringConverter(int, StringConverter); + static StringConverter customStringConverter(int); + + static bool isModule(const QByteArray &module, int versionMajor, int versionMinor); + + static QList<QDeclarativePrivate::AutoParentFunction> parentFunctions(); +}; + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeType +{ +public: + QByteArray typeName() const; + QByteArray qmlTypeName() const; + + QByteArray module() const; + int majorVersion() const; + int minorVersion() const; + + bool availableInVersion(int vmajor, int vminor) const; + bool availableInVersion(const QByteArray &module, int vmajor, int vminor) const; + + QObject *create() const; + void create(QObject **, void **, size_t) const; + + typedef void (*CreateFunc)(void *); + CreateFunc createFunction() const; + int createSize() const; + + QDeclarativeCustomParser *customParser() const; + + bool isCreatable() const; + bool isExtendedType() const; + QString noCreationReason() const; + + bool isInterface() const; + int typeId() const; + int qListTypeId() const; + + const QMetaObject *metaObject() const; + const QMetaObject *baseMetaObject() const; + int metaObjectRevision() const; + bool containsRevisionedAttributes() const; + + QDeclarativeAttachedPropertiesFunc attachedPropertiesFunction() const; + const QMetaObject *attachedPropertiesType() const; + int attachedPropertiesId() const; + + int parserStatusCast() const; + QVariant fromObject(QObject *) const; + const char *interfaceIId() const; + int propertyValueSourceCast() const; + int propertyValueInterceptorCast() const; + + int index() const; + +private: + QDeclarativeType *superType() const; + friend class QDeclarativeTypePrivate; + friend struct QDeclarativeMetaTypeData; + friend int registerType(const QDeclarativePrivate::RegisterType &); + friend int registerInterface(const QDeclarativePrivate::RegisterInterface &); + QDeclarativeType(int, const QDeclarativePrivate::RegisterInterface &); + QDeclarativeType(int, const QDeclarativePrivate::RegisterType &); + ~QDeclarativeType(); + + QDeclarativeTypePrivate *d; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEMETATYPE_P_H + diff --git a/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.cpp b/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.cpp new file mode 100644 index 00000000..fd08badd --- /dev/null +++ b/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativenetworkaccessmanagerfactory.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDeclarativeNetworkAccessManagerFactory + \since 4.7 + \brief The QDeclarativeNetworkAccessManagerFactory class creates QNetworkAccessManager instances for a QML engine. + + A QML engine uses QNetworkAccessManager for all network access. + By implementing a factory, it is possible to provide the QML engine + with custom QNetworkAccessManager instances with specialized caching, + proxy and cookies support. + + To implement a factory, subclass QDeclarativeNetworkAccessManagerFactory and + implement the virtual create() method, then assign it to the relevant QML + engine using QDeclarativeEngine::setNetworkAccessManagerFactory(). + + Note the QML engine may create QNetworkAccessManager instances + from multiple threads. Because of this, the implementation of the create() + method must be \l{Reentrancy and Thread-Safety}{reentrant}. In addition, + the developer should be careful if the signals of the object to be + returned from create() are connected to the slots of an object that may + be created in a different thread: + + \list + \o The QML engine internally handles all requests, and cleans up any + QNetworkReply objects it creates. Receiving the + QNetworkAccessManager::finished() signal in another thread may not + provide the receiver with a valid reply object if it has already + been deleted. + \o Authentication details provided to QNetworkAccessManager::authenticationRequired() + must be provided immediately, so this signal cannot be connected as a + Qt::QueuedConnection (or as the default Qt::AutoConnection from another + thread). + \endlist + + For more information about signals and threads, see + \l {Threads and QObjects} and \l {Signals and Slots Across Threads}. + + \sa {declarative/cppextensions/networkaccessmanagerfactory}{NetworkAccessManagerFactory example} +*/ + +/*! + Destroys the factory. The default implementation does nothing. + */ +QDeclarativeNetworkAccessManagerFactory::~QDeclarativeNetworkAccessManagerFactory() +{ +} + +/*! + \fn QNetworkAccessManager *QDeclarativeNetworkAccessManagerFactory::create(QObject *parent) + + Creates and returns a network access manager with the specified \a parent. + This method must return a new QNetworkAccessManager instance each time + it is called. + + Note: this method may be called by multiple threads, so ensure the + implementation of this method is reentrant. +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.h b/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.h new file mode 100644 index 00000000..c55f8e30 --- /dev/null +++ b/src/declarative/qml/qdeclarativenetworkaccessmanagerfactory.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVENETWORKACCESSMANAGERFACTORY_H +#define QDECLARATIVENETWORKACCESSMANAGERFACTORY_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QNetworkAccessManager; +class Q_DECLARATIVE_EXPORT QDeclarativeNetworkAccessManagerFactory +{ +public: + virtual ~QDeclarativeNetworkAccessManagerFactory(); + virtual QNetworkAccessManager *create(QObject *parent) = 0; + +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVENETWORKACCESSMANAGERFACTORY_H diff --git a/src/declarative/qml/qdeclarativenotifier.cpp b/src/declarative/qml/qdeclarativenotifier.cpp new file mode 100644 index 00000000..64731dee --- /dev/null +++ b/src/declarative/qml/qdeclarativenotifier.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativenotifier_p.h" +#include "private/qdeclarativeproperty_p.h" + +QT_BEGIN_NAMESPACE + +void QDeclarativeNotifier::emitNotify(QDeclarativeNotifierEndpoint *endpoint) +{ + QDeclarativeNotifierEndpoint::Notifier *n = endpoint->asNotifier(); + + QDeclarativeNotifierEndpoint **oldDisconnected = n->disconnected; + n->disconnected = &endpoint; + + if (n->next) + emitNotify(n->next); + + if (endpoint) { + void *args[] = { 0 }; + + QMetaObject::metacall(endpoint->target, QMetaObject::InvokeMetaMethod, + endpoint->targetMethod, args); + + if (endpoint) + endpoint->asNotifier()->disconnected = oldDisconnected; + } + + if (oldDisconnected) *oldDisconnected = endpoint; +} + +void QDeclarativeNotifierEndpoint::connect(QObject *source, int sourceSignal) +{ + Signal *s = toSignal(); + + if (s->source == source && s->sourceSignal == sourceSignal) + return; + + disconnect(); + + QDeclarativePropertyPrivate::connect(source, sourceSignal, target, targetMethod); + + s->source = source; + s->sourceSignal = sourceSignal; +} + +void QDeclarativeNotifierEndpoint::copyAndClear(QDeclarativeNotifierEndpoint &other) +{ + other.disconnect(); + + other.target = target; + other.targetMethod = targetMethod; + + if (!isConnected()) + return; + + if (SignalType == type) { + Signal *other_s = other.toSignal(); + Signal *s = asSignal(); + + other_s->source = s->source; + other_s->sourceSignal = s->sourceSignal; + s->source = 0; + } else if(NotifierType == type) { + Notifier *other_n = other.toNotifier(); + Notifier *n = asNotifier(); + + other_n->notifier = n->notifier; + other_n->disconnected = n->disconnected; + if (other_n->disconnected) *other_n->disconnected = &other; + + if (n->next) { + other_n->next = n->next; + n->next->asNotifier()->prev = &other_n->next; + } + other_n->prev = n->prev; + *other_n->prev = &other; + + n->prev = 0; + n->next = 0; + n->disconnected = 0; + n->notifier = 0; + } +} + + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativenotifier_p.h b/src/declarative/qml/qdeclarativenotifier_p.h new file mode 100644 index 00000000..433022f8 --- /dev/null +++ b/src/declarative/qml/qdeclarativenotifier_p.h @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVENOTIFIER_P_H +#define QDECLARATIVENOTIFIER_P_H + +#include "private/qdeclarativeguard_p.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativeNotifierEndpoint; +class QDeclarativeNotifier +{ +public: + inline QDeclarativeNotifier(); + inline ~QDeclarativeNotifier(); + inline void notify(); + +private: + friend class QDeclarativeNotifierEndpoint; + + static void emitNotify(QDeclarativeNotifierEndpoint *); + QDeclarativeNotifierEndpoint *endpoints; +}; + +class QDeclarativeNotifierEndpoint +{ +public: + inline QDeclarativeNotifierEndpoint(); + inline QDeclarativeNotifierEndpoint(QObject *t, int m); + inline ~QDeclarativeNotifierEndpoint(); + + QObject *target; + int targetMethod; + + inline bool isConnected(); + inline bool isConnected(QObject *source, int sourceSignal); + inline bool isConnected(QDeclarativeNotifier *); + + void connect(QObject *source, int sourceSignal); + inline void connect(QDeclarativeNotifier *); + inline void disconnect(); + + void copyAndClear(QDeclarativeNotifierEndpoint &other); + +private: + friend class QDeclarativeNotifier; + + struct Signal { + QDeclarativeGuard<QObject> source; + int sourceSignal; + }; + + struct Notifier { + QDeclarativeNotifier *notifier; + QDeclarativeNotifierEndpoint **disconnected; + + QDeclarativeNotifierEndpoint *next; + QDeclarativeNotifierEndpoint **prev; + }; + + enum { InvalidType, SignalType, NotifierType } type; + union { + struct { + Signal *signal; + union { + char signalData[sizeof(Signal)]; + qint64 q_for_alignment_1; + double q_for_alignment_2; + }; + } signal; + Notifier notifier; + }; + + inline Notifier *toNotifier(); + inline Notifier *asNotifier(); + inline Signal *toSignal(); + inline Signal *asSignal(); +}; + +QDeclarativeNotifier::QDeclarativeNotifier() +: endpoints(0) +{ +} + +QDeclarativeNotifier::~QDeclarativeNotifier() +{ + QDeclarativeNotifierEndpoint *endpoint = endpoints; + while (endpoint) { + QDeclarativeNotifierEndpoint::Notifier *n = endpoint->asNotifier(); + endpoint = n->next; + + n->next = 0; + n->prev = 0; + n->notifier = 0; + if (n->disconnected) *n->disconnected = 0; + n->disconnected = 0; + } + endpoints = 0; +} + +void QDeclarativeNotifier::notify() +{ + if (endpoints) emitNotify(endpoints); +} + +QDeclarativeNotifierEndpoint::QDeclarativeNotifierEndpoint() +: target(0), targetMethod(0), type(InvalidType) +{ +} + +QDeclarativeNotifierEndpoint::QDeclarativeNotifierEndpoint(QObject *t, int m) +: target(t), targetMethod(m), type(InvalidType) +{ +} + +QDeclarativeNotifierEndpoint::~QDeclarativeNotifierEndpoint() +{ + disconnect(); + if (SignalType == type) { + Signal *s = asSignal(); + s->~Signal(); + } +} + +bool QDeclarativeNotifierEndpoint::isConnected() +{ + if (SignalType == type) { + return asSignal()->source; + } else if (NotifierType == type) { + return asNotifier()->notifier; + } else { + return false; + } +} + +bool QDeclarativeNotifierEndpoint::isConnected(QObject *source, int sourceSignal) +{ + return SignalType == type && asSignal()->source == source && asSignal()->sourceSignal == sourceSignal; +} + +bool QDeclarativeNotifierEndpoint::isConnected(QDeclarativeNotifier *notifier) +{ + return NotifierType == type && asNotifier()->notifier == notifier; +} + +void QDeclarativeNotifierEndpoint::connect(QDeclarativeNotifier *notifier) +{ + Notifier *n = toNotifier(); + + if (n->notifier == notifier) + return; + + disconnect(); + + n->next = notifier->endpoints; + if (n->next) { n->next->asNotifier()->prev = &n->next; } + notifier->endpoints = this; + n->prev = ¬ifier->endpoints; + n->notifier = notifier; +} + +void QDeclarativeNotifierEndpoint::disconnect() +{ + if (type == SignalType) { + Signal *s = asSignal(); + if (s->source) { + QMetaObject::disconnectOne(s->source, s->sourceSignal, target, targetMethod); + s->source = 0; + } + } else if (type == NotifierType) { + Notifier *n = asNotifier(); + + if (n->next) n->next->asNotifier()->prev = n->prev; + if (n->prev) *n->prev = n->next; + if (n->disconnected) *n->disconnected = 0; + n->next = 0; + n->prev = 0; + n->disconnected = 0; + n->notifier = 0; + } +} + +QDeclarativeNotifierEndpoint::Notifier *QDeclarativeNotifierEndpoint::toNotifier() +{ + if (NotifierType == type) + return asNotifier(); + + if (SignalType == type) { + disconnect(); + Signal *s = asSignal(); + s->~Signal(); + } + + type = NotifierType; + Notifier *n = asNotifier(); + n->next = 0; + n->prev = 0; + n->disconnected = 0; + n->notifier = 0; + return n; +} + +QDeclarativeNotifierEndpoint::Notifier *QDeclarativeNotifierEndpoint::asNotifier() +{ + Q_ASSERT(type == NotifierType); + return ¬ifier; +} + +QDeclarativeNotifierEndpoint::Signal *QDeclarativeNotifierEndpoint::toSignal() +{ + if (SignalType == type) + return asSignal(); + + disconnect(); + signal.signal = new (&signal.signalData) Signal; + type = SignalType; + return signal.signal; +} + +QDeclarativeNotifierEndpoint::Signal *QDeclarativeNotifierEndpoint::asSignal() +{ + Q_ASSERT(type == SignalType); + return signal.signal; +} + +QT_END_NAMESPACE + +#endif // QDECLARATIVENOTIFIER_P_H + diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp new file mode 100644 index 00000000..e3d01c39 --- /dev/null +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -0,0 +1,1242 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativeobjectscriptclass_p.h" + +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativedata_p.h" +#include "private/qdeclarativetypenamescriptclass_p.h" +#include "private/qdeclarativelistscriptclass_p.h" +#include "private/qdeclarativebinding_p.h" +#include "private/qdeclarativeguard_p.h" +#include "private/qdeclarativevmemetaobject_p.h" + +#include <QtCore/qtimer.h> +#include <QtCore/qvarlengtharray.h> +#include <QtScript/qscriptcontextinfo.h> + +Q_DECLARE_METATYPE(QScriptValue) + +#if defined(__GNUC__) +# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 +// The code in this file does not violate strict aliasing, but GCC thinks it does +// so turn off the warnings for us to have a clean build +# pragma GCC diagnostic ignored "-Wstrict-aliasing" +# endif +#endif + +QT_BEGIN_NAMESPACE + +struct ObjectData : public QScriptDeclarativeClass::Object { + ObjectData(QObject *o, int t) : object(o), type(t) { + if (o) { + QDeclarativeData *ddata = QDeclarativeData::get(object, true); + if (ddata) ddata->objectDataRefCount++; + } + } + + virtual ~ObjectData() { + if (object && !object->parent()) { + QDeclarativeData *ddata = QDeclarativeData::get(object, false); + if (ddata && !ddata->indestructible && 0 == --ddata->objectDataRefCount) + object->deleteLater(); + } + } + + QDeclarativeGuard<QObject> object; + int type; +}; + +/* + The QDeclarativeObjectScriptClass handles property access for QObjects + via QtScript. It is also used to provide a more useful API in + QtScript for QML. + */ +QDeclarativeObjectScriptClass::QDeclarativeObjectScriptClass(QDeclarativeEngine *bindEngine) +: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), + methods(bindEngine), lastData(0), engine(bindEngine) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + m_destroy = scriptEngine->newFunction(destroy); + m_destroyId = createPersistentIdentifier(QLatin1String("destroy")); + m_toString = scriptEngine->newFunction(tostring); + m_toStringId = createPersistentIdentifier(QLatin1String("toString")); +} + +QDeclarativeObjectScriptClass::~QDeclarativeObjectScriptClass() +{ +} + +QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + if (!object) + return scriptEngine->nullValue(); +// return newObject(scriptEngine, this, new ObjectData(object, type)); + + if (QObjectPrivate::get(object)->wasDeleted) + return scriptEngine->undefinedValue(); + + QDeclarativeData *ddata = QDeclarativeData::get(object, true); + + if (!ddata) { + return scriptEngine->undefinedValue(); + } else if (!ddata->indestructible && !object->parent()) { + return newObject(scriptEngine, this, new ObjectData(object, type)); + } else if (!ddata->scriptValue) { + ddata->scriptValue = new QScriptValue(newObject(scriptEngine, this, new ObjectData(object, type))); + return *ddata->scriptValue; + } else if (ddata->scriptValue->engine() == QDeclarativeEnginePrivate::getScriptEngine(engine)) { + return *ddata->scriptValue; + } else { + return newObject(scriptEngine, this, new ObjectData(object, type)); + } +} + +QObject *QDeclarativeObjectScriptClass::toQObject(const QScriptValue &value) const +{ + return value.toQObject(); +} + +int QDeclarativeObjectScriptClass::objectType(const QScriptValue &value) const +{ + if (scriptClass(value) != this) + return QVariant::Invalid; + + Object *o = object(value); + return ((ObjectData*)(o))->type; +} + +QScriptClass::QueryFlags +QDeclarativeObjectScriptClass::queryProperty(Object *object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + return queryProperty(toQObject(object), name, flags, 0); +} + +QScriptClass::QueryFlags +QDeclarativeObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, + QScriptClass::QueryFlags flags, QDeclarativeContextData *evalContext, + QueryHints hints) +{ + Q_UNUSED(flags); + lastData = 0; + lastTNData = 0; + + if (name == m_destroyId.identifier || + name == m_toStringId.identifier) + return QScriptClass::HandlesReadAccess; + + if (!obj) + return 0; + + QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine); + lastData = QDeclarativePropertyCache::property(engine, obj, name, local); + if ((hints & ImplicitObject) && lastData && lastData->revision != 0) { + + QDeclarativeData *ddata = QDeclarativeData::get(obj); + if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(lastData)) + return 0; + } + + if (lastData) + return QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; + + if (!(hints & SkipAttachedProperties)) { + if (!evalContext && context()) { + // Global object, QScriptContext activation object, QDeclarativeContext object + QScriptValue scopeNode = scopeChainValue(context(), -3); + if (scopeNode.isValid()) { + Q_ASSERT(scriptClass(scopeNode) == enginePrivate->contextClass); + + evalContext = enginePrivate->contextClass->contextFromValue(scopeNode); + } + } + + if (evalContext && evalContext->imports) { + QDeclarativeTypeNameCache::Data *data = evalContext->imports->data(name); + if (data) { + lastTNData = data; + return QScriptClass::HandlesReadAccess; + } + } + } + + if (!(hints & ImplicitObject)) { + local.coreIndex = -1; + lastData = &local; + return QScriptClass::HandlesWriteAccess; + } + + return 0; +} + +QDeclarativeObjectScriptClass::Value +QDeclarativeObjectScriptClass::property(Object *object, const Identifier &name) +{ + return property(toQObject(object), name); +} + +QDeclarativeObjectScriptClass::Value +QDeclarativeObjectScriptClass::property(QObject *obj, const Identifier &name) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + if (name == m_destroyId.identifier) + return Value(scriptEngine, m_destroy); + else if (name == m_toStringId.identifier) + return Value(scriptEngine, m_toString); + + if (lastData && !lastData->isValid()) + return Value(); + + Q_ASSERT(obj); + + QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); + + if (lastTNData) { + + if (lastTNData->type) + return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->type)); + else + return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->typeNamespace)); + + } else if (lastData->flags & QDeclarativePropertyCache::Data::IsFunction) { + if (lastData->flags & QDeclarativePropertyCache::Data::IsVMEFunction) { + return Value(scriptEngine, ((QDeclarativeVMEMetaObject *)(obj->metaObject()))->vmeMethod(lastData->coreIndex)); + } else { + // Uncomment to use QtScript method call logic + // QScriptValue sobj = scriptEngine->newQObject(obj); + // return Value(scriptEngine, sobj.property(toString(name))); + return Value(scriptEngine, methods.newMethod(obj, lastData)); + } + } else { + if (enginePriv->captureProperties && !(lastData->flags & QDeclarativePropertyCache::Data::IsConstant)) { + if (lastData->coreIndex == 0) { + enginePriv->capturedProperties << + QDeclarativeEnginePrivate::CapturedProperty(QDeclarativeData::get(obj, true)->objectNameNotifier()); + } else { + enginePriv->capturedProperties << + QDeclarativeEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex); + } + } + + if (QDeclarativeValueTypeFactory::isValueType((uint)lastData->propType)) { + QDeclarativeValueType *valueType = enginePriv->valueTypes[lastData->propType]; + if (valueType) + return Value(scriptEngine, enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType)); + } + + if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) { + return Value(scriptEngine, enginePriv->listClass->newList(obj, lastData->coreIndex, lastData->propType)); + } else if (lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) { + QObject *rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, newQObject(rv, lastData->propType)); + } else if (lastData->flags & QDeclarativePropertyCache::Data::IsQScriptValue) { + QScriptValue rv = scriptEngine->nullValue(); + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::QReal) { + qreal rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::Int || lastData->flags & QDeclarativePropertyCache::Data::IsEnumType) { + int rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::Bool) { + bool rv = false; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::QString) { + QString rv; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::UInt) { + uint rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::Float) { + float rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else if (lastData->propType == QMetaType::Double) { + double rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); + return Value(scriptEngine, rv); + } else { + QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); + return Value(scriptEngine, enginePriv->scriptValueFromVariant(var)); + } + } +} + +void QDeclarativeObjectScriptClass::setProperty(Object *object, + const Identifier &name, + const QScriptValue &value) +{ + return setProperty(toQObject(object), name, value, context()); +} + +void QDeclarativeObjectScriptClass::setProperty(QObject *obj, + const Identifier &name, + const QScriptValue &value, + QScriptContext *context, + QDeclarativeContextData *evalContext) +{ + Q_UNUSED(name); + + Q_ASSERT(obj); + Q_ASSERT(lastData); + Q_ASSERT(context); + + if (!lastData->isValid()) { + QString error = QLatin1String("Cannot assign to non-existent property \"") + + toString(name) + QLatin1Char('\"'); + context->throwError(error); + return; + } + + if (!(lastData->flags & QDeclarativePropertyCache::Data::IsWritable) && + !(lastData->flags & QDeclarativePropertyCache::Data::IsQList)) { + QString error = QLatin1String("Cannot assign to read-only property \"") + + toString(name) + QLatin1Char('\"'); + context->throwError(error); + return; + } + + QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); + + if (!evalContext) { + // Global object, QScriptContext activation object, QDeclarativeContext object + QScriptValue scopeNode = scopeChainValue(context, -3); + if (scopeNode.isValid()) { + Q_ASSERT(scriptClass(scopeNode) == enginePriv->contextClass); + + evalContext = enginePriv->contextClass->contextFromValue(scopeNode); + } + } + + QDeclarativeBinding *newBinding = 0; + if (value.isFunction() && !value.isRegExp()) { + QScriptContextInfo ctxtInfo(context); + QDeclarativePropertyCache::ValueTypeData valueTypeData; + + newBinding = new QDeclarativeBinding(value, obj, evalContext); + newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber()); + newBinding->setTarget(QDeclarativePropertyPrivate::restore(*lastData, valueTypeData, obj, evalContext)); + if (newBinding->expression().contains(QLatin1String("this"))) + newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject); + } + + QDeclarativeAbstractBinding *delBinding = + QDeclarativePropertyPrivate::setBinding(obj, lastData->coreIndex, -1, newBinding); + if (delBinding) + delBinding->destroy(); + + if (value.isNull() && lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) { + QObject *o = 0; + int status = -1; + int flags = 0; + void *argv[] = { &o, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, argv); + } else if (value.isUndefined() && lastData->flags & QDeclarativePropertyCache::Data::IsResettable) { + void *a[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::ResetProperty, lastData->coreIndex, a); + } else if (value.isUndefined() && lastData->propType == qMetaTypeId<QVariant>()) { + QDeclarativePropertyPrivate::write(obj, *lastData, QVariant(), evalContext); + } else if (value.isUndefined()) { + QString error = QLatin1String("Cannot assign [undefined] to ") + + QLatin1String(QMetaType::typeName(lastData->propType)); + context->throwError(error); + } else if (value.isFunction() && !value.isRegExp()) { + // this is handled by the binding creation above + } else { + //### expand optimization for other known types + if (lastData->propType == QMetaType::Int && value.isNumber()) { + int rawValue = qRound(value.toNumber()); + int status = -1; + int flags = 0; + void *a[] = { (void *)&rawValue, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, + lastData->coreIndex, a); + return; + } else if (lastData->propType == QMetaType::QReal && value.isNumber()) { + qreal rawValue = qreal(value.toNumber()); + int status = -1; + int flags = 0; + void *a[] = { (void *)&rawValue, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, + lastData->coreIndex, a); + return; + } else if (lastData->propType == QMetaType::QString && value.isString()) { + const QString &rawValue = value.toString(); + int status = -1; + int flags = 0; + void *a[] = { (void *)&rawValue, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, + lastData->coreIndex, a); + return; + } + + QVariant v; + if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) + v = enginePriv->scriptValueToVariant(value, qMetaTypeId<QList<QObject *> >()); + else + v = enginePriv->scriptValueToVariant(value, lastData->propType); + + if (!QDeclarativePropertyPrivate::write(obj, *lastData, v, evalContext)) { + const char *valueType = 0; + if (v.userType() == QVariant::Invalid) valueType = "null"; + else valueType = QMetaType::typeName(v.userType()); + + QString error = QLatin1String("Cannot assign ") + + QLatin1String(valueType) + + QLatin1String(" to ") + + QLatin1String(QMetaType::typeName(lastData->propType)); + context->throwError(error); + } + } +} + +bool QDeclarativeObjectScriptClass::isQObject() const +{ + return true; +} + +QObject *QDeclarativeObjectScriptClass::toQObject(Object *object, bool *ok) +{ + if (ok) *ok = true; + + ObjectData *data = (ObjectData*)object; + return data->object.data(); +} + +QScriptValue QDeclarativeObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *) +{ + QObject* obj = context->thisObject().toQObject(); + + QString ret; + if(obj){ + QString objectName = obj->objectName(); + + ret += QString::fromUtf8(obj->metaObject()->className()); + ret += QLatin1String("(0x"); + ret += QString::number((quintptr)obj,16); + + if (!objectName.isEmpty()) { + ret += QLatin1String(", \""); + ret += objectName; + ret += QLatin1Char('\"'); + } + + ret += QLatin1Char(')'); + }else{ + ret += QLatin1String("null"); + } + return QScriptValue(ret); +} + +QScriptValue QDeclarativeObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine) +{ + QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine); + QScriptValue that = context->thisObject(); + + if (scriptClass(that) != p->objectClass) + return engine->undefinedValue(); + + ObjectData *data = (ObjectData *)p->objectClass->object(that); + if (!data->object) + return engine->undefinedValue(); + + QDeclarativeData *ddata = QDeclarativeData::get(data->object, false); + if (!ddata || ddata->indestructible) + return engine->currentContext()->throwError(QLatin1String("Invalid attempt to destroy() an indestructible object")); + + QObject *obj = data->object; + int delay = 0; + if (context->argumentCount() > 0) + delay = context->argument(0).toInt32(); + if (delay > 0) + QTimer::singleShot(delay, obj, SLOT(deleteLater())); + else + obj->deleteLater(); + + return engine->undefinedValue(); +} + +QStringList QDeclarativeObjectScriptClass::propertyNames(Object *object) +{ + QObject *obj = toQObject(object); + if (!obj) + return QStringList(); + + QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine); + + QDeclarativePropertyCache *cache = 0; + QDeclarativeData *ddata = QDeclarativeData::get(obj); + if (ddata) + cache = ddata->propertyCache; + if (!cache) { + cache = enginePrivate->cache(obj); + if (cache) { + if (ddata) { cache->addref(); ddata->propertyCache = cache; } + } else { + // Not cachable - fall back to QMetaObject (eg. dynamic meta object) + // XXX QDeclarativeOpenMetaObject has a cache, so this is suboptimal. + // XXX This is a workaround for QTBUG-9420. + const QMetaObject *mo = obj->metaObject(); + QStringList r; + int pc = mo->propertyCount(); + int po = mo->propertyOffset(); + for (int i=po; i<pc; ++i) + r += QString::fromUtf8(mo->property(i).name()); + return r; + } + } + return cache->propertyNames(); +} + +bool QDeclarativeObjectScriptClass::compare(Object *o1, Object *o2) +{ + ObjectData *d1 = (ObjectData *)o1; + ObjectData *d2 = (ObjectData *)o2; + + return d1 == d2 || d1->object == d2->object; +} + +struct MethodData : public QScriptDeclarativeClass::Object { + MethodData(QObject *o, const QDeclarativePropertyCache::Data &d) : object(o), data(d) {} + + QDeclarativeGuard<QObject> object; + QDeclarativePropertyCache::Data data; +}; + +QDeclarativeObjectMethodScriptClass::QDeclarativeObjectMethodScriptClass(QDeclarativeEngine *bindEngine) +: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), + engine(bindEngine) +{ + qRegisterMetaType<QList<QObject *> >("QList<QObject *>"); + + setSupportsCall(true); + + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + m_connect = scriptEngine->newFunction(connect); + m_connectId = createPersistentIdentifier(QLatin1String("connect")); + m_disconnect = scriptEngine->newFunction(disconnect); + m_disconnectId = createPersistentIdentifier(QLatin1String("disconnect")); +} + +QDeclarativeObjectMethodScriptClass::~QDeclarativeObjectMethodScriptClass() +{ +} + +QScriptValue QDeclarativeObjectMethodScriptClass::newMethod(QObject *object, const QDeclarativePropertyCache::Data *method) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, new MethodData(object, *method)); +} + +QScriptValue QDeclarativeObjectMethodScriptClass::connect(QScriptContext *context, QScriptEngine *engine) +{ + QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine); + + QScriptValue that = context->thisObject(); + if (&p->objectClass->methods != scriptClass(that)) + return engine->undefinedValue(); + + MethodData *data = (MethodData *)object(that); + + if (!data->object || context->argumentCount() == 0) + return engine->undefinedValue(); + + QByteArray signal("2"); + signal.append(data->object->metaObject()->method(data->data.coreIndex).signature()); + + if (context->argumentCount() == 1) { + qScriptConnect(data->object, signal.constData(), QScriptValue(), context->argument(0)); + } else { + qScriptConnect(data->object, signal.constData(), context->argument(0), context->argument(1)); + } + + return engine->undefinedValue(); +} + +QScriptValue QDeclarativeObjectMethodScriptClass::disconnect(QScriptContext *context, QScriptEngine *engine) +{ + QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine); + + QScriptValue that = context->thisObject(); + if (&p->objectClass->methods != scriptClass(that)) + return engine->undefinedValue(); + + MethodData *data = (MethodData *)object(that); + + if (!data->object || context->argumentCount() == 0) + return engine->undefinedValue(); + + QByteArray signal("2"); + signal.append(data->object->metaObject()->method(data->data.coreIndex).signature()); + + if (context->argumentCount() == 1) { + qScriptDisconnect(data->object, signal.constData(), QScriptValue(), context->argument(0)); + } else { + qScriptDisconnect(data->object, signal.constData(), context->argument(0), context->argument(1)); + } + + return engine->undefinedValue(); +} + +QScriptClass::QueryFlags +QDeclarativeObjectMethodScriptClass::queryProperty(Object *, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + if (name == m_connectId.identifier || name == m_disconnectId.identifier) + return QScriptClass::HandlesReadAccess; + else + return 0; + +} + +QDeclarativeObjectMethodScriptClass::Value +QDeclarativeObjectMethodScriptClass::property(Object *, const Identifier &name) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + if (name == m_connectId.identifier) + return Value(scriptEngine, m_connect); + else if (name == m_disconnectId.identifier) + return Value(scriptEngine, m_disconnect); + else + return Value(); +} + +namespace { +struct MetaCallArgument { + inline MetaCallArgument(); + inline ~MetaCallArgument(); + inline void *dataPtr(); + + inline void initAsType(int type, QDeclarativeEngine *); + void fromScriptValue(int type, QDeclarativeEngine *, const QScriptValue &); + inline QScriptDeclarativeClass::Value toValue(QDeclarativeEngine *); + +private: + MetaCallArgument(const MetaCallArgument &); + + inline void cleanup(); + + union { + float floatValue; + double doubleValue; + quint32 intValue; + bool boolValue; + QObject *qobjectPtr; + + char allocData[sizeof(QVariant)]; + }; + + // Pointers to allocData + union { + QString *qstringPtr; + QVariant *qvariantPtr; + QList<QObject *> *qlistPtr; + QScriptValue *qscriptValuePtr; + }; + + int type; +}; +} + +MetaCallArgument::MetaCallArgument() +: type(QVariant::Invalid) +{ +} + +MetaCallArgument::~MetaCallArgument() +{ + cleanup(); +} + +void MetaCallArgument::cleanup() +{ + if (type == QMetaType::QString) { + qstringPtr->~QString(); + } else if (type == -1 || type == QMetaType::QVariant) { + qvariantPtr->~QVariant(); + } else if (type == qMetaTypeId<QScriptValue>()) { + qscriptValuePtr->~QScriptValue(); + } else if (type == qMetaTypeId<QList<QObject *> >()) { + qlistPtr->~QList<QObject *>(); + } +} + +void *MetaCallArgument::dataPtr() +{ + if (type == -1) + return qvariantPtr->data(); + else + return (void *)&allocData; +} + +void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) +{ + if (type != 0) { cleanup(); type = 0; } + if (callType == 0) return; + + QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); + + if (callType == qMetaTypeId<QScriptValue>()) { + qscriptValuePtr = new (&allocData) QScriptValue(engine->undefinedValue()); + type = callType; + } else if (callType == QMetaType::Int || + callType == QMetaType::UInt || + callType == QMetaType::Bool || + callType == QMetaType::Double || + callType == QMetaType::Float) { + type = callType; + } else if (callType == QMetaType::QObjectStar) { + qobjectPtr = 0; + type = callType; + } else if (callType == QMetaType::QString) { + qstringPtr = new (&allocData) QString(); + type = callType; + } else if (callType == qMetaTypeId<QVariant>()) { + type = callType; + qvariantPtr = new (&allocData) QVariant(); + } else if (callType == qMetaTypeId<QList<QObject *> >()) { + type = callType; + qlistPtr = new (&allocData) QList<QObject *>(); + } else { + type = -1; + qvariantPtr = new (&allocData) QVariant(callType, (void *)0); + } +} + +void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, const QScriptValue &value) +{ + if (type != 0) { cleanup(); type = 0; } + + if (callType == qMetaTypeId<QScriptValue>()) { + qscriptValuePtr = new (&allocData) QScriptValue(value); + type = qMetaTypeId<QScriptValue>(); + } else if (callType == QMetaType::Int) { + intValue = quint32(value.toInt32()); + type = callType; + } else if (callType == QMetaType::UInt) { + intValue = quint32(value.toUInt32()); + type = callType; + } else if (callType == QMetaType::Bool) { + boolValue = value.toBool(); + type = callType; + } else if (callType == QMetaType::Double) { + doubleValue = double(value.toNumber()); + type = callType; + } else if (callType == QMetaType::Float) { + floatValue = float(value.toNumber()); + type = callType; + } else if (callType == QMetaType::QString) { + if (value.isNull() || value.isUndefined()) + qstringPtr = new (&allocData) QString(); + else + qstringPtr = new (&allocData) QString(value.toString()); + type = callType; + } else if (callType == QMetaType::QObjectStar) { + qobjectPtr = value.toQObject(); + type = callType; + } else if (callType == qMetaTypeId<QVariant>()) { + QVariant other = QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value); + qvariantPtr = new (&allocData) QVariant(other); + type = callType; + } else if (callType == qMetaTypeId<QList<QObject*> >()) { + qlistPtr = new (&allocData) QList<QObject *>(); + if (value.isArray()) { + int length = value.property(QLatin1String("length")).toInt32(); + for (int ii = 0; ii < length; ++ii) { + QScriptValue arrayItem = value.property(ii); + QObject *d = arrayItem.toQObject(); + qlistPtr->append(d); + } + } else if (QObject *d = value.toQObject()) { + qlistPtr->append(d); + } + type = callType; + } else { + qvariantPtr = new (&allocData) QVariant(); + type = -1; + + QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine); + QVariant v = priv->scriptValueToVariant(value); + if (v.userType() == callType) { + *qvariantPtr = v; + } else if (v.canConvert((QVariant::Type)callType)) { + *qvariantPtr = v; + qvariantPtr->convert((QVariant::Type)callType); + } else if (const QMetaObject *mo = priv->rawMetaObjectForType(callType)) { + QObject *obj = priv->toQObject(v); + + if (obj) { + const QMetaObject *objMo = obj->metaObject(); + while (objMo && objMo != mo) objMo = objMo->superClass(); + if (!objMo) obj = 0; + } + + *qvariantPtr = QVariant(callType, &obj); + } else { + *qvariantPtr = QVariant(callType, (void *)0); + } + } +} + +QScriptDeclarativeClass::Value MetaCallArgument::toValue(QDeclarativeEngine *e) +{ + QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); + + if (type == qMetaTypeId<QScriptValue>()) { + return QScriptDeclarativeClass::Value(engine, *qscriptValuePtr); + } else if (type == QMetaType::Int) { + return QScriptDeclarativeClass::Value(engine, int(intValue)); + } else if (type == QMetaType::UInt) { + return QScriptDeclarativeClass::Value(engine, uint(intValue)); + } else if (type == QMetaType::Bool) { + return QScriptDeclarativeClass::Value(engine, boolValue); + } else if (type == QMetaType::Double) { + return QScriptDeclarativeClass::Value(engine, doubleValue); + } else if (type == QMetaType::Float) { + return QScriptDeclarativeClass::Value(engine, floatValue); + } else if (type == QMetaType::QString) { + return QScriptDeclarativeClass::Value(engine, *qstringPtr); + } else if (type == QMetaType::QObjectStar) { + if (qobjectPtr) + QDeclarativeData::get(qobjectPtr, true)->setImplicitDestructible(); + QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); + return QScriptDeclarativeClass::Value(engine, priv->objectClass->newQObject(qobjectPtr)); + } else if (type == qMetaTypeId<QList<QObject *> >()) { + QList<QObject *> &list = *qlistPtr; + QScriptValue rv = engine->newArray(list.count()); + QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); + for (int ii = 0; ii < list.count(); ++ii) { + QObject *object = list.at(ii); + QDeclarativeData::get(object, true)->setImplicitDestructible(); + rv.setProperty(ii, priv->objectClass->newQObject(object)); + } + return QScriptDeclarativeClass::Value(engine, rv); + } else if (type == -1 || type == qMetaTypeId<QVariant>()) { + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(e); + QScriptValue rv = ep->scriptValueFromVariant(*qvariantPtr); + if (rv.isQObject()) { + QObject *object = rv.toQObject(); + if (object) + QDeclarativeData::get(object, true)->setImplicitDestructible(); + } + return QScriptDeclarativeClass::Value(engine, rv); + } else { + return QScriptDeclarativeClass::Value(); + } +} + +int QDeclarativeObjectMethodScriptClass::enumType(const QMetaObject *meta, const QString &strname) +{ + QByteArray str = strname.toUtf8(); + QByteArray scope; + QByteArray name; + int scopeIdx = str.lastIndexOf("::"); + if (scopeIdx != -1) { + scope = str.left(scopeIdx); + name = str.mid(scopeIdx + 2); + } else { + name = str; + } + for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { + QMetaEnum m = meta->enumerator(i); + if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) + return QVariant::Int; + } + return QVariant::Invalid; +} + +QDeclarativeObjectMethodScriptClass::Value QDeclarativeObjectMethodScriptClass::call(Object *o, QScriptContext *ctxt) +{ + MethodData *method = static_cast<MethodData *>(o); + + if (method->data.relatedIndex == -1) + return callPrecise(method->object, method->data, ctxt); + else + return callOverloaded(method, ctxt); +} + +QDeclarativeObjectMethodScriptClass::Value +QDeclarativeObjectMethodScriptClass::callPrecise(QObject *object, const QDeclarativePropertyCache::Data &data, + QScriptContext *ctxt) +{ + if (data.flags & QDeclarativePropertyCache::Data::HasArguments) { + + QMetaMethod m = object->metaObject()->method(data.coreIndex); + QList<QByteArray> argTypeNames = m.parameterTypes(); + QVarLengthArray<int, 9> argTypes(argTypeNames.count()); + + // ### Cache + for (int ii = 0; ii < argTypeNames.count(); ++ii) { + argTypes[ii] = QMetaType::type(argTypeNames.at(ii)); + if (argTypes[ii] == QVariant::Invalid) + argTypes[ii] = enumType(object->metaObject(), QString::fromLatin1(argTypeNames.at(ii))); + if (argTypes[ii] == QVariant::Invalid) + return Value(ctxt, ctxt->throwError(QString::fromLatin1("Unknown method parameter type: %1").arg(QLatin1String(argTypeNames.at(ii))))); + } + + if (argTypes.count() > ctxt->argumentCount()) + return Value(ctxt, ctxt->throwError(QLatin1String("Insufficient arguments"))); + + return callMethod(object, data.coreIndex, data.propType, argTypes.count(), argTypes.data(), ctxt); + + } else { + + return callMethod(object, data.coreIndex, data.propType, 0, 0, ctxt); + + } +} + +QDeclarativeObjectMethodScriptClass::Value +QDeclarativeObjectMethodScriptClass::callMethod(QObject *object, int index, + int returnType, int argCount, int *argTypes, + QScriptContext *ctxt) +{ + if (argCount > 0) { + + QVarLengthArray<MetaCallArgument, 9> args(argCount + 1); + args[0].initAsType(returnType, engine); + + for (int ii = 0; ii < argCount; ++ii) + args[ii + 1].fromScriptValue(argTypes[ii], engine, ctxt->argument(ii)); + + QVarLengthArray<void *, 9> argData(args.count()); + for (int ii = 0; ii < args.count(); ++ii) + argData[ii] = args[ii].dataPtr(); + + QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data()); + + return args[0].toValue(engine); + + } else if (returnType != 0) { + + MetaCallArgument arg; + arg.initAsType(returnType, engine); + + void *args[] = { arg.dataPtr() }; + + QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args); + + return arg.toValue(engine); + + } else { + + void *args[] = { 0 }; + QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args); + return Value(); + + } +} + +/*! +Resolve the overloaded method to call. The algorithm works conceptually like this: + 1. Resolve the set of overloads it is *possible* to call. + Impossible overloads include those that have too many parameters or have parameters + of unknown type. + 2. Filter the set of overloads to only contain those with the closest number of + parameters. + For example, if we are called with 3 parameters and there are 2 overloads that + take 2 parameters and one that takes 3, eliminate the 2 parameter overloads. + 3. Find the best remaining overload based on its match score. + If two or more overloads have the same match score, call the last one. The match + score is constructed by adding the matchScore() result for each of the parameters. +*/ +QDeclarativeObjectMethodScriptClass::Value +QDeclarativeObjectMethodScriptClass::callOverloaded(MethodData *method, QScriptContext *ctxt) +{ + int argumentCount = ctxt->argumentCount(); + + QDeclarativePropertyCache::Data *best = 0; + int bestParameterScore = INT_MAX; + int bestMatchScore = INT_MAX; + + QDeclarativePropertyCache::Data dummy; + QDeclarativePropertyCache::Data *attempt = &method->data; + + do { + QList<QByteArray> methodArgTypeNames; + + if (attempt->flags & QDeclarativePropertyCache::Data::HasArguments) + methodArgTypeNames = method->object->metaObject()->method(attempt->coreIndex).parameterTypes(); + + int methodArgumentCount = methodArgTypeNames.count(); + + if (methodArgumentCount > argumentCount) + continue; // We don't have sufficient arguments to call this method + + int methodParameterScore = argumentCount - methodArgumentCount; + if (methodParameterScore > bestParameterScore) + continue; // We already have a better option + + int methodMatchScore = 0; + QVarLengthArray<int, 9> methodArgTypes(methodArgumentCount); + + bool unknownArgument = false; + for (int ii = 0; ii < methodArgumentCount; ++ii) { + methodArgTypes[ii] = QMetaType::type(methodArgTypeNames.at(ii)); + if (methodArgTypes[ii] == QVariant::Invalid) + methodArgTypes[ii] = enumType(method->object->metaObject(), + QString::fromLatin1(methodArgTypeNames.at(ii))); + if (methodArgTypes[ii] == QVariant::Invalid) { + unknownArgument = true; + break; + } + methodMatchScore += matchScore(ctxt->argument(ii), methodArgTypes[ii], methodArgTypeNames.at(ii)); + } + if (unknownArgument) + continue; // We don't understand all the parameters + + if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) { + best = attempt; + bestParameterScore = methodParameterScore; + bestMatchScore = methodMatchScore; + } + + if (bestParameterScore == 0 && bestMatchScore == 0) + break; // We can't get better than that + + } while((attempt = relatedMethod(method->object, attempt, dummy)) != 0); + + if (best) { + return callPrecise(method->object, *best, ctxt); + } else { + QString error = QLatin1String("Unable to determine callable overload. Candidates are:"); + QDeclarativePropertyCache::Data *candidate = &method->data; + while (candidate) { + error += QLatin1String("\n ") + QString::fromUtf8(method->object->metaObject()->method(candidate->coreIndex).signature()); + candidate = relatedMethod(method->object, candidate, dummy); + } + return Value(ctxt, ctxt->throwError(error)); + } +} + +/*! + Returns the match score for converting \a actual to be of type \a conversionType. A + zero score means "perfect match" whereas a higher score is worse. + + The conversion table is copied out of the QtScript callQtMethod() function. +*/ +int QDeclarativeObjectMethodScriptClass::matchScore(const QScriptValue &actual, int conversionType, + const QByteArray &conversionTypeName) +{ + if (actual.isNumber()) { + switch (conversionType) { + case QMetaType::Double: + return 0; + case QMetaType::Float: + return 1; + case QMetaType::LongLong: + case QMetaType::ULongLong: + return 2; + case QMetaType::Long: + case QMetaType::ULong: + return 3; + case QMetaType::Int: + case QMetaType::UInt: + return 4; + case QMetaType::Short: + case QMetaType::UShort: + return 5; + break; + case QMetaType::Char: + case QMetaType::UChar: + return 6; + default: + return 10; + } + } else if (actual.isString()) { + switch (conversionType) { + case QMetaType::QString: + return 0; + default: + return 10; + } + } else if (actual.isBoolean()) { + switch (conversionType) { + case QMetaType::Bool: + return 0; + default: + return 10; + } + } else if (actual.isDate()) { + switch (conversionType) { + case QMetaType::QDateTime: + return 0; + case QMetaType::QDate: + return 1; + case QMetaType::QTime: + return 2; + default: + return 10; + } + } else if (actual.isRegExp()) { + switch (conversionType) { + case QMetaType::QRegExp: + return 0; + default: + return 10; + } + } else if (actual.isVariant()) { + if (conversionType == qMetaTypeId<QVariant>()) + return 0; + else if (actual.toVariant().userType() == conversionType) + return 0; + else + return 10; + } else if (actual.isArray()) { + switch (conversionType) { + case QMetaType::QStringList: + case QMetaType::QVariantList: + return 5; + default: + return 10; + } + } else if (actual.isQObject()) { + switch (conversionType) { + case QMetaType::QObjectStar: + return 0; + default: + return 10; + } + } else if (actual.isNull()) { + switch (conversionType) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + return 0; + default: + if (!conversionTypeName.endsWith('*')) + return 10; + else + return 0; + } + } else { + return 10; + } +} + +static inline int QMetaObject_methods(const QMetaObject *metaObject) +{ + struct Private + { + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + }; + + return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount; +} + +static QByteArray QMetaMethod_name(const QMetaMethod &m) +{ + QByteArray sig = m.signature(); + int paren = sig.indexOf('('); + if (paren == -1) + return sig; + else + return sig.left(paren); +} + +/*! +Returns the next related method, if one, or 0. +*/ +QDeclarativePropertyCache::Data * +QDeclarativeObjectMethodScriptClass::relatedMethod(QObject *object, QDeclarativePropertyCache::Data *current, + QDeclarativePropertyCache::Data &dummy) +{ + QDeclarativePropertyCache *cache = QDeclarativeData::get(object)->propertyCache; + if (current->relatedIndex == -1) + return 0; + + if (cache) { + return cache->method(current->relatedIndex); + } else { + const QMetaObject *mo = object->metaObject(); + int methodOffset = mo->methodCount() - QMetaObject_methods(mo); + + while (methodOffset > current->relatedIndex) { + mo = mo->superClass(); + methodOffset -= QMetaObject_methods(mo); + } + + QMetaMethod method = mo->method(current->relatedIndex); + dummy.load(method); + + // Look for overloaded methods + QByteArray methodName = QMetaMethod_name(method); + for (int ii = current->relatedIndex - 1; ii >= methodOffset; --ii) { + if (methodName == QMetaMethod_name(mo->method(ii))) { + dummy.relatedIndex = ii; + return &dummy; + } + } + + return &dummy; + } +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass_p.h b/src/declarative/qml/qdeclarativeobjectscriptclass_p.h new file mode 100644 index 00000000..6910960f --- /dev/null +++ b/src/declarative/qml/qdeclarativeobjectscriptclass_p.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEOBJECTSCRIPTCLASS_P_H +#define QDECLARATIVEOBJECTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativepropertycache_p.h" +#include "private/qdeclarativetypenamecache_p.h" + +#include <private/qscriptdeclarativeclass_p.h> +#include <QtScript/qscriptengine.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeEngine; +class QScriptContext; +class QScriptEngine; +class QDeclarativeContextData; +class MethodData; + +class Q_AUTOTEST_EXPORT QDeclarativeObjectMethodScriptClass : public QScriptDeclarativeClass +{ +public: + QDeclarativeObjectMethodScriptClass(QDeclarativeEngine *); + ~QDeclarativeObjectMethodScriptClass(); + + QScriptValue newMethod(QObject *, const QDeclarativePropertyCache::Data *); + +protected: + virtual Value call(Object *, QScriptContext *); + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags); + virtual Value property(Object *, const Identifier &); + +private: + int enumType(const QMetaObject *, const QString &); + + Value callPrecise(QObject *, const QDeclarativePropertyCache::Data &, QScriptContext *); + Value callOverloaded(MethodData *, QScriptContext *); + Value callMethod(QObject *, int index, int returnType, int argCount, int *argTypes, QScriptContext *ctxt); + + int matchScore(const QScriptValue &, int, const QByteArray &); + QDeclarativePropertyCache::Data *relatedMethod(QObject *, QDeclarativePropertyCache::Data *current, + QDeclarativePropertyCache::Data &dummy); + + PersistentIdentifier m_connectId; + PersistentIdentifier m_disconnectId; + QScriptValue m_connect; + QScriptValue m_disconnect; + + static QScriptValue connect(QScriptContext *context, QScriptEngine *engine); + static QScriptValue disconnect(QScriptContext *context, QScriptEngine *engine); + + QDeclarativeEngine *engine; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeObjectScriptClass : public QScriptDeclarativeClass +{ +public: + QDeclarativeObjectScriptClass(QDeclarativeEngine *); + ~QDeclarativeObjectScriptClass(); + + QScriptValue newQObject(QObject *, int type = QMetaType::QObjectStar); + + QObject *toQObject(const QScriptValue &) const; + int objectType(const QScriptValue &) const; + + enum QueryHint { + ImplicitObject = 0x01, + SkipAttachedProperties = 0x02 + }; + Q_DECLARE_FLAGS(QueryHints, QueryHint) + + QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &, + QScriptClass::QueryFlags flags, + QDeclarativeContextData *evalContext, + QueryHints hints = 0); + + Value property(QObject *, const Identifier &); + + void setProperty(QObject *, const Identifier &name, const QScriptValue &, + QScriptContext *context, QDeclarativeContextData *evalContext = 0); + virtual QStringList propertyNames(Object *); + virtual bool compare(Object *, Object *); + +protected: + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + + virtual Value property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); + virtual bool isQObject() const; + virtual QObject *toQObject(Object *, bool *ok = 0); + +private: + friend class QDeclarativeObjectMethodScriptClass; + QDeclarativeObjectMethodScriptClass methods; + + QDeclarativeTypeNameCache::Data *lastTNData; + QDeclarativePropertyCache::Data *lastData; + QDeclarativePropertyCache::Data local; + + PersistentIdentifier m_destroyId; + PersistentIdentifier m_toStringId; + QScriptValue m_destroy; + QScriptValue m_toString; + + static QScriptValue tostring(QScriptContext *context, QScriptEngine *engine); + static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine); + + QDeclarativeEngine *engine; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeObjectScriptClass::QueryHints); + +QT_END_NAMESPACE + +#endif // QDECLARATIVEOBJECTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qdeclarativeparser.cpp b/src/declarative/qml/qdeclarativeparser.cpp new file mode 100644 index 00000000..0bb52564 --- /dev/null +++ b/src/declarative/qml/qdeclarativeparser.cpp @@ -0,0 +1,437 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativeparser_p.h" + +#include "qdeclarativepropertyvaluesource.h" +#include "private/qdeclarativevme_p.h" +#include "qdeclarative.h" +#include "private/qdeclarativecomponent_p.h" +#include "qdeclarativecomponent.h" +#include "private/qmetaobjectbuilder_p.h" +#include "private/qdeclarativevmemetaobject_p.h" +#include "private/qdeclarativecompiler_p.h" +#include "parser/qdeclarativejsast_p.h" +#include "parser/qdeclarativejsengine_p.h" + +#include <QStack> +#include <QColor> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <QStringBuilder> +#include <QtDebug> + +QT_BEGIN_NAMESPACE + +using namespace QDeclarativeJS; +using namespace QDeclarativeParser; + +QDeclarativeParser::Object::Object() +: type(-1), majorVersion(-1), minorVersion(-1), idIndex(-1), metatype(0), synthCache(0), defaultProperty(0), parserStatusCast(-1) +{ +} + +QDeclarativeParser::Object::~Object() +{ + if (defaultProperty) defaultProperty->release(); + if (synthCache) synthCache->release(); + foreach(Property *prop, properties) + prop->release(); + foreach(Property *prop, valueProperties) + prop->release(); + foreach(Property *prop, signalProperties) + prop->release(); + foreach(Property *prop, attachedProperties) + prop->release(); + foreach(Property *prop, groupedProperties) + prop->release(); + foreach(Property *prop, valueTypeProperties) + prop->release(); + typedef QPair<Property *, int> PropPair; + foreach(const PropPair &prop, scriptStringProperties) + prop.first->release(); + foreach(const DynamicProperty &prop, dynamicProperties) + if (prop.defaultValue) prop.defaultValue->release(); +} + +void Object::setBindingBit(int b) +{ + while (bindingBitmask.size() < 4 * (1 + b / 32)) + bindingBitmask.append(char(0)); + + quint32 *bits = (quint32 *)bindingBitmask.data(); + bits[b / 32] |= (1 << (b % 32)); +} + +const QMetaObject *Object::metaObject() const +{ + if (!metadata.isEmpty() && metatype) + return &extObject; + else + return metatype; +} + +QDeclarativeParser::Property *Object::getDefaultProperty() +{ + if (!defaultProperty) { + defaultProperty = new Property; + defaultProperty->parent = this; + } + return defaultProperty; +} + +void QDeclarativeParser::Object::addValueProperty(Property *p) +{ + p->addref(); + valueProperties << p; +} + +void QDeclarativeParser::Object::addSignalProperty(Property *p) +{ + p->addref(); + signalProperties << p; +} + +void QDeclarativeParser::Object::addAttachedProperty(Property *p) +{ + p->addref(); + attachedProperties << p; +} + +void QDeclarativeParser::Object::addGroupedProperty(Property *p) +{ + p->addref(); + groupedProperties << p; +} + +void QDeclarativeParser::Object::addValueTypeProperty(Property *p) +{ + p->addref(); + valueTypeProperties << p; +} + +void QDeclarativeParser::Object::addScriptStringProperty(Property *p, int stack) +{ + p->addref(); + scriptStringProperties << qMakePair(p, stack); +} + + +Property *QDeclarativeParser::Object::getProperty(const QByteArray &name, bool create) +{ + if (!properties.contains(name)) { + if (create) { + Property *property = new Property(name); + property->parent = this; + properties.insert(name, property); + } else { + return 0; + } + } + return properties[name]; +} + +QDeclarativeParser::Object::DynamicProperty::DynamicProperty() +: isDefaultProperty(false), type(Variant), defaultValue(0) +{ +} + +QDeclarativeParser::Object::DynamicProperty::DynamicProperty(const DynamicProperty &o) +: isDefaultProperty(o.isDefaultProperty), + type(o.type), + customType(o.customType), + name(o.name), + defaultValue(o.defaultValue), + location(o.location) +{ +} + +QDeclarativeParser::Object::DynamicSignal::DynamicSignal() +{ +} + +QDeclarativeParser::Object::DynamicSignal::DynamicSignal(const DynamicSignal &o) +: name(o.name), parameterTypes(o.parameterTypes), + parameterNames(o.parameterNames) +{ +} + +QDeclarativeParser::Object::DynamicSlot::DynamicSlot() +{ +} + +QDeclarativeParser::Object::DynamicSlot::DynamicSlot(const DynamicSlot &o) +: name(o.name), body(o.body), parameterNames(o.parameterNames), location(o.location) +{ +} + +QDeclarativeParser::Property::Property() +: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false), + isValueTypeSubProperty(false), isAlias(false) +{ +} + +QDeclarativeParser::Property::Property(const QByteArray &n) +: parent(0), type(0), index(-1), value(0), name(n), isDefault(false), + isDeferred(false), isValueTypeSubProperty(false), isAlias(false) +{ +} + +QDeclarativeParser::Property::~Property() +{ + foreach(Value *value, values) + value->release(); + foreach(Value *value, onValues) + value->release(); + if (value) value->release(); +} + +QDeclarativeParser::Object *QDeclarativeParser::Property::getValue(const LocationSpan &l) +{ + if (!value) { value = new QDeclarativeParser::Object; value->location = l; } + return value; +} + +void QDeclarativeParser::Property::addValue(Value *v) +{ + values << v; +} + +void QDeclarativeParser::Property::addOnValue(Value *v) +{ + onValues << v; +} + +bool QDeclarativeParser::Property::isEmpty() const +{ + return !value && values.isEmpty() && onValues.isEmpty(); +} + +QDeclarativeParser::Value::Value() +: type(Unknown), object(0) +{ +} + +QDeclarativeParser::Value::~Value() +{ + if (object) object->release(); +} + +QDeclarativeParser::Variant::Variant() +: t(Invalid) {} + +QDeclarativeParser::Variant::Variant(const Variant &o) +: t(o.t), d(o.d), s(o.s) +{ +} + +QDeclarativeParser::Variant::Variant(bool v) +: t(Boolean), b(v) +{ +} + +QDeclarativeParser::Variant::Variant(double v, const QString &asWritten) +: t(Number), d(v), s(asWritten) +{ +} + +QDeclarativeParser::Variant::Variant(const QString &v) +: t(String), s(v) +{ +} + +QDeclarativeParser::Variant::Variant(const QString &v, QDeclarativeJS::AST::Node *n) +: t(Script), n(n), s(v) +{ +} + +QDeclarativeParser::Variant &QDeclarativeParser::Variant::operator=(const Variant &o) +{ + t = o.t; + d = o.d; + s = o.s; + return *this; +} + +QDeclarativeParser::Variant::Type QDeclarativeParser::Variant::type() const +{ + return t; +} + +bool QDeclarativeParser::Variant::asBoolean() const +{ + return b; +} + +QString QDeclarativeParser::Variant::asString() const +{ + return s; +} + +double QDeclarativeParser::Variant::asNumber() const +{ + return d; +} + +//reverse of Lexer::singleEscape() +QString escapedString(const QString &string) +{ + QString tmp = QLatin1String("\""); + for (int i = 0; i < string.length(); ++i) { + const QChar &c = string.at(i); + switch(c.unicode()) { + case 0x08: + tmp += QLatin1String("\\b"); + break; + case 0x09: + tmp += QLatin1String("\\t"); + break; + case 0x0A: + tmp += QLatin1String("\\n"); + break; + case 0x0B: + tmp += QLatin1String("\\v"); + break; + case 0x0C: + tmp += QLatin1String("\\f"); + break; + case 0x0D: + tmp += QLatin1String("\\r"); + break; + case 0x22: + tmp += QLatin1String("\\\""); + break; + case 0x27: + tmp += QLatin1String("\\\'"); + break; + case 0x5C: + tmp += QLatin1String("\\\\"); + break; + default: + tmp += c; + break; + } + } + tmp += QLatin1Char('\"'); + return tmp; +} + +QString QDeclarativeParser::Variant::asScript() const +{ + switch(type()) { + default: + case Invalid: + return QString(); + case Boolean: + return b?QLatin1String("true"):QLatin1String("false"); + case Number: + if (s.isEmpty()) + return QString::number(d); + else + return s; + case String: + return escapedString(s); + case Script: + return s; + } +} + +QDeclarativeJS::AST::Node *QDeclarativeParser::Variant::asAST() const +{ + if (type() == Script) + return n; + else + return 0; +} + +bool QDeclarativeParser::Variant::isStringList() const +{ + if (isString()) + return true; + + if (type() != Script || !n) + return false; + + AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n); + if (!array) + return false; + + AST::ElementList *elements = array->elements; + + while (elements) { + + if (!AST::cast<AST::StringLiteral *>(elements->expression)) + return false; + + elements = elements->next; + } + + return true; +} + +QStringList QDeclarativeParser::Variant::asStringList() const +{ + QStringList rv; + if (isString()) { + rv << asString(); + return rv; + } + + AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n); + if (!array) + return rv; + + AST::ElementList *elements = array->elements; + while (elements) { + + AST::StringLiteral *string = AST::cast<AST::StringLiteral *>(elements->expression); + if (!string) + return QStringList(); + rv.append(string->value->asString()); + + elements = elements->next; + } + + return rv; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeparser_p.h b/src/declarative/qml/qdeclarativeparser_p.h new file mode 100644 index 00000000..6e4d6cd3 --- /dev/null +++ b/src/declarative/qml/qdeclarativeparser_p.h @@ -0,0 +1,381 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPARSER_P_H +#define QDECLARATIVEPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarative.h" + +#include <QtCore/qbytearray.h> +#include <QtCore/qlist.h> +#include <QtCore/qurl.h> +#include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> + +#include <private/qobject_p.h> +#include <private/qdeclarativerefcount_p.h> +#include <private/qdeclarativeglobal_p.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativePropertyCache; +namespace QDeclarativeJS { namespace AST { class Node; } } + +/* + XXX + + These types are created (and owned) by the QDeclarativeXmlParser and consumed by the + QDeclarativeCompiler. During the compilation phase the compiler will update some of + the fields for both its own use and for the use of the upcoming QDeclarativeDom API. + + The types are part of the generic sounding "QDeclarativeParser" namespace for legacy + reasons (there used to be more in this namespace) and will be cleaned up and + migrated into a more appropriate location shortly. +*/ +namespace QDeclarativeParser +{ + struct Location + { + Location() : line(-1), column(-1) {} + int line; + int column; + }; + + struct LocationRange + { + LocationRange() : offset(0), length(0) {} + quint32 offset; + quint32 length; + }; + + struct LocationSpan + { + Location start; + Location end; + LocationRange range; + + bool operator<(LocationSpan &o) const { + return (start.line < o.start.line) || + (start.line == o.start.line && start.column < o.start.column); + } + }; + + class Property; + class Object : public QDeclarativeRefCount + { + public: + Object(); + virtual ~Object(); + + // Type of the object. The integer is an index into the + // QDeclarativeCompiledData::types array, or -1 if the object is a property + // group. + int type; + // The url of this object if it is an external type. Used by the DOM + QUrl url; + + // version information if type is defined in library or C++ + int majorVersion; + int minorVersion; + + // The fully-qualified name of this type + QByteArray typeName; + // The class name + QByteArray className; + // The id assigned to the object (if any). Set by the QDeclarativeCompiler + QString id; + // The id index assigned to the object (if any). Set by the QDeclarativeCompiler + int idIndex; + // Custom parsed data + QByteArray custom; + // Bit mask of the properties assigned bindings + QByteArray bindingBitmask; + void setBindingBit(int); + // Returns the metaobject for this type, or 0 if not available. + // Internally selectd between the metatype and extObject variables + const QMetaObject *metaObject() const; + + // The compile time metaobject for this type + const QMetaObject *metatype; + // The synthesized metaobject, if QML added signals or properties to + // this type. Otherwise null + QAbstractDynamicMetaObject extObject; + QByteArray metadata; // Generated by compiler + QByteArray synthdata; // Generated by compiler + QDeclarativePropertyCache *synthCache; // Generated by compiler + + Property *getDefaultProperty(); + Property *getProperty(const QByteArray &name, bool create=true); + + Property *defaultProperty; + QHash<QByteArray, Property *> properties; + + // Output of the compilation phase (these properties continue to exist + // in either the defaultProperty or properties members too) + void addValueProperty(Property *); + void addSignalProperty(Property *); + void addAttachedProperty(Property *); + void addGroupedProperty(Property *); + void addValueTypeProperty(Property *); + void addScriptStringProperty(Property *, int = 0); + QList<Property *> valueProperties; + QList<Property *> signalProperties; + QList<Property *> attachedProperties; + QList<Property *> groupedProperties; + QList<Property *> valueTypeProperties; + QList<QPair<Property *, int> > scriptStringProperties; + + // Script blocks that were nested under this object + struct ScriptBlock { + enum Pragma { + None = 0x00000000, + Shared = 0x00000001 + }; + Q_DECLARE_FLAGS(Pragmas, Pragma) + + QString code; + QString file; + Pragmas pragmas; + }; + + // The bytes to cast instances by to get to the QDeclarativeParserStatus + // interface. -1 indicates the type doesn't support this interface. + // Set by the QDeclarativeCompiler. + int parserStatusCast; + + LocationSpan location; + + struct DynamicProperty { + DynamicProperty(); + DynamicProperty(const DynamicProperty &); + + enum Type { Variant, Int, Bool, Real, String, Url, Color, Time, Date, DateTime, Alias, Custom, CustomList }; + + bool isDefaultProperty; + Type type; + QByteArray customType; + QByteArray name; + QDeclarativeParser::Property *defaultValue; + LocationSpan location; + }; + struct DynamicSignal { + DynamicSignal(); + DynamicSignal(const DynamicSignal &); + + QByteArray name; + QList<QByteArray> parameterTypes; + QList<QByteArray> parameterNames; + }; + struct DynamicSlot { + DynamicSlot(); + DynamicSlot(const DynamicSlot &); + + QByteArray name; + QString body; + QList<QByteArray> parameterNames; + LocationSpan location; + }; + + // The list of dynamic properties + QList<DynamicProperty> dynamicProperties; + // The list of dynamic signals + QList<DynamicSignal> dynamicSignals; + // The list of dynamic slots + QList<DynamicSlot> dynamicSlots; + }; + + class Q_DECLARATIVE_EXPORT Variant + { + public: + enum Type { + Invalid, + Boolean, + Number, + String, + Script + }; + + Variant(); + Variant(const Variant &); + Variant(bool); + Variant(double, const QString &asWritten=QString()); + Variant(const QString &); + Variant(const QString &, QDeclarativeJS::AST::Node *); + Variant &operator=(const Variant &); + + Type type() const; + + bool isBoolean() const { return type() == Boolean; } + bool isNumber() const { return type() == Number; } + bool isString() const { return type() == String; } + bool isScript() const { return type() == Script; } + bool isStringList() const; + + bool asBoolean() const; + QString asString() const; + double asNumber() const; + QString asScript() const; + QDeclarativeJS::AST::Node *asAST() const; + QStringList asStringList() const; + + private: + Type t; + union { + bool b; + double d; + QDeclarativeJS::AST::Node *n; + }; + QString s; + }; + + class Value : public QDeclarativeRefCount + { + public: + Value(); + virtual ~Value(); + + enum Type { + // The type of this value assignment is not yet known + Unknown, + // This is used as a literal property assignment + Literal, + // This is used as a property binding assignment + PropertyBinding, + // This is used as a QDeclarativePropertyValueSource assignment + ValueSource, + // This is used as a QDeclarativePropertyValueInterceptor assignment + ValueInterceptor, + // This is used as a property QObject assignment + CreatedObject, + // This is used as a signal object assignment + SignalObject, + // This is used as a signal expression assignment + SignalExpression, + // This is used as an id assignment only + Id + }; + Type type; + + // ### Temporary (for id only) + QString primitive() const { return value.isString() ? value.asString() : value.asScript(); } + + // Primitive value + Variant value; + // Object value + Object *object; + + LocationSpan location; + }; + + class Property : public QDeclarativeRefCount + { + public: + Property(); + Property(const QByteArray &n); + virtual ~Property(); + + // The Object to which this property is attached + Object *parent; + + Object *getValue(const LocationSpan &); + void addValue(Value *v); + void addOnValue(Value *v); + + // The QVariant::Type of the property, or 0 (QVariant::Invalid) if + // unknown. + int type; + // The metaobject index of this property, or -1 if unknown. + int index; + + // Returns true if this is an empty property - both value and values + // are unset. + bool isEmpty() const; + // The list of values assigned to this property. Content in values + // and value are mutually exclusive + QList<Value *> values; + // The list of values assigned to this property using the "on" syntax + QList<Value *> onValues; + // The accessed property. This is used to represent dot properties. + // Content in value and values are mutually exclusive. + Object *value; + // The property name + QByteArray name; + // True if this property was accessed as the default property. + bool isDefault; + // True if the setting of this property will be deferred. Set by the + // QDeclarativeCompiler + bool isDeferred; + // True if this property is a value-type pseudo-property + bool isValueTypeSubProperty; + // True if this property is a property alias. Set by the + // QDeclarativeCompiler + bool isAlias; + + LocationSpan location; + LocationRange listValueRange; + QList<int> listCommaPositions; + }; +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeParser::Object::ScriptBlock::Pragmas); + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDeclarativeParser::Variant) + +QT_END_HEADER + +#endif // QDECLARATIVEPARSER_P_H diff --git a/src/declarative/qml/qdeclarativeparserstatus.cpp b/src/declarative/qml/qdeclarativeparserstatus.cpp new file mode 100644 index 00000000..ebf47152 --- /dev/null +++ b/src/declarative/qml/qdeclarativeparserstatus.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeparserstatus.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDeclarativeParserStatus + \since 4.7 + \brief The QDeclarativeParserStatus class provides updates on the QML parser state. + + QDeclarativeParserStatus provides a mechanism for classes instantiated by + a QDeclarativeEngine to receive notification at key points in their creation. + + This class is often used for optimization purposes, as it allows you to defer an + expensive operation until after all the properties have been set on an + object. For example, QML's \l {Text} element uses the parser status + to defer text layout until all of its properties have been set (we + don't want to layout when the \c text is assigned, and then relayout + when the \c font is assigned, and relayout again when the \c width is assigned, + and so on). + + To use QDeclarativeParserStatus, you must inherit both a QObject-derived class + and QDeclarativeParserStatus, and use the Q_INTERFACES() macro. + + \code + class MyObject : public QObject, public QDeclarativeParserStatus + { + Q_OBJECT + Q_INTERFACES(QDeclarativeParserStatus) + + public: + MyObject(QObject *parent = 0); + ... + void classBegin(); + void componentComplete(); + } + \endcode +*/ + +/*! \internal */ +QDeclarativeParserStatus::QDeclarativeParserStatus() +: d(0) +{ +} + +/*! \internal */ +QDeclarativeParserStatus::~QDeclarativeParserStatus() +{ + if(d) + (*d) = 0; +} + +/*! + \fn void QDeclarativeParserStatus::classBegin() + + Invoked after class creation, but before any properties have been set. +*/ + +/*! + \fn void QDeclarativeParserStatus::componentComplete() + + Invoked after the root component that caused this instantiation has + completed construction. At this point all static values and binding values + have been assigned to the class. +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeparserstatus.h b/src/declarative/qml/qdeclarativeparserstatus.h new file mode 100644 index 00000000..460600af --- /dev/null +++ b/src/declarative/qml/qdeclarativeparserstatus.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPARSERSTATUS_H +#define QDECLARATIVEPARSERSTATUS_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_DECLARATIVE_EXPORT QDeclarativeParserStatus +{ +public: + QDeclarativeParserStatus(); + virtual ~QDeclarativeParserStatus(); + + virtual void classBegin()=0; + virtual void componentComplete()=0; + +private: + friend class QDeclarativeVME; + friend class QDeclarativeComponent; + friend class QDeclarativeComponentPrivate; + friend class QDeclarativeEnginePrivate; + QDeclarativeParserStatus **d; +}; +Q_DECLARE_INTERFACE(QDeclarativeParserStatus, "com.trolltech.qml.QDeclarativeParserStatus") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEPARSERSTATUS_H diff --git a/src/declarative/qml/qdeclarativeprivate.h b/src/declarative/qml/qdeclarativeprivate.h new file mode 100644 index 00000000..20dcca0e --- /dev/null +++ b/src/declarative/qml/qdeclarativeprivate.h @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPRIVATE_H +#define QDECLARATIVEPRIVATE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +typedef QObject *(*QDeclarativeAttachedPropertiesFunc)(QObject *); + +template <typename TYPE> +class QDeclarativeTypeInfo +{ +public: + enum { + hasAttachedProperties = 0 + }; +}; + + +class QDeclarativeCustomParser; +namespace QDeclarativePrivate +{ + void Q_DECLARATIVE_EXPORT qdeclarativeelement_destructor(QObject *); + template<typename T> + class QDeclarativeElement : public T + { + public: + virtual ~QDeclarativeElement() { + QDeclarativePrivate::qdeclarativeelement_destructor(this); + } + }; + + template<typename T> + void createInto(void *memory) { new (memory) QDeclarativeElement<T>; } + + template<typename T> + QObject *createParent(QObject *p) { return new T(p); } + + template<class From, class To, int N> + struct StaticCastSelectorClass + { + static inline int cast() { return -1; } + }; + + template<class From, class To> + struct StaticCastSelectorClass<From, To, sizeof(int)> + { + static inline int cast() { return int(reinterpret_cast<quintptr>(static_cast<To *>(reinterpret_cast<From *>(0x10000000)))) - 0x10000000; } + }; + + template<class From, class To> + struct StaticCastSelector + { + typedef int yes_type; + typedef char no_type; + + static yes_type check(To *); + static no_type check(...); + + static inline int cast() + { + return StaticCastSelectorClass<From, To, sizeof(check(reinterpret_cast<From *>(0)))>::cast(); + } + }; + + template <typename T> + struct has_attachedPropertiesMember + { + static bool const value = QDeclarativeTypeInfo<T>::hasAttachedProperties; + }; + + template <typename T, bool hasMember> + class has_attachedPropertiesMethod + { + public: + typedef int yes_type; + typedef char no_type; + + template<typename ReturnType> + static yes_type check(ReturnType *(*)(QObject *)); + static no_type check(...); + + static bool const value = sizeof(check(&T::qmlAttachedProperties)) == sizeof(yes_type); + }; + + template <typename T> + class has_attachedPropertiesMethod<T, false> + { + public: + static bool const value = false; + }; + + template<typename T, int N> + class AttachedPropertySelector + { + public: + static inline QDeclarativeAttachedPropertiesFunc func() { return 0; } + static inline const QMetaObject *metaObject() { return 0; } + }; + template<typename T> + class AttachedPropertySelector<T, 1> + { + static inline QObject *attachedProperties(QObject *obj) { + return T::qmlAttachedProperties(obj); + } + template<typename ReturnType> + static inline const QMetaObject *attachedPropertiesMetaObject(ReturnType *(*)(QObject *)) { + return &ReturnType::staticMetaObject; + } + public: + static inline QDeclarativeAttachedPropertiesFunc func() { + return &attachedProperties; + } + static inline const QMetaObject *metaObject() { + return attachedPropertiesMetaObject(&T::qmlAttachedProperties); + } + }; + + template<typename T> + inline QDeclarativeAttachedPropertiesFunc attachedPropertiesFunc() + { + return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::func(); + } + + template<typename T> + inline const QMetaObject *attachedPropertiesMetaObject() + { + return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::metaObject(); + } + + enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent }; + typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent); + + struct RegisterType { + int version; + + int typeId; + int listId; + int objectSize; + void (*create)(void *); + QString noCreationReason; + + const char *uri; + int versionMajor; + int versionMinor; + const char *elementName; + const QMetaObject *metaObject; + + QDeclarativeAttachedPropertiesFunc attachedPropertiesFunction; + const QMetaObject *attachedPropertiesMetaObject; + + int parserStatusCast; + int valueSourceCast; + int valueInterceptorCast; + + QObject *(*extensionObjectCreate)(QObject *); + const QMetaObject *extensionMetaObject; + + QDeclarativeCustomParser *customParser; + int revision; + // If this is extended ensure "version" is bumped!!! + }; + + struct RegisterInterface { + int version; + + int typeId; + int listId; + + const char *iid; + }; + + struct RegisterAutoParent { + int version; + + AutoParentFunction function; + }; + + enum RegistrationType { + TypeRegistration = 0, + InterfaceRegistration = 1, + AutoParentRegistration = 2 + }; + + int Q_DECLARATIVE_EXPORT qmlregister(RegistrationType, void *); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEPRIVATE_H diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp new file mode 100644 index 00000000..05bec635 --- /dev/null +++ b/src/declarative/qml/qdeclarativeproperty.cpp @@ -0,0 +1,1654 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativeproperty.h" +#include "private/qdeclarativeproperty_p.h" + +#include "qdeclarative.h" +#include "private/qdeclarativebinding_p.h" +#include "qdeclarativecontext.h" +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativeboundsignal_p.h" +#include "qdeclarativeengine.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativedata_p.h" +#include "private/qdeclarativestringconverters_p.h" +#include "private/qdeclarativelist_p.h" +#include "private/qdeclarativecompiler_p.h" +#include "private/qdeclarativevmemetaobject_p.h" + +#include <QStringList> +#include <QtCore/qdebug.h> + +#include <math.h> + +QT_BEGIN_NAMESPACE + +/*! +\class QDeclarativeProperty +\since 4.7 +\brief The QDeclarativeProperty class abstracts accessing properties on objects created from QML. + +As QML uses Qt's meta-type system all of the existing QMetaObject classes can be used to introspect +and interact with objects created by QML. However, some of the new features provided by QML - such +as type safety and attached properties - are most easily used through the QDeclarativeProperty class +that simplifies some of their natural complexity. + +Unlike QMetaProperty which represents a property on a class type, QDeclarativeProperty encapsulates +a property on a specific object instance. To read a property's value, programmers create a +QDeclarativeProperty instance and call the read() method. Likewise to write a property value the +write() method is used. + +For example, for the following QML code: + +\qml +// MyItem.qml +import QtQuick 1.0 + +Text { text: "A bit of text" } +\endqml + +The \l Text object's properties could be accessed using QDeclarativeProperty, like this: + +\code +#include <QDeclarativeProperty> +#include <QGraphicsObject> + +... + +QDeclarativeView view(QUrl::fromLocalFile("MyItem.qml")); +QDeclarativeProperty property(view.rootObject(), "font.pixelSize"); +qWarning() << "Current pixel size:" << property.read().toInt(); +property.write(24); +qWarning() << "Pixel size should now be 24:" << property.read().toInt(); +\endcode +*/ + +/*! + Create an invalid QDeclarativeProperty. +*/ +QDeclarativeProperty::QDeclarativeProperty() +: d(0) +{ +} + +/*! \internal */ +QDeclarativeProperty::~QDeclarativeProperty() +{ + if (d) + d->release(); + d = 0; +} + +/*! + Creates a QDeclarativeProperty for the default property of \a obj. If there is no + default property, an invalid QDeclarativeProperty will be created. + */ +QDeclarativeProperty::QDeclarativeProperty(QObject *obj) +: d(new QDeclarativePropertyPrivate) +{ + d->initDefault(obj); +} + +/*! + Creates a QDeclarativeProperty for the default property of \a obj + using the \l{QDeclarativeContext} {context} \a ctxt. If there is + no default property, an invalid QDeclarativeProperty will be + created. + */ +QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeContext *ctxt) +: d(new QDeclarativePropertyPrivate) +{ + d->context = ctxt?QDeclarativeContextData::get(ctxt):0; + d->engine = ctxt?ctxt->engine():0; + d->initDefault(obj); +} + +/*! + Creates a QDeclarativeProperty for the default property of \a obj + using the environment for instantiating QML components that is + provided by \a engine. If there is no default property, an + invalid QDeclarativeProperty will be created. + */ +QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeEngine *engine) + : d(new QDeclarativePropertyPrivate) +{ + d->context = 0; + d->engine = engine; + d->initDefault(obj); +} + +/*! + Initialize from the default property of \a obj +*/ +void QDeclarativePropertyPrivate::initDefault(QObject *obj) +{ + if (!obj) + return; + + QMetaProperty p = QDeclarativeMetaType::defaultProperty(obj); + core.load(p); + if (core.isValid()) + object = obj; +} + +/*! + Creates a QDeclarativeProperty for the property \a name of \a obj. + */ +QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name) +: d(new QDeclarativePropertyPrivate) +{ + d->initProperty(obj, name); + if (!isValid()) d->object = 0; +} + +/*! + Creates a QDeclarativeProperty for the property \a name of \a obj + using the \l{QDeclarativeContext} {context} \a ctxt. + + Creating a QDeclarativeProperty without a context will render some + properties - like attached properties - inaccessible. +*/ +QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeContext *ctxt) +: d(new QDeclarativePropertyPrivate) +{ + d->context = ctxt?QDeclarativeContextData::get(ctxt):0; + d->engine = ctxt?ctxt->engine():0; + d->initProperty(obj, name); + if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; } +} + +/*! + Creates a QDeclarativeProperty for the property \a name of \a obj + using the environment for instantiating QML components that is + provided by \a engine. + */ +QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeEngine *engine) +: d(new QDeclarativePropertyPrivate) +{ + d->context = 0; + d->engine = engine; + d->initProperty(obj, name); + if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; } +} + +Q_GLOBAL_STATIC(QDeclarativeValueTypeFactory, qmlValueTypes); + +void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name) +{ + if (!obj) return; + + QDeclarativeTypeNameCache *typeNameCache = context?context->imports:0; + + QStringList path = name.split(QLatin1Char('.')); + if (path.isEmpty()) return; + + QObject *currentObject = obj; + + // Everything up to the last property must be an "object type" property + for (int ii = 0; ii < path.count() - 1; ++ii) { + const QString &pathName = path.at(ii); + + if (QDeclarativeTypeNameCache::Data *data = typeNameCache?typeNameCache->data(pathName):0) { + if (data->type) { + QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction(); + if (!func) return; // Not an attachable type + + currentObject = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), currentObject); + if (!currentObject) return; // Something is broken with the attachable type + } else { + Q_ASSERT(data->typeNamespace); + if ((ii + 1) == path.count()) return; // No type following the namespace + + ++ii; data = data->typeNamespace->data(path.at(ii)); + if (!data || !data->type) return; // Invalid type in namespace + + QDeclarativeAttachedPropertiesFunc func = data->type->attachedPropertiesFunction(); + if (!func) return; // Not an attachable type + + currentObject = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), currentObject); + if (!currentObject) return; // Something is broken with the attachable type + } + } else { + + QDeclarativePropertyCache::Data local; + QDeclarativePropertyCache::Data *property = + QDeclarativePropertyCache::property(engine, obj, pathName, local); + + if (!property) return; // Not a property + if (property->flags & QDeclarativePropertyCache::Data::IsFunction) + return; // Not an object property + + if (ii == (path.count() - 2) && QDeclarativeValueTypeFactory::isValueType(property->propType)) { + // We're now at a value type property. We can use a global valuetypes array as we + // never actually use the objects, just look up their properties. + QObject *typeObject = (*qmlValueTypes())[property->propType]; + if (!typeObject) return; // Not a value type + + int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData()); + if (idx == -1) return; // Value type property does not exist + + QMetaProperty vtProp = typeObject->metaObject()->property(idx); + + object = currentObject; + core = *property; + valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(vtProp); + valueType.valueTypeCoreIdx = idx; + valueType.valueTypePropType = vtProp.userType(); + + return; + } else { + if (!(property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived)) + return; // Not an object property + + void *args[] = { ¤tObject, 0 }; + QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args); + if (!currentObject) return; // No value + + } + } + + } + + const QString &terminal = path.last(); + + if (terminal.count() >= 3 && + terminal.at(0) == QLatin1Char('o') && + terminal.at(1) == QLatin1Char('n') && + terminal.at(2).isUpper()) { + + QString signalName = terminal.mid(2); + signalName[0] = signalName.at(0).toLower(); + + QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName.toLatin1().constData()); + if (method.signature()) { + object = currentObject; + core.load(method); + return; + } + } + + // Property + QDeclarativePropertyCache::Data local; + QDeclarativePropertyCache::Data *property = + QDeclarativePropertyCache::property(engine, currentObject, terminal, local); + if (property && !(property->flags & QDeclarativePropertyCache::Data::IsFunction)) { + object = currentObject; + core = *property; + nameCache = terminal; + isNameCached = true; + } +} + +/*! + Create a copy of \a other. +*/ +QDeclarativeProperty::QDeclarativeProperty(const QDeclarativeProperty &other) +{ + d = other.d; + if (d) + d->addref(); +} + +/*! + \enum QDeclarativeProperty::PropertyTypeCategory + + This enum specifies a category of QML property. + + \value InvalidCategory The property is invalid, or is a signal property. + \value List The property is a QDeclarativeListProperty list property + \value Object The property is a QObject derived type pointer + \value Normal The property is a normal value property. + */ + +/*! + \enum QDeclarativeProperty::Type + + This enum specifies a type of QML property. + + \value Invalid The property is invalid. + \value Property The property is a regular Qt property. + \value SignalProperty The property is a signal property. +*/ + +/*! + Returns the property category. +*/ +QDeclarativeProperty::PropertyTypeCategory QDeclarativeProperty::propertyTypeCategory() const +{ + return d ? d->propertyTypeCategory() : InvalidCategory; +} + +QDeclarativeProperty::PropertyTypeCategory +QDeclarativePropertyPrivate::propertyTypeCategory() const +{ + uint type = this->type(); + + if (isValueType()) { + return QDeclarativeProperty::Normal; + } else if (type & QDeclarativeProperty::Property) { + int type = propertyType(); + if (type == QVariant::Invalid) + return QDeclarativeProperty::InvalidCategory; + else if (QDeclarativeValueTypeFactory::isValueType((uint)type)) + return QDeclarativeProperty::Normal; + else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) + return QDeclarativeProperty::Object; + else if (core.flags & QDeclarativePropertyCache::Data::IsQList) + return QDeclarativeProperty::List; + else + return QDeclarativeProperty::Normal; + } else { + return QDeclarativeProperty::InvalidCategory; + } +} + +/*! + Returns the type name of the property, or 0 if the property has no type + name. +*/ +const char *QDeclarativeProperty::propertyTypeName() const +{ + if (!d) + return 0; + if (d->isValueType()) { + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context); + QDeclarativeValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[d->core.propType]; + else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType); + Q_ASSERT(valueType); + + const char *rv = valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).typeName(); + + if (!ep) delete valueType; + + return rv; + } else if (d->object && type() & Property && d->core.isValid()) { + return d->object->metaObject()->property(d->core.coreIndex).typeName(); + } else { + return 0; + } +} + +/*! + Returns true if \a other and this QDeclarativeProperty represent the same + property. +*/ +bool QDeclarativeProperty::operator==(const QDeclarativeProperty &other) const +{ + if (!d || !other.d) + return false; + // category is intentially omitted here as it is generated + // from the other members + return d->object == other.d->object && + d->core == other.d->core && + d->valueType == other.d->valueType; +} + +/*! + Returns the QVariant type of the property, or QVariant::Invalid if the + property has no QVariant type. +*/ +int QDeclarativeProperty::propertyType() const +{ + return d ? d->propertyType() : int(QVariant::Invalid); +} + +bool QDeclarativePropertyPrivate::isValueType() const +{ + return valueType.valueTypeCoreIdx != -1; +} + +int QDeclarativePropertyPrivate::propertyType() const +{ + uint type = this->type(); + if (isValueType()) { + return valueType.valueTypePropType; + } else if (type & QDeclarativeProperty::Property) { + if (core.propType == (int)QVariant::LastType) + return qMetaTypeId<QVariant>(); + else + return core.propType; + } else { + return QVariant::Invalid; + } +} + +QDeclarativeProperty::Type QDeclarativePropertyPrivate::type() const +{ + if (core.flags & QDeclarativePropertyCache::Data::IsFunction) + return QDeclarativeProperty::SignalProperty; + else if (core.isValid()) + return QDeclarativeProperty::Property; + else + return QDeclarativeProperty::Invalid; +} + +/*! + Returns the type of the property. +*/ +QDeclarativeProperty::Type QDeclarativeProperty::type() const +{ + return d ? d->type() : Invalid; +} + +/*! + Returns true if this QDeclarativeProperty represents a regular Qt property. +*/ +bool QDeclarativeProperty::isProperty() const +{ + return type() & Property; +} + +/*! + Returns true if this QDeclarativeProperty represents a QML signal property. +*/ +bool QDeclarativeProperty::isSignalProperty() const +{ + return type() & SignalProperty; +} + +/*! + Returns the QDeclarativeProperty's QObject. +*/ +QObject *QDeclarativeProperty::object() const +{ + return d ? d->object : 0; +} + +/*! + Assign \a other to this QDeclarativeProperty. +*/ +QDeclarativeProperty &QDeclarativeProperty::operator=(const QDeclarativeProperty &other) +{ + if (d) + d->release(); + d = other.d; + if (d) + d->addref(); + + return *this; +} + +/*! + Returns true if the property is writable, otherwise false. +*/ +bool QDeclarativeProperty::isWritable() const +{ + if (!d) + return false; + if (!d->object) + return false; + if (d->core.flags & QDeclarativePropertyCache::Data::IsQList) //list + return true; + else if (d->core.flags & QDeclarativePropertyCache::Data::IsFunction) //signal handler + return false; + else if (d->core.isValid()) //normal property + return d->core.flags & QDeclarativePropertyCache::Data::IsWritable; + else + return false; +} + +/*! + Returns true if the property is designable, otherwise false. +*/ +bool QDeclarativeProperty::isDesignable() const +{ + if (!d) + return false; + if (type() & Property && d->core.isValid() && d->object) + return d->object->metaObject()->property(d->core.coreIndex).isDesignable(); + else + return false; +} + +/*! + Returns true if the property is resettable, otherwise false. +*/ +bool QDeclarativeProperty::isResettable() const +{ + if (!d) + return false; + if (type() & Property && d->core.isValid() && d->object) + return d->core.flags & QDeclarativePropertyCache::Data::IsResettable; + else + return false; +} + +/*! + Returns true if the QDeclarativeProperty refers to a valid property, otherwise + false. +*/ +bool QDeclarativeProperty::isValid() const +{ + if (!d) + return false; + return type() != Invalid; +} + +/*! + Return the name of this QML property. +*/ +QString QDeclarativeProperty::name() const +{ + if (!d) + return QString(); + if (!d->isNameCached) { + // ### + if (!d->object) { + } else if (d->isValueType()) { + QString rv = d->core.name(d->object) + QLatin1Char('.'); + + QDeclarativeEnginePrivate *ep = d->engine?QDeclarativeEnginePrivate::get(d->engine):0; + QDeclarativeValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[d->core.propType]; + else valueType = QDeclarativeValueTypeFactory::valueType(d->core.propType); + Q_ASSERT(valueType); + + rv += QString::fromUtf8(valueType->metaObject()->property(d->valueType.valueTypeCoreIdx).name()); + + if (!ep) delete valueType; + + d->nameCache = rv; + } else if (type() & SignalProperty) { + QString name = QLatin1String("on") + d->core.name(d->object); + name[2] = name.at(2).toUpper(); + d->nameCache = name; + } else { + d->nameCache = d->core.name(d->object); + } + d->isNameCached = true; + } + + return d->nameCache; +} + +/*! + Returns the \l{QMetaProperty} {Qt property} associated with + this QML property. + */ +QMetaProperty QDeclarativeProperty::property() const +{ + if (!d) + return QMetaProperty(); + if (type() & Property && d->core.isValid() && d->object) + return d->object->metaObject()->property(d->core.coreIndex); + else + return QMetaProperty(); +} + +/*! + Return the QMetaMethod for this property if it is a SignalProperty, + otherwise returns an invalid QMetaMethod. +*/ +QMetaMethod QDeclarativeProperty::method() const +{ + if (!d) + return QMetaMethod(); + if (type() & SignalProperty && d->object) + return d->object->metaObject()->method(d->core.coreIndex); + else + return QMetaMethod(); +} + +/*! + Returns the binding associated with this property, or 0 if no binding + exists. +*/ +QDeclarativeAbstractBinding * +QDeclarativePropertyPrivate::binding(const QDeclarativeProperty &that) +{ + if (!that.d || !that.isProperty() || !that.d->object) + return 0; + + return binding(that.d->object, that.d->core.coreIndex, that.d->valueType.valueTypeCoreIdx); +} + +/*! + Set the binding associated with this property to \a newBinding. Returns + the existing binding (if any), otherwise 0. + + \a newBinding will be enabled, and the returned binding (if any) will be + disabled. + + Ownership of \a newBinding transfers to QML. Ownership of the return value + is assumed by the caller. + + \a flags is passed through to the binding and is used for the initial update (when + the binding sets the initial value, it will use these flags for the write). +*/ +QDeclarativeAbstractBinding * +QDeclarativePropertyPrivate::setBinding(const QDeclarativeProperty &that, + QDeclarativeAbstractBinding *newBinding, + WriteFlags flags) +{ + if (!that.d || !that.isProperty() || !that.d->object) { + if (newBinding) + newBinding->destroy(); + return 0; + } + + return that.d->setBinding(that.d->object, that.d->core.coreIndex, + that.d->valueType.valueTypeCoreIdx, newBinding, flags); +} + +QDeclarativeAbstractBinding * +QDeclarativePropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex) +{ + QDeclarativeData *data = QDeclarativeData::get(object); + if (!data) + return 0; + + QDeclarativePropertyCache::Data *propertyData = + data->propertyCache?data->propertyCache->property(coreIndex):0; + if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) { + const QDeclarativeVMEMetaObject *vme = + static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex)); + + QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; + if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1) + return 0; + + // This will either be a value type sub-reference or an alias to a value-type sub-reference not both + Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); + return binding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex); + } + + if (!data->hasBindingBit(coreIndex)) + return 0; + + QDeclarativeAbstractBinding *binding = data->bindings; + while (binding && binding->propertyIndex() != coreIndex) + binding = binding->m_nextBinding; + + if (binding && valueTypeIndex != -1) { + if (binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) { + int index = coreIndex | (valueTypeIndex << 24); + binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index); + } + } + + return binding; +} + +void QDeclarativePropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, + QObject **targetObject, int *targetBindingIndex) +{ + int coreIndex = bindingIndex & 0xFFFFFF; + int valueTypeIndex = bindingIndex >> 24; + if (valueTypeIndex == 0) valueTypeIndex = -1; + + QDeclarativeData *data = QDeclarativeData::get(object, false); + if (data) { + QDeclarativePropertyCache::Data *propertyData = + data->propertyCache?data->propertyCache->property(coreIndex):0; + if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) { + const QDeclarativeVMEMetaObject *vme = + static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex)); + QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; + if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { + // This will either be a value type sub-reference or an alias to a value-type sub-reference not both + Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); + + int aBindingIndex = aCoreIndex; + if (aValueTypeIndex != -1) + aBindingIndex |= aValueTypeIndex << 24; + else if (valueTypeIndex != -1) + aBindingIndex |= valueTypeIndex << 24; + + findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex); + return; + } + } + } + + *targetObject = object; + *targetBindingIndex = bindingIndex; +} + +QDeclarativeAbstractBinding * +QDeclarativePropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeIndex, + QDeclarativeAbstractBinding *newBinding, WriteFlags flags) +{ + QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding); + QDeclarativeAbstractBinding *binding = 0; + + if (data) { + QDeclarativePropertyCache::Data *propertyData = + data->propertyCache?data->propertyCache->property(coreIndex):0; + if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) { + const QDeclarativeVMEMetaObject *vme = + static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex)); + + QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; + if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { + if (newBinding) newBinding->destroy(); + return 0; + } + + // This will either be a value type sub-reference or an alias to a value-type sub-reference not both + Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); + return setBinding(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex, + newBinding, flags); + } + } + + if (data && data->hasBindingBit(coreIndex)) { + binding = data->bindings; + + while (binding && binding->propertyIndex() != coreIndex) + binding = binding->m_nextBinding; + } + + int index = coreIndex; + if (valueTypeIndex != -1) + index |= (valueTypeIndex << 24); + + if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) + binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index); + + if (binding) { + binding->removeFromObject(); + binding->setEnabled(false, 0); + } + + if (newBinding) { + newBinding->addToObject(object, index); + newBinding->setEnabled(true, flags); + } + + return binding; +} + +QDeclarativeAbstractBinding * +QDeclarativePropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valueTypeIndex, + QDeclarativeAbstractBinding *newBinding) +{ + QDeclarativeData *data = QDeclarativeData::get(object, 0 != newBinding); + QDeclarativeAbstractBinding *binding = 0; + + if (data) { + QDeclarativePropertyCache::Data *propertyData = + data->propertyCache?data->propertyCache->property(coreIndex):0; + if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) { + const QDeclarativeVMEMetaObject *vme = + static_cast<const QDeclarativeVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex)); + + QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; + if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { + if (newBinding) newBinding->destroy(); + return 0; + } + + // This will either be a value type sub-reference or an alias to a value-type sub-reference not both + Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); + return setBindingNoEnable(aObject, aCoreIndex, (valueTypeIndex == -1)?aValueTypeIndex:valueTypeIndex, + newBinding); + } + } + + if (data && data->hasBindingBit(coreIndex)) { + binding = data->bindings; + + while (binding && binding->propertyIndex() != coreIndex) + binding = binding->m_nextBinding; + } + + int index = coreIndex; + if (valueTypeIndex != -1) + index |= (valueTypeIndex << 24); + + if (binding && valueTypeIndex != -1 && binding->bindingType() == QDeclarativeAbstractBinding::ValueTypeProxy) + binding = static_cast<QDeclarativeValueTypeProxyBinding *>(binding)->binding(index); + + if (binding) + binding->removeFromObject(); + + if (newBinding) + newBinding->addToObject(object, index); + + return binding; +} + +/*! + Returns the expression associated with this signal property, or 0 if no + signal expression exists. +*/ +QDeclarativeExpression * +QDeclarativePropertyPrivate::signalExpression(const QDeclarativeProperty &that) +{ + if (!(that.type() & QDeclarativeProperty::SignalProperty)) + return 0; + + const QObjectList &children = that.d->object->children(); + + for (int ii = 0; ii < children.count(); ++ii) { + QObject *child = children.at(ii); + + QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child); + if (signal && signal->index() == that.index()) + return signal->expression(); + } + + return 0; +} + +/*! + Set the signal expression associated with this signal property to \a expr. + Returns the existing signal expression (if any), otherwise 0. + + Ownership of \a expr transfers to QML. Ownership of the return value is + assumed by the caller. +*/ +QDeclarativeExpression * +QDeclarativePropertyPrivate::setSignalExpression(const QDeclarativeProperty &that, + QDeclarativeExpression *expr) +{ + if (!(that.type() & QDeclarativeProperty::SignalProperty)) { + delete expr; + return 0; + } + + const QObjectList &children = that.d->object->children(); + + for (int ii = 0; ii < children.count(); ++ii) { + QObject *child = children.at(ii); + + QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child); + if (signal && signal->index() == that.index()) + return signal->setExpression(expr); + } + + if (expr) { + QDeclarativeBoundSignal *signal = new QDeclarativeBoundSignal(that.d->object, that.method(), that.d->object); + return signal->setExpression(expr); + } else { + return 0; + } +} + +/*! + Returns the property value. +*/ +QVariant QDeclarativeProperty::read() const +{ + if (!d) + return QVariant(); + if (!d->object) + return QVariant(); + + if (type() & SignalProperty) { + + return QVariant(); + + } else if (type() & Property) { + + return d->readValueProperty(); + + } + return QVariant(); +} + +/*! +Return the \a name property value of \a object. This method is equivalent to: +\code + QDeclarativeProperty p(object, name); + p.read(); +\endcode +*/ +QVariant QDeclarativeProperty::read(QObject *object, const QString &name) +{ + QDeclarativeProperty p(object, name); + return p.read(); +} + +/*! + Return the \a name property value of \a object using the + \l{QDeclarativeContext} {context} \a ctxt. This method is + equivalent to: + + \code + QDeclarativeProperty p(object, name, context); + p.read(); + \endcode +*/ +QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeContext *ctxt) +{ + QDeclarativeProperty p(object, name, ctxt); + return p.read(); +} + +/*! + + Return the \a name property value of \a object using the environment + for instantiating QML components that is provided by \a engine. . + This method is equivalent to: + + \code + QDeclarativeProperty p(object, name, engine); + p.read(); + \endcode +*/ +QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeEngine *engine) +{ + QDeclarativeProperty p(object, name, engine); + return p.read(); +} + +QVariant QDeclarativePropertyPrivate::readValueProperty() +{ + if (isValueType()) { + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context); + QDeclarativeValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[core.propType]; + else valueType = QDeclarativeValueTypeFactory::valueType(core.propType); + Q_ASSERT(valueType); + + valueType->read(object, core.coreIndex); + + QVariant rv = + valueType->metaObject()->property(this->valueType.valueTypeCoreIdx).read(valueType); + + if (!ep) delete valueType; + return rv; + + } else if (core.flags & QDeclarativePropertyCache::Data::IsQList) { + + QDeclarativeListProperty<QObject> prop; + void *args[] = { &prop, 0 }; + QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args); + return QVariant::fromValue(QDeclarativeListReferencePrivate::init(prop, core.propType, engine)); + + } else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) { + + QObject *rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args); + return QVariant::fromValue(rv); + + } else { + + return object->metaObject()->property(core.coreIndex).read(object.data()); + + } +} + +//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC! +bool QDeclarativePropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags) +{ + if (!object || !prop.isWritable()) + return false; + + QVariant v = value; + if (prop.isEnumType()) { + QMetaEnum menum = prop.enumerator(); + if (v.userType() == QVariant::String +#ifdef QT3_SUPPORT + || v.userType() == QVariant::CString +#endif + ) { + if (prop.isFlagType()) + v = QVariant(menum.keysToValue(value.toByteArray())); + else + v = QVariant(menum.keyToValue(value.toByteArray())); + } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) { + int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name())); + if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData()) + return false; + v = QVariant(*reinterpret_cast<const int *>(v.constData())); + } + v.convert(QVariant::Int); + } + + // the status variable is changed by qt_metacall to indicate what it did + // this feature is currently only used by QtDBus and should not be depended + // upon. Don't change it without looking into QDBusAbstractInterface first + // -1 (unchanged): normal qt_metacall, result stored in argv[0] + // changed: result stored directly in value, return the value of status + int status = -1; + void *argv[] = { v.data(), &v, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, idx, argv); + return status; +} + +bool QDeclarativePropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags) +{ + // Remove any existing bindings on this property + if (!(flags & DontRemoveBinding) && + (type() & QDeclarativeProperty::Property) && object) { + QDeclarativeAbstractBinding *binding = setBinding(object, core.coreIndex, + valueType.valueTypeCoreIdx, 0, flags); + if (binding) binding->destroy(); + } + + bool rv = false; + if (isValueType()) { + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context); + + QDeclarativeValueType *writeBack = 0; + if (ep) { + writeBack = ep->valueTypes[core.propType]; + } else { + writeBack = QDeclarativeValueTypeFactory::valueType(core.propType); + } + + writeBack->read(object, core.coreIndex); + + QDeclarativePropertyCache::Data data = core; + data.flags = valueType.flags; + data.coreIndex = valueType.valueTypeCoreIdx; + data.propType = valueType.valueTypePropType; + rv = write(writeBack, data, value, context, flags); + + writeBack->write(object, core.coreIndex, flags); + if (!ep) delete writeBack; + + } else { + + rv = write(object, core, value, context, flags); + + } + + return rv; +} + +bool QDeclarativePropertyPrivate::write(QObject *object, const QDeclarativePropertyCache::Data &property, + const QVariant &value, QDeclarativeContextData *context, + WriteFlags flags) +{ + int coreIdx = property.coreIndex; + int status = -1; //for dbus + + if (property.flags & QDeclarativePropertyCache::Data::IsEnumType) { + QMetaProperty prop = object->metaObject()->property(property.coreIndex); + QVariant v = value; + // Enum values come through the script engine as doubles + if (value.userType() == QVariant::Double) { + double integral; + double fractional = modf(value.toDouble(), &integral); + if (qFuzzyIsNull(fractional)) + v.convert(QVariant::Int); + } + return writeEnumProperty(prop, coreIdx, object, v, flags); + } + + int propertyType = property.propType; + int variantType = value.userType(); + + QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(context); + + if (propertyType == QVariant::Url) { + + QUrl u; + bool found = false; + if (variantType == QVariant::Url) { + u = value.toUrl(); + found = true; + } else if (variantType == QVariant::ByteArray) { + u = QUrl(QString::fromUtf8(value.toByteArray())); + found = true; + } else if (variantType == QVariant::String) { + u = QUrl(value.toString()); + found = true; + } + + if (!found) + return false; + + if (context && u.isRelative() && !u.isEmpty()) + u = context->resolvedUrl(u); + int status = -1; + void *argv[] = { &u, 0, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv); + + } else if (variantType == propertyType) { + + void *a[] = { (void *)value.constData(), 0, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + + } else if (qMetaTypeId<QVariant>() == propertyType) { + + void *a[] = { (void *)&value, 0, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + + } else if (property.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) { + + const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType()); + + if (!valMo) + return false; + + QObject *o = *(QObject **)value.constData(); + const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType); + + if (o) valMo = o->metaObject(); + + if (canConvert(valMo, propMo)) { + void *args[] = { &o, 0, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, + args); + } else if (!o && canConvert(propMo, valMo)) { + // In the case of a null QObject, we assign the null if there is + // any change that the null variant type could be up or down cast to + // the property type. + void *args[] = { &o, 0, &status, &flags }; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, + args); + } else { + return false; + } + + } else if (property.flags & QDeclarativePropertyCache::Data::IsQList) { + + const QMetaObject *listType = 0; + if (enginePriv) { + listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType)); + } else { + QDeclarativeType *type = QDeclarativeMetaType::qmlType(QDeclarativeMetaType::listType(property.propType)); + if (!type) return false; + listType = type->baseMetaObject(); + } + if (!listType) return false; + + QDeclarativeListProperty<void> prop; + void *args[] = { &prop, 0 }; + QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args); + + if (!prop.clear) return false; + + prop.clear(&prop); + + if (value.userType() == qMetaTypeId<QList<QObject *> >()) { + const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value); + + for (int ii = 0; ii < list.count(); ++ii) { + QObject *o = list.at(ii); + if (o && !canConvert(o->metaObject(), listType)) + o = 0; + prop.append(&prop, (void *)o); + } + } else { + QObject *o = enginePriv?enginePriv->toQObject(value):QDeclarativeMetaType::toQObject(value); + if (o && !canConvert(o->metaObject(), listType)) + o = 0; + prop.append(&prop, (void *)o); + } + + } else { + Q_ASSERT(variantType != propertyType); + + bool ok = false; + QVariant v; + if (variantType == QVariant::String) + v = QDeclarativeStringConverters::variantFromString(value.toString(), propertyType, &ok); + if (!ok) { + v = value; + if (v.convert((QVariant::Type)propertyType)) { + ok = true; + } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) { + QDeclarativeMetaType::StringConverter con = QDeclarativeMetaType::customStringConverter(propertyType); + if (con) { + v = con(value.toString()); + if (v.userType() == propertyType) + ok = true; + } + } + } + if (ok) { + void *a[] = { (void *)v.constData(), 0, &status, &flags}; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + } else { + return false; + } + } + + return true; +} + +const QMetaObject *QDeclarativePropertyPrivate::rawMetaObjectForType(QDeclarativeEnginePrivate *engine, int userType) +{ + if (engine) { + return engine->rawMetaObjectForType(userType); + } else { + QDeclarativeType *type = QDeclarativeMetaType::qmlType(userType); + return type?type->baseMetaObject():0; + } +} + +/*! + Sets the property value to \a value and returns true. + Returns false if the property can't be set because the + \a value is the wrong type, for example. + */ +bool QDeclarativeProperty::write(const QVariant &value) const +{ + return QDeclarativePropertyPrivate::write(*this, value, 0); +} + +/*! + Writes \a value to the \a name property of \a object. This method + is equivalent to: + + \code + QDeclarativeProperty p(object, name); + p.write(value); + \endcode +*/ +bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value) +{ + QDeclarativeProperty p(object, name); + return p.write(value); +} + +/*! + Writes \a value to the \a name property of \a object using the + \l{QDeclarativeContext} {context} \a ctxt. This method is + equivalent to: + + \code + QDeclarativeProperty p(object, name, ctxt); + p.write(value); + \endcode +*/ +bool QDeclarativeProperty::write(QObject *object, + const QString &name, + const QVariant &value, + QDeclarativeContext *ctxt) +{ + QDeclarativeProperty p(object, name, ctxt); + return p.write(value); +} + +/*! + + Writes \a value to the \a name property of \a object using the + environment for instantiating QML components that is provided by + \a engine. This method is equivalent to: + + \code + QDeclarativeProperty p(object, name, engine); + p.write(value); + \endcode +*/ +bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value, + QDeclarativeEngine *engine) +{ + QDeclarativeProperty p(object, name, engine); + return p.write(value); +} + +/*! + Resets the property and returns true if the property is + resettable. If the property is not resettable, nothing happens + and false is returned. +*/ +bool QDeclarativeProperty::reset() const +{ + if (isResettable()) { + void *args[] = { 0 }; + QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args); + return true; + } else { + return false; + } +} + +bool QDeclarativePropertyPrivate::write(const QDeclarativeProperty &that, + const QVariant &value, WriteFlags flags) +{ + if (!that.d) + return false; + if (that.d->object && that.type() & QDeclarativeProperty::Property && + that.d->core.isValid() && that.isWritable()) + return that.d->writeValueProperty(value, flags); + else + return false; +} + +/*! + Returns true if the property has a change notifier signal, otherwise false. +*/ +bool QDeclarativeProperty::hasNotifySignal() const +{ + if (type() & Property && d->object) { + return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal(); + } + return false; +} + +/*! + Returns true if the property needs a change notifier signal for bindings + to remain upto date, false otherwise. + + Some properties, such as attached properties or those whose value never + changes, do not require a change notifier. +*/ +bool QDeclarativeProperty::needsNotifySignal() const +{ + return type() & Property && !property().isConstant(); +} + +/*! + Connects the property's change notifier signal to the + specified \a method of the \a dest object and returns + true. Returns false if this metaproperty does not + represent a regular Qt property or if it has no + change notifier signal, or if the \a dest object does + not have the specified \a method. +*/ +bool QDeclarativeProperty::connectNotifySignal(QObject *dest, int method) const +{ + if (!(type() & Property) || !d->object) + return false; + + QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex); + if (prop.hasNotifySignal()) { + return QDeclarativePropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection); + } else { + return false; + } +} + +/*! + Connects the property's change notifier signal to the + specified \a slot of the \a dest object and returns + true. Returns false if this metaproperty does not + represent a regular Qt property or if it has no + change notifier signal, or if the \a dest object does + not have the specified \a slot. +*/ +bool QDeclarativeProperty::connectNotifySignal(QObject *dest, const char *slot) const +{ + if (!(type() & Property) || !d->object) + return false; + + QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex); + if (prop.hasNotifySignal()) { + QByteArray signal(QByteArray("2") + prop.notifySignal().signature()); + return QObject::connect(d->object, signal.constData(), dest, slot); + } else { + return false; + } +} + +/*! + Return the Qt metaobject index of the property. +*/ +int QDeclarativeProperty::index() const +{ + return d ? d->core.coreIndex : -1; +} + +int QDeclarativePropertyPrivate::valueTypeCoreIndex(const QDeclarativeProperty &that) +{ + return that.d ? that.d->valueType.valueTypeCoreIdx : -1; +} + +/*! + Returns the "property index" for use in bindings. The top 8 bits are the value type + offset, and 0 otherwise. The bottom 24-bits are the regular property index. +*/ +int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativeProperty &that) +{ + if (!that.d) + return -1; + int rv = that.d->core.coreIndex; + if (rv != -1 && that.d->valueType.valueTypeCoreIdx != -1) + rv = rv | (that.d->valueType.valueTypeCoreIdx << 24); + return rv; +} + +struct SerializedData { + bool isValueType; + QDeclarativePropertyCache::Data core; +}; + +struct ValueTypeSerializedData : public SerializedData { + QDeclarativePropertyCache::ValueTypeData valueType; +}; + +QByteArray QDeclarativePropertyPrivate::saveValueType(const QMetaObject *metaObject, int index, + const QMetaObject *subObject, int subIndex) +{ + QMetaProperty prop = metaObject->property(index); + QMetaProperty subProp = subObject->property(subIndex); + + ValueTypeSerializedData sd; + memset(&sd, 0, sizeof(sd)); + sd.isValueType = true; + sd.core.load(metaObject->property(index)); + sd.valueType.flags = QDeclarativePropertyCache::Data::flagsForProperty(subProp); + sd.valueType.valueTypeCoreIdx = subIndex; + sd.valueType.valueTypePropType = subProp.userType(); + + QByteArray rv((const char *)&sd, sizeof(sd)); + + return rv; +} + +QByteArray QDeclarativePropertyPrivate::saveProperty(const QMetaObject *metaObject, int index) +{ + SerializedData sd; + memset(&sd, 0, sizeof(sd)); + sd.isValueType = false; + sd.core.load(metaObject->property(index)); + + QByteArray rv((const char *)&sd, sizeof(sd)); + return rv; +} + +QDeclarativeProperty +QDeclarativePropertyPrivate::restore(const QByteArray &data, QObject *object, QDeclarativeContextData *ctxt) +{ + QDeclarativeProperty prop; + + if (data.isEmpty()) + return prop; + + const SerializedData *sd = (const SerializedData *)data.constData(); + if (sd->isValueType) { + const ValueTypeSerializedData *vt = (const ValueTypeSerializedData *)sd; + return restore(vt->core, vt->valueType, object, ctxt); + } else { + QDeclarativePropertyCache::ValueTypeData data; + return restore(sd->core, data, object, ctxt); + } +} + +QDeclarativeProperty +QDeclarativePropertyPrivate::restore(const QDeclarativePropertyCache::Data &data, const QDeclarativePropertyCache::ValueTypeData &valueType, QObject *object, QDeclarativeContextData *ctxt) +{ + QDeclarativeProperty prop; + + prop.d = new QDeclarativePropertyPrivate; + prop.d->object = object; + prop.d->context = ctxt; + prop.d->engine = ctxt->engine; + + prop.d->core = data; + prop.d->valueType = valueType; + + return prop; +} + +/*! + Returns true if lhs and rhs refer to the same metaobject data +*/ +bool QDeclarativePropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs) +{ + return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata); +} + +/*! + Returns true if from inherits to. +*/ +bool QDeclarativePropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to) +{ + if (from && to == &QObject::staticMetaObject) + return true; + + while (from) { + if (equal(from, to)) + return true; + from = from->superClass(); + } + + return false; +} + +/*! + Return the signal corresponding to \a name +*/ +QMetaMethod QDeclarativePropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name) +{ + Q_ASSERT(mo); + int methods = mo->methodCount(); + for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal + QMetaMethod method = mo->method(ii); + QByteArray methodName = method.signature(); + int idx = methodName.indexOf('('); + methodName = methodName.left(idx); + + if (methodName == name) + return method; + } + + // If no signal is found, but the signal is of the form "onBlahChanged", + // return the notify signal for the property "Blah" + if (name.endsWith("Changed")) { + QByteArray propName = name.mid(0, name.length() - 7); + int propIdx = mo->indexOfProperty(propName.constData()); + if (propIdx >= 0) { + QMetaProperty prop = mo->property(propIdx); + if (prop.hasNotifySignal()) + return prop.notifySignal(); + } + } + + return QMetaMethod(); +} + +static inline int QMetaObject_methods(const QMetaObject *metaObject) +{ + struct Private + { + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + int propertyCount, propertyData; + }; + + return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount; +} + +static inline int QMetaObject_properties(const QMetaObject *metaObject) +{ + struct Private + { + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + int propertyCount, propertyData; + }; + + return reinterpret_cast<const Private *>(metaObject->d.data)->propertyCount; +} + +static inline void flush_vme_signal(const QObject *object, int index) +{ + QDeclarativeData *data = static_cast<QDeclarativeData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData); + if (data && data->propertyCache) { + QDeclarativePropertyCache::Data *property = data->propertyCache->method(index); + + if (property && property->flags & QDeclarativePropertyCache::Data::IsVMESignal) { + const QMetaObject *metaObject = object->metaObject(); + int methodOffset = metaObject->methodOffset(); + + while (methodOffset > index) { + metaObject = metaObject->d.superdata; + methodOffset -= QMetaObject_methods(metaObject); + } + + QDeclarativeVMEMetaObject *vme = + static_cast<QDeclarativeVMEMetaObject *>(const_cast<QMetaObject *>(metaObject)); + + vme->connectAliasSignal(index); + } + } +} + +/*! +Connect \a sender \a signal_index to \a receiver \a method_index with the specified +\a type and \a types. This behaves identically to QMetaObject::connect() except that +it connects any lazy "proxy" signal connections set up by QML. + +It is possible that this logic should be moved to QMetaObject::connect(). +*/ +bool QDeclarativePropertyPrivate::connect(const QObject *sender, int signal_index, + const QObject *receiver, int method_index, + int type, int *types) +{ + flush_vme_signal(sender, signal_index); + flush_vme_signal(receiver, method_index); + + return QMetaObject::connect(sender, signal_index, receiver, method_index, type, types); +} + +/*! +Return \a metaObject's [super] meta object that provides data for \a property. +*/ +const QMetaObject *QDeclarativePropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property) +{ + int propertyOffset = metaObject->propertyOffset(); + + while (propertyOffset > property) { + metaObject = metaObject->d.superdata; + propertyOffset -= QMetaObject_properties(metaObject); + } + + return metaObject; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeproperty.h b/src/declarative/qml/qdeclarativeproperty.h new file mode 100644 index 00000000..b58d7800 --- /dev/null +++ b/src/declarative/qml/qdeclarativeproperty.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPROPERTY_H +#define QDECLARATIVEPROPERTY_H + +#include <QtCore/qmetaobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QObject; +class QVariant; +class QDeclarativeContext; +class QDeclarativeEngine; + +class QDeclarativePropertyPrivate; +class Q_DECLARATIVE_EXPORT QDeclarativeProperty +{ +public: + enum PropertyTypeCategory { + InvalidCategory, + List, + Object, + Normal + }; + + enum Type { + Invalid, + Property, + SignalProperty + }; + + QDeclarativeProperty(); + ~QDeclarativeProperty(); + + QDeclarativeProperty(QObject *); + QDeclarativeProperty(QObject *, QDeclarativeContext *); + QDeclarativeProperty(QObject *, QDeclarativeEngine *); + + QDeclarativeProperty(QObject *, const QString &); + QDeclarativeProperty(QObject *, const QString &, QDeclarativeContext *); + QDeclarativeProperty(QObject *, const QString &, QDeclarativeEngine *); + + QDeclarativeProperty(const QDeclarativeProperty &); + QDeclarativeProperty &operator=(const QDeclarativeProperty &); + + bool operator==(const QDeclarativeProperty &) const; + + Type type() const; + bool isValid() const; + bool isProperty() const; + bool isSignalProperty() const; + + int propertyType() const; + PropertyTypeCategory propertyTypeCategory() const; + const char *propertyTypeName() const; + + QString name() const; + + QVariant read() const; + static QVariant read(QObject *, const QString &); + static QVariant read(QObject *, const QString &, QDeclarativeContext *); + static QVariant read(QObject *, const QString &, QDeclarativeEngine *); + + bool write(const QVariant &) const; + static bool write(QObject *, const QString &, const QVariant &); + static bool write(QObject *, const QString &, const QVariant &, QDeclarativeContext *); + static bool write(QObject *, const QString &, const QVariant &, QDeclarativeEngine *); + + bool reset() const; + + bool hasNotifySignal() const; + bool needsNotifySignal() const; + bool connectNotifySignal(QObject *dest, const char *slot) const; + bool connectNotifySignal(QObject *dest, int method) const; + + bool isWritable() const; + bool isDesignable() const; + bool isResettable() const; + QObject *object() const; + + int index() const; + QMetaProperty property() const; + QMetaMethod method() const; + +private: + friend class QDeclarativePropertyPrivate; + QDeclarativePropertyPrivate *d; +}; +typedef QList<QDeclarativeProperty> QDeclarativeProperties; + +inline uint qHash (const QDeclarativeProperty &key) +{ + return qHash(key.object()) + qHash(key.name()); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEPROPERTY_H diff --git a/src/declarative/qml/qdeclarativeproperty_p.h b/src/declarative/qml/qdeclarativeproperty_p.h new file mode 100644 index 00000000..40b25ca2 --- /dev/null +++ b/src/declarative/qml/qdeclarativeproperty_p.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPROPERTY_P_H +#define QDECLARATIVEPROPERTY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativeproperty.h" + +#include <private/qobject_p.h> +#include <private/qdeclarativeglobal_p.h> +#include <private/qdeclarativepropertycache_p.h> +#include <private/qdeclarativeguard_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeContext; +class QDeclarativeEnginePrivate; +class QDeclarativeExpression; +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativePropertyPrivate : public QDeclarativeRefCount +{ +public: + enum WriteFlag { BypassInterceptor = 0x01, DontRemoveBinding = 0x02, RemoveBindingOnAliasWrite = 0x04 }; + Q_DECLARE_FLAGS(WriteFlags, WriteFlag) + + QDeclarativePropertyPrivate() + : context(0), engine(0), object(0), isNameCached(false) {} + + QDeclarativeContextData *context; + QDeclarativeEngine *engine; + QDeclarativeGuard<QObject> object; + + bool isNameCached:1; + QDeclarativePropertyCache::Data core; + QString nameCache; + + // Describes the "virtual" value-type sub-property. + QDeclarativePropertyCache::ValueTypeData valueType; + + void initProperty(QObject *obj, const QString &name); + void initDefault(QObject *obj); + + bool isValueType() const; + int propertyType() const; + QDeclarativeProperty::Type type() const; + QDeclarativeProperty::PropertyTypeCategory propertyTypeCategory() const; + + QVariant readValueProperty(); + bool writeValueProperty(const QVariant &, WriteFlags); + + static const QMetaObject *rawMetaObjectForType(QDeclarativeEnginePrivate *, int); + static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, + const QVariant &value, int flags); + static bool write(QObject *, const QDeclarativePropertyCache::Data &, const QVariant &, + QDeclarativeContextData *, WriteFlags flags = 0); + static void findAliasTarget(QObject *, int, QObject **, int *); + static QDeclarativeAbstractBinding *setBinding(QObject *, int coreIndex, int valueTypeIndex /* -1 */, + QDeclarativeAbstractBinding *, + WriteFlags flags = DontRemoveBinding); + static QDeclarativeAbstractBinding *setBindingNoEnable(QObject *, int coreIndex, int valueTypeIndex /* -1 */, + QDeclarativeAbstractBinding *); + static QDeclarativeAbstractBinding *binding(QObject *, int coreIndex, int valueTypeIndex /* -1 */); + + static QByteArray saveValueType(const QMetaObject *, int, + const QMetaObject *, int); + static QByteArray saveProperty(const QMetaObject *, int); + + static QDeclarativeProperty restore(const QByteArray &, QObject *, QDeclarativeContextData *); + static QDeclarativeProperty restore(const QDeclarativePropertyCache::Data &, + const QDeclarativePropertyCache::ValueTypeData &, + QObject *, + QDeclarativeContextData *); + + static bool equal(const QMetaObject *, const QMetaObject *); + static bool canConvert(const QMetaObject *from, const QMetaObject *to); + + // "Public" (to QML) methods + static QDeclarativeAbstractBinding *binding(const QDeclarativeProperty &that); + static QDeclarativeAbstractBinding *setBinding(const QDeclarativeProperty &that, + QDeclarativeAbstractBinding *, + WriteFlags flags = DontRemoveBinding); + static QDeclarativeExpression *signalExpression(const QDeclarativeProperty &that); + static QDeclarativeExpression *setSignalExpression(const QDeclarativeProperty &that, + QDeclarativeExpression *) ; + static bool write(const QDeclarativeProperty &that, const QVariant &, WriteFlags); + static int valueTypeCoreIndex(const QDeclarativeProperty &that); + static int bindingIndex(const QDeclarativeProperty &that); + static QMetaMethod findSignalByName(const QMetaObject *mo, const QByteArray &); + static bool connect(const QObject *sender, int signal_index, + const QObject *receiver, int method_index, + int type = 0, int *types = 0); + static const QMetaObject *metaObjectForProperty(const QMetaObject *, int); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePropertyPrivate::WriteFlags) + +QT_END_NAMESPACE + +#endif // QDECLARATIVEPROPERTY_P_H diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp new file mode 100644 index 00000000..7ce5ab9e --- /dev/null +++ b/src/declarative/qml/qdeclarativepropertycache.cpp @@ -0,0 +1,471 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativepropertycache_p.h" + +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativebinding_p.h" +#include <QtCore/qdebug.h> + +Q_DECLARE_METATYPE(QScriptValue) + +QT_BEGIN_NAMESPACE + +QDeclarativePropertyCache::Data::Flags QDeclarativePropertyCache::Data::flagsForProperty(const QMetaProperty &p, QDeclarativeEngine *engine) +{ + int propType = p.userType(); + + Flags flags; + + if (p.isConstant()) + flags |= Data::IsConstant; + if (p.isWritable()) + flags |= Data::IsWritable; + if (p.isResettable()) + flags |= Data::IsResettable; + + if (propType == qMetaTypeId<QDeclarativeBinding *>()) { + flags |= Data::IsQmlBinding; + } else if (propType == qMetaTypeId<QScriptValue>()) { + flags |= Data::IsQScriptValue; + } else if (p.isEnumType()) { + flags |= Data::IsEnumType; + } else { + QDeclarativeMetaType::TypeCategory cat = engine ? QDeclarativeEnginePrivate::get(engine)->typeCategory(propType) + : QDeclarativeMetaType::typeCategory(propType); + if (cat == QDeclarativeMetaType::Object) + flags |= Data::IsQObjectDerived; + else if (cat == QDeclarativeMetaType::List) + flags |= Data::IsQList; + } + + return flags; +} + +void QDeclarativePropertyCache::Data::load(const QMetaProperty &p, QDeclarativeEngine *engine) +{ + propType = p.userType(); + if (QVariant::Type(propType) == QVariant::LastType) + propType = qMetaTypeId<QVariant>(); + coreIndex = p.propertyIndex(); + notifyIndex = p.notifySignalIndex(); + flags = flagsForProperty(p, engine); + revision = p.revision(); +} + +void QDeclarativePropertyCache::Data::load(const QMetaMethod &m) +{ + coreIndex = m.methodIndex(); + relatedIndex = -1; + flags |= Data::IsFunction; + if (m.methodType() == QMetaMethod::Signal) + flags |= Data::IsSignal; + propType = QVariant::Invalid; + + const char *returnType = m.typeName(); + if (returnType) + propType = QMetaType::type(returnType); + + QList<QByteArray> params = m.parameterTypes(); + if (!params.isEmpty()) + flags |= Data::HasArguments; + revision = m.revision(); +} + + +/*! +Creates a new empty QDeclarativePropertyCache. +*/ +QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e) +: QDeclarativeCleanup(e), engine(e) +{ + Q_ASSERT(engine); +} + +/*! +Creates a new QDeclarativePropertyCache of \a metaObject. +*/ +QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e, const QMetaObject *metaObject) +: QDeclarativeCleanup(e), engine(e) +{ + Q_ASSERT(engine); + Q_ASSERT(metaObject); + + update(engine, metaObject); +} + +QDeclarativePropertyCache::~QDeclarativePropertyCache() +{ + clear(); +} + +void QDeclarativePropertyCache::clear() +{ + for (int ii = 0; ii < indexCache.count(); ++ii) { + if (indexCache.at(ii)) indexCache.at(ii)->release(); + } + + for (int ii = 0; ii < methodIndexCache.count(); ++ii) { + RData *data = methodIndexCache.at(ii); + if (data) data->release(); + } + + for (StringCache::ConstIterator iter = stringCache.begin(); + iter != stringCache.end(); ++iter) { + RData *data = (*iter); + data->release(); + } + + for (IdentifierCache::ConstIterator iter = identifierCache.begin(); + iter != identifierCache.end(); ++iter) { + RData *data = (*iter); + data->release(); + } + + indexCache.clear(); + methodIndexCache.clear(); + stringCache.clear(); + identifierCache.clear(); +} + +QDeclarativePropertyCache::Data QDeclarativePropertyCache::create(const QMetaObject *metaObject, + const QString &property) +{ + Q_ASSERT(metaObject); + + QDeclarativePropertyCache::Data rv; + { + const QMetaObject *cmo = metaObject; + while (cmo) { + int idx = metaObject->indexOfProperty(property.toUtf8()); + if (idx != -1) { + QMetaProperty p = metaObject->property(idx); + if (p.isScriptable()) { + rv.load(metaObject->property(idx)); + return rv; + } else { + while (cmo && cmo->propertyOffset() >= idx) + cmo = cmo->superClass(); + } + } else { + cmo = 0; + } + } + } + + int methodCount = metaObject->methodCount(); + for (int ii = methodCount - 1; ii >= 3; --ii) { // >=3 to block the destroyed signal and deleteLater() slot + QMetaMethod m = metaObject->method(ii); + if (m.access() == QMetaMethod::Private) + continue; + QString methodName = QString::fromUtf8(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + QStringRef methodNameRef = methodName.leftRef(parenIdx); + + if (methodNameRef == property) { + rv.load(m); + return rv; + } + } + + return rv; +} + +QDeclarativePropertyCache *QDeclarativePropertyCache::copy() const +{ + QDeclarativePropertyCache *cache = new QDeclarativePropertyCache(engine); + cache->indexCache = indexCache; + cache->methodIndexCache = methodIndexCache; + cache->stringCache = stringCache; + cache->identifierCache = identifierCache; + cache->allowedRevisionCache = allowedRevisionCache; + + for (int ii = 0; ii < indexCache.count(); ++ii) { + if (indexCache.at(ii)) indexCache.at(ii)->addref(); + } + for (int ii = 0; ii < methodIndexCache.count(); ++ii) { + if (methodIndexCache.at(ii)) methodIndexCache.at(ii)->addref(); + } + for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) + (*iter)->addref(); + for (IdentifierCache::ConstIterator iter = identifierCache.begin(); iter != identifierCache.end(); ++iter) + (*iter)->addref(); + + return cache; +} + +void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject, + Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags) +{ + append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags); +} + +void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject, + int revision, + Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags) +{ + Q_UNUSED(revision); + + allowedRevisionCache.append(0); + + QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); + int methodCount = metaObject->methodCount(); + // 3 to block the destroyed signal and the deleteLater() slot + int methodOffset = qMax(3, metaObject->methodOffset()); + + methodIndexCache.resize(methodCount); + for (int ii = methodOffset; ii < methodCount; ++ii) { + QMetaMethod m = metaObject->method(ii); + if (m.access() == QMetaMethod::Private) + continue; + QString methodName = QString::fromUtf8(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + methodName = methodName.left(parenIdx); + + RData *data = new RData; + data->identifier = enginePriv->objectClass->createPersistentIdentifier(methodName); + methodIndexCache[ii] = data; + + data->load(m); + if (m.methodType() == QMetaMethod::Slot || m.methodType() == QMetaMethod::Method) + data->flags |= methodFlags; + else if (m.methodType() == QMetaMethod::Signal) + data->flags |= signalFlags; + + data->metaObjectOffset = allowedRevisionCache.count() - 1; + + if (stringCache.contains(methodName)) { + RData *old = stringCache[methodName]; + // We only overload methods in the same class, exactly like C++ + if (old->flags & Data::IsFunction && old->coreIndex >= methodOffset) + data->relatedIndex = old->coreIndex; + data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction); + data->overrideIndex = old->coreIndex; + stringCache[methodName]->release(); + identifierCache[data->identifier.identifier]->release(); + } + + stringCache.insert(methodName, data); + identifierCache.insert(data->identifier.identifier, data); + data->addref(); + data->addref(); + } + + int propCount = metaObject->propertyCount(); + int propOffset = metaObject->propertyOffset(); + + indexCache.resize(propCount); + for (int ii = propOffset; ii < propCount; ++ii) { + QMetaProperty p = metaObject->property(ii); + if (!p.isScriptable()) + continue; + + QString propName = QString::fromUtf8(p.name()); + + RData *data = new RData; + data->identifier = enginePriv->objectClass->createPersistentIdentifier(propName); + indexCache[ii] = data; + + data->load(p, engine); + data->flags |= propertyFlags; + + data->metaObjectOffset = allowedRevisionCache.count() - 1; + + if (stringCache.contains(propName)) { + RData *old = stringCache[propName]; + data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction); + data->overrideIndex = old->coreIndex; + stringCache[propName]->release(); + identifierCache[data->identifier.identifier]->release(); + } + + stringCache.insert(propName, data); + identifierCache.insert(data->identifier.identifier, data); + data->addref(); + data->addref(); + } +} + +void QDeclarativePropertyCache::updateRecur(QDeclarativeEngine *engine, const QMetaObject *metaObject) +{ + if (!metaObject) + return; + + updateRecur(engine, metaObject->superClass()); + + append(engine, metaObject); +} + +void QDeclarativePropertyCache::update(QDeclarativeEngine *engine, const QMetaObject *metaObject) +{ + Q_ASSERT(engine); + Q_ASSERT(metaObject); + + clear(); + + // Optimization to prevent unnecessary reallocation of lists + indexCache.reserve(metaObject->propertyCount()); + methodIndexCache.reserve(metaObject->methodCount()); + + updateRecur(engine,metaObject); +} + +QDeclarativePropertyCache::Data * +QDeclarativePropertyCache::property(int index) const +{ + if (index < 0 || index >= indexCache.count()) + return 0; + + return indexCache.at(index); +} + +QDeclarativePropertyCache::Data * +QDeclarativePropertyCache::method(int index) const +{ + if (index < 0 || index >= methodIndexCache.count()) + return 0; + + return methodIndexCache.at(index); +} + +QDeclarativePropertyCache::Data * +QDeclarativePropertyCache::property(const QString &str) const +{ + return stringCache.value(str); +} + +QString QDeclarativePropertyCache::Data::name(QObject *object) +{ + if (!object) + return QString(); + + return name(object->metaObject()); +} + +QString QDeclarativePropertyCache::Data::name(const QMetaObject *metaObject) +{ + if (!metaObject || coreIndex == -1) + return QString(); + + if (flags & IsFunction) { + QMetaMethod m = metaObject->method(coreIndex); + + QString name = QString::fromUtf8(m.signature()); + int parenIdx = name.indexOf(QLatin1Char('(')); + if (parenIdx != -1) + name = name.left(parenIdx); + return name; + } else { + QMetaProperty p = metaObject->property(coreIndex); + return QString::fromUtf8(p.name()); + } +} + +QStringList QDeclarativePropertyCache::propertyNames() const +{ + return stringCache.keys(); +} + +QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, + const QScriptDeclarativeClass::Identifier &name, Data &local) +{ + QDeclarativePropertyCache::Data *rv = 0; + + QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine); + + QDeclarativePropertyCache *cache = 0; + QDeclarativeData *ddata = QDeclarativeData::get(obj); + if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine) + cache = ddata->propertyCache; + if (!cache) { + cache = enginePrivate->cache(obj); + if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; } + } + + if (cache) { + rv = cache->property(name); + } else { + local = QDeclarativePropertyCache::create(obj->metaObject(), enginePrivate->objectClass->toString(name)); + if (local.isValid()) + rv = &local; + } + + return rv; +} + +QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, + const QString &name, Data &local) +{ + QDeclarativePropertyCache::Data *rv = 0; + + if (!engine) { + local = QDeclarativePropertyCache::create(obj->metaObject(), name); + if (local.isValid()) + rv = &local; + } else { + QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine); + + QDeclarativePropertyCache *cache = 0; + QDeclarativeData *ddata = QDeclarativeData::get(obj); + if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine) + cache = ddata->propertyCache; + if (!cache) { + cache = enginePrivate->cache(obj); + if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; } + } + + if (cache) { + rv = cache->property(name); + } else { + local = QDeclarativePropertyCache::create(obj->metaObject(), name); + if (local.isValid()) + rv = &local; + } + } + + return rv; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h new file mode 100644 index 00000000..7ac69254 --- /dev/null +++ b/src/declarative/qml/qdeclarativepropertycache_p.h @@ -0,0 +1,240 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPROPERTYCACHE_P_H +#define QDECLARATIVEPROPERTYCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativerefcount_p.h" +#include "private/qdeclarativecleanup_p.h" +#include "private/qdeclarativenotifier_p.h" + +#include <QtCore/qvector.h> + +#include <QtScript/private/qscriptdeclarativeclass_p.h> +QT_BEGIN_NAMESPACE + +class QDeclarativeEngine; +class QMetaProperty; + +class Q_AUTOTEST_EXPORT QDeclarativePropertyCache : public QDeclarativeRefCount, public QDeclarativeCleanup +{ +public: + QDeclarativePropertyCache(QDeclarativeEngine *); + QDeclarativePropertyCache(QDeclarativeEngine *, const QMetaObject *); + virtual ~QDeclarativePropertyCache(); + + struct Data { + inline Data(); + inline bool operator==(const Data &); + + enum Flag { + NoFlags = 0x00000000, + + // Can apply to all properties, except IsFunction + IsConstant = 0x00000001, + IsWritable = 0x00000002, + IsResettable = 0x00000004, + IsAlias = 0x00000008, + + // These are mutualy exclusive + IsFunction = 0x00000010, + IsQObjectDerived = 0x00000020, + IsEnumType = 0x00000040, + IsQList = 0x00000080, + IsQmlBinding = 0x00000100, + IsQScriptValue = 0x00000200, + + // Apply only to IsFunctions + IsVMEFunction = 0x00000400, + HasArguments = 0x00000800, + IsSignal = 0x00001000, + IsVMESignal = 0x00002000 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + bool isValid() const { return coreIndex != -1; } + + Flags flags; + int propType; + int coreIndex; + union { + int notifyIndex; // When !IsFunction + int relatedIndex; // When IsFunction + }; + uint overrideIndexIsProperty : 1; + signed int overrideIndex : 31; + int revision; + int metaObjectOffset; + + static Flags flagsForProperty(const QMetaProperty &, QDeclarativeEngine *engine = 0); + void load(const QMetaProperty &, QDeclarativeEngine *engine = 0); + void load(const QMetaMethod &); + QString name(QObject *); + QString name(const QMetaObject *); + }; + + struct ValueTypeData { + inline ValueTypeData(); + inline bool operator==(const ValueTypeData &); + Data::Flags flags; // flags of the access property on the value type proxy object + int valueTypeCoreIdx; // The prop index of the access property on the value type proxy object + int valueTypePropType; // The QVariant::Type of access property on the value type proxy object + }; + + void update(QDeclarativeEngine *, const QMetaObject *); + + QDeclarativePropertyCache *copy() const; + void append(QDeclarativeEngine *, const QMetaObject *, Data::Flag propertyFlags = Data::NoFlags, + Data::Flag methodFlags = Data::NoFlags, Data::Flag signalFlags = Data::NoFlags); + void append(QDeclarativeEngine *, const QMetaObject *, int revision, Data::Flag propertyFlags = Data::NoFlags, + Data::Flag methodFlags = Data::NoFlags, Data::Flag signalFlags = Data::NoFlags); + + static Data create(const QMetaObject *, const QString &); + + inline Data *property(const QScriptDeclarativeClass::Identifier &id) const; + Data *property(const QString &) const; + Data *property(int) const; + Data *method(int) const; + QStringList propertyNames() const; + + inline Data *overrideData(Data *) const; + inline bool isAllowedInRevision(Data *) const; + + inline QDeclarativeEngine *qmlEngine() const; + static Data *property(QDeclarativeEngine *, QObject *, const QScriptDeclarativeClass::Identifier &, Data &); + static Data *property(QDeclarativeEngine *, QObject *, const QString &, Data &); + +protected: + virtual void clear(); + +private: + friend class QDeclarativeEnginePrivate; + + struct RData : public Data, public QDeclarativeRefCount { + QScriptDeclarativeClass::PersistentIdentifier identifier; + }; + + typedef QVector<RData *> IndexCache; + typedef QHash<QString, RData *> StringCache; + typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache; + typedef QVector<int> AllowedRevisionCache; + + void updateRecur(QDeclarativeEngine *, const QMetaObject *); + + QDeclarativeEngine *engine; + IndexCache indexCache; + IndexCache methodIndexCache; + StringCache stringCache; + IdentifierCache identifierCache; + AllowedRevisionCache allowedRevisionCache; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePropertyCache::Data::Flags); + +QDeclarativePropertyCache::Data::Data() +: flags(0), propType(0), coreIndex(-1), notifyIndex(-1), overrideIndexIsProperty(false), overrideIndex(-1), + revision(0), metaObjectOffset(-1) +{ +} + +bool QDeclarativePropertyCache::Data::operator==(const QDeclarativePropertyCache::Data &other) +{ + return flags == other.flags && + propType == other.propType && + coreIndex == other.coreIndex && + notifyIndex == other.notifyIndex && + revision == other.revision; +} + +QDeclarativePropertyCache::Data * +QDeclarativePropertyCache::overrideData(Data *data) const +{ + if (data->overrideIndex < 0) + return 0; + + if (data->overrideIndexIsProperty) + return indexCache.at(data->overrideIndex); + else + return methodIndexCache.at(data->overrideIndex); +} + +QDeclarativePropertyCache::Data * +QDeclarativePropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const +{ + return identifierCache.value(id); +} + +QDeclarativePropertyCache::ValueTypeData::ValueTypeData() +: flags(QDeclarativePropertyCache::Data::NoFlags), valueTypeCoreIdx(-1), valueTypePropType(0) +{ +} + +bool QDeclarativePropertyCache::ValueTypeData::operator==(const ValueTypeData &o) +{ + return flags == o.flags && + valueTypeCoreIdx == o.valueTypeCoreIdx && + valueTypePropType == o.valueTypePropType; +} + +bool QDeclarativePropertyCache::isAllowedInRevision(Data *data) const +{ + return (data->metaObjectOffset == -1 && data->revision == 0) || + (allowedRevisionCache[data->metaObjectOffset] >= data->revision); +} + +QDeclarativeEngine *QDeclarativePropertyCache::qmlEngine() const +{ + return engine; +} + +QT_END_NAMESPACE + +#endif // QDECLARATIVEPROPERTYCACHE_P_H diff --git a/src/declarative/qml/qdeclarativepropertyvalueinterceptor.cpp b/src/declarative/qml/qdeclarativepropertyvalueinterceptor.cpp new file mode 100644 index 00000000..d0c920ee --- /dev/null +++ b/src/declarative/qml/qdeclarativepropertyvalueinterceptor.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativepropertyvalueinterceptor.h" + +#include "qdeclarative.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDeclarativePropertyValueInterceptor + \brief The QDeclarativePropertyValueInterceptor class is inherited by property interceptors such as Behavior. + \internal + + This class intercepts property writes, allowing for custom handling. For example, Behavior uses this + interception to provide a default animation for all changes to a property's value. + */ + +/*! + Constructs a QDeclarativePropertyValueInterceptor. +*/ +QDeclarativePropertyValueInterceptor::QDeclarativePropertyValueInterceptor() +{ +} + +QDeclarativePropertyValueInterceptor::~QDeclarativePropertyValueInterceptor() +{ +} + +/*! + \fn void QDeclarativePropertyValueInterceptor::setTarget(const QDeclarativeProperty &property) + Set the target \a property for the value interceptor. This method will + be called by the QML engine when assigning a value interceptor. +*/ + +/*! + \fn void QDeclarativePropertyValueInterceptor::write(const QVariant &value) + This method will be called when a new \a value is assigned to the property being intercepted. +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativepropertyvalueinterceptor.h b/src/declarative/qml/qdeclarativepropertyvalueinterceptor.h new file mode 100644 index 00000000..49d214b2 --- /dev/null +++ b/src/declarative/qml/qdeclarativepropertyvalueinterceptor.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPROPERTYVALUEINTERCEPTOR_H +#define QDECLARATIVEPROPERTYVALUEINTERCEPTOR_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeProperty; +class Q_DECLARATIVE_EXPORT QDeclarativePropertyValueInterceptor +{ +public: + QDeclarativePropertyValueInterceptor(); + virtual ~QDeclarativePropertyValueInterceptor(); + virtual void setTarget(const QDeclarativeProperty &property) = 0; + virtual void write(const QVariant &value) = 0; +}; +Q_DECLARE_INTERFACE(QDeclarativePropertyValueInterceptor, "com.trolltech.qml.QDeclarativePropertyValueInterceptor") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEPROPERTYVALUEINTERCEPTOR_H diff --git a/src/declarative/qml/qdeclarativepropertyvaluesource.cpp b/src/declarative/qml/qdeclarativepropertyvaluesource.cpp new file mode 100644 index 00000000..ee6269d0 --- /dev/null +++ b/src/declarative/qml/qdeclarativepropertyvaluesource.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativepropertyvaluesource.h" + +#include "qdeclarative.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDeclarativePropertyValueSource + \brief The QDeclarativePropertyValueSource class is an interface for property value sources such as animations and bindings. + + See \l{Property Value Sources} for information on writing custom property + value sources. + */ + +/*! + Constructs a QDeclarativePropertyValueSource. +*/ +QDeclarativePropertyValueSource::QDeclarativePropertyValueSource() +{ +} + +/*! + Destroys the value source. +*/ +QDeclarativePropertyValueSource::~QDeclarativePropertyValueSource() +{ +} + +/*! + \fn void QDeclarativePropertyValueSource::setTarget(const QDeclarativeProperty &property) + Set the target \a property for the value source. This method will + be called by the QML engine when assigning a value source. +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativepropertyvaluesource.h b/src/declarative/qml/qdeclarativepropertyvaluesource.h new file mode 100644 index 00000000..deb01912 --- /dev/null +++ b/src/declarative/qml/qdeclarativepropertyvaluesource.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPROPERTYVALUESOURCE_H +#define QDECLARATIVEPROPERTYVALUESOURCE_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeProperty; +class Q_DECLARATIVE_EXPORT QDeclarativePropertyValueSource +{ +public: + QDeclarativePropertyValueSource(); + virtual ~QDeclarativePropertyValueSource(); + virtual void setTarget(const QDeclarativeProperty &) = 0; +}; +Q_DECLARE_INTERFACE(QDeclarativePropertyValueSource, "com.trolltech.qml.QDeclarativePropertyValueSource") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEPROPERTYVALUESOURCE_H diff --git a/src/declarative/qml/qdeclarativeproxymetaobject.cpp b/src/declarative/qml/qdeclarativeproxymetaobject.cpp new file mode 100644 index 00000000..ca2f3aeb --- /dev/null +++ b/src/declarative/qml/qdeclarativeproxymetaobject.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativeproxymetaobject_p.h" +#include "private/qdeclarativeproperty_p.h" + +QT_BEGIN_NAMESPACE + +QDeclarativeProxyMetaObject::QDeclarativeProxyMetaObject(QObject *obj, QList<ProxyData> *mList) +: metaObjects(mList), proxies(0), parent(0), object(obj) +{ + *static_cast<QMetaObject *>(this) = *metaObjects->first().metaObject; + + QObjectPrivate *op = QObjectPrivate::get(obj); + if (op->metaObject) + parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject); + + op->metaObject = this; +} + +QDeclarativeProxyMetaObject::~QDeclarativeProxyMetaObject() +{ + if (parent) + delete parent; + parent = 0; + + if (proxies) + delete [] proxies; + proxies = 0; +} + +int QDeclarativeProxyMetaObject::metaCall(QMetaObject::Call c, int id, void **a) +{ + if ((c == QMetaObject::ReadProperty || + c == QMetaObject::WriteProperty) && + id >= metaObjects->last().propertyOffset) { + + for (int ii = 0; ii < metaObjects->count(); ++ii) { + const ProxyData &data = metaObjects->at(ii); + if (id >= data.propertyOffset) { + if (!proxies) { + proxies = new QObject*[metaObjects->count()]; + ::memset(proxies, 0, + sizeof(QObject *) * metaObjects->count()); + } + + if (!proxies[ii]) { + QObject *proxy = data.createFunc(object); + const QMetaObject *metaObject = proxy->metaObject(); + proxies[ii] = proxy; + + int localOffset = data.metaObject->methodOffset(); + int methodOffset = metaObject->methodOffset(); + int methods = metaObject->methodCount() - methodOffset; + + // ### - Can this be done more optimally? + for (int jj = 0; jj < methods; ++jj) { + QMetaMethod method = + metaObject->method(jj + methodOffset); + if (method.methodType() == QMetaMethod::Signal) + QDeclarativePropertyPrivate::connect(proxy, methodOffset + jj, object, localOffset + jj); + } + } + + int proxyOffset = proxies[ii]->metaObject()->propertyOffset(); + int proxyId = id - data.propertyOffset + proxyOffset; + + return proxies[ii]->qt_metacall(c, proxyId, a); + } + } + } else if (c == QMetaObject::InvokeMetaMethod && + id >= metaObjects->last().methodOffset) { + QMetaMethod m = object->metaObject()->method(id); + if (m.methodType() == QMetaMethod::Signal) { + QMetaObject::activate(object, id, a); + return -1; + } + } + + if (parent) + return parent->metaCall(c, id, a); + else + return object->qt_metacall(c, id, a); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeproxymetaobject_p.h b/src/declarative/qml/qdeclarativeproxymetaobject_p.h new file mode 100644 index 00000000..19a9365e --- /dev/null +++ b/src/declarative/qml/qdeclarativeproxymetaobject_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPROXYMETAOBJECT_P_H +#define QDECLARATIVEPROXYMETAOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qmetaobjectbuilder_p.h" +#include "qdeclarative.h" + +#include <QtCore/QMetaObject> +#include <QtCore/QObject> + +#include <private/qobject_p.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeProxyMetaObject : public QAbstractDynamicMetaObject +{ +public: + struct ProxyData { + typedef QObject *(*CreateFunc)(QObject *); + QMetaObject *metaObject; + CreateFunc createFunc; + int propertyOffset; + int methodOffset; + }; + + QDeclarativeProxyMetaObject(QObject *, QList<ProxyData> *); + virtual ~QDeclarativeProxyMetaObject(); + +protected: + virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); + +private: + QList<ProxyData> *metaObjects; + QObject **proxies; + + QAbstractDynamicMetaObject *parent; + QObject *object; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEPROXYMETAOBJECT_P_H + diff --git a/src/declarative/qml/qdeclarativerefcount.cpp b/src/declarative/qml/qdeclarativerefcount.cpp new file mode 100644 index 00000000..8fbc0bab --- /dev/null +++ b/src/declarative/qml/qdeclarativerefcount.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativerefcount_p.h" + +QT_BEGIN_NAMESPACE + +QDeclarativeRefCount::QDeclarativeRefCount() +: refCount(1) +{ +} + +QDeclarativeRefCount::~QDeclarativeRefCount() +{ +} + +void QDeclarativeRefCount::addref() +{ + Q_ASSERT(refCount > 0); + ++refCount; +} + +void QDeclarativeRefCount::release() +{ + Q_ASSERT(refCount > 0); + --refCount; + if (refCount == 0) + delete this; +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativerefcount_p.h b/src/declarative/qml/qdeclarativerefcount_p.h new file mode 100644 index 00000000..ca09c337 --- /dev/null +++ b/src/declarative/qml/qdeclarativerefcount_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEREFCOUNT_P_H +#define QDECLARATIVEREFCOUNT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_DECLARATIVE_EXPORT QDeclarativeRefCount +{ +public: + QDeclarativeRefCount(); + virtual ~QDeclarativeRefCount(); + void addref(); + void release(); + +private: + int refCount; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEREFCOUNT_P_H diff --git a/src/declarative/qml/qdeclarativerewrite.cpp b/src/declarative/qml/qdeclarativerewrite.cpp new file mode 100644 index 00000000..ef104115 --- /dev/null +++ b/src/declarative/qml/qdeclarativerewrite.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativerewrite_p.h" + +#include "private/qdeclarativeglobal_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP); + +namespace QDeclarativeRewrite { + +bool SharedBindingTester::isSharable(const QString &code) +{ + Engine engine; + NodePool pool(QString(), &engine); + Lexer lexer(&engine); + Parser parser(&engine); + lexer.setCode(code, 0); + parser.parseStatement(); + if (!parser.statement()) + return false; + + return isSharable(parser.statement()); +} + +bool SharedBindingTester::isSharable(AST::Node *node) +{ + _sharable = true; + AST::Node::acceptChild(node, this); + return _sharable; +} + +QString RewriteBinding::operator()(const QString &code, bool *ok, bool *sharable) +{ + Engine engine; + NodePool pool(QString(), &engine); + Lexer lexer(&engine); + Parser parser(&engine); + lexer.setCode(code, 0); + parser.parseStatement(); + if (!parser.statement()) { + if (ok) *ok = false; + return QString(); + } else { + if (ok) *ok = true; + if (sharable) { + SharedBindingTester tester; + *sharable = tester.isSharable(parser.statement()); + } + } + return rewrite(code, 0, parser.statement()); +} + +QString RewriteBinding::operator()(QDeclarativeJS::AST::Node *node, const QString &code, bool *sharable) +{ + if (!node) + return code; + + if (sharable) { + SharedBindingTester tester; + *sharable = tester.isSharable(node); + } + + QDeclarativeJS::AST::ExpressionNode *expression = node->expressionCast(); + QDeclarativeJS::AST::Statement *statement = node->statementCast(); + if(!expression && !statement) + return code; + + TextWriter w; + _writer = &w; + _position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin(); + _inLoop = 0; + + accept(node); + + unsigned startOfStatement = 0; + unsigned endOfStatement = (expression ? expression->lastSourceLocation().end() : statement->lastSourceLocation().end()) - _position; + + QString startString = QLatin1String("(function ") + QString::fromUtf8(_name) + QLatin1String("() { "); + if (expression) + startString += QLatin1String("return "); + _writer->replace(startOfStatement, 0, startString); + _writer->replace(endOfStatement, 0, QLatin1String(" })")); + + if (rewriteDump()) { + qWarning() << "============================================================="; + qWarning() << "Rewrote:"; + qWarning() << qPrintable(code); + } + + QString codeCopy = code; + w.write(&codeCopy); + + if (rewriteDump()) { + qWarning() << "To:"; + qWarning() << qPrintable(code); + qWarning() << "============================================================="; + } + + return codeCopy; +} + +void RewriteBinding::accept(AST::Node *node) +{ + AST::Node::acceptChild(node, this); +} + +QString RewriteBinding::rewrite(QString code, unsigned position, + AST::Statement *node) +{ + TextWriter w; + _writer = &w; + _position = position; + _inLoop = 0; + + accept(node); + + unsigned startOfStatement = node->firstSourceLocation().begin() - _position; + unsigned endOfStatement = node->lastSourceLocation().end() - _position; + + _writer->replace(startOfStatement, 0, QLatin1String("(function ") + QString::fromUtf8(_name) + QLatin1String("() { ")); + _writer->replace(endOfStatement, 0, QLatin1String(" })")); + + if (rewriteDump()) { + qWarning() << "============================================================="; + qWarning() << "Rewrote:"; + qWarning() << qPrintable(code); + } + + w.write(&code); + + if (rewriteDump()) { + qWarning() << "To:"; + qWarning() << qPrintable(code); + qWarning() << "============================================================="; + } + + return code; +} + +bool RewriteBinding::visit(AST::Block *ast) +{ + for (AST::StatementList *it = ast->statements; it; it = it->next) { + if (! it->next) { + // we need to rewrite only the last statement of a block. + accept(it->statement); + } + } + + return false; +} + +bool RewriteBinding::visit(AST::ExpressionStatement *ast) +{ + if (! _inLoop) { + unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position; + _writer->replace(startOfExpressionStatement, 0, QLatin1String("return ")); + } + + return false; +} + +bool RewriteBinding::visit(AST::DoWhileStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::DoWhileStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::WhileStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::WhileStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::ForStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::ForStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::LocalForStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::LocalForStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::ForEachStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::ForEachStatement *) +{ + --_inLoop; +} + +bool RewriteBinding::visit(AST::LocalForEachStatement *) +{ + ++_inLoop; + return true; +} + +void RewriteBinding::endVisit(AST::LocalForEachStatement *) +{ + --_inLoop; +} + +} // namespace QDeclarativeRewrite + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativerewrite_p.h b/src/declarative/qml/qdeclarativerewrite_p.h new file mode 100644 index 00000000..76efb584 --- /dev/null +++ b/src/declarative/qml/qdeclarativerewrite_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEREWRITE_P_H +#define QDECLARATIVEREWRITE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "rewriter/textwriter_p.h" +#include "parser/qdeclarativejslexer_p.h" +#include "parser/qdeclarativejsparser_p.h" +#include "parser/qdeclarativejsnodepool_p.h" + +QT_BEGIN_NAMESPACE + +namespace QDeclarativeRewrite { +using namespace QDeclarativeJS; + +class SharedBindingTester : protected AST::Visitor +{ + bool _sharable; +public: + bool isSharable(const QString &code); + bool isSharable(AST::Node *Node); + + virtual bool visit(AST::FunctionDeclaration *) { _sharable = false; return false; } + virtual bool visit(AST::FunctionExpression *) { _sharable = false; return false; } + virtual bool visit(AST::CallExpression *) { _sharable = false; return false; } +}; + +class RewriteBinding: protected AST::Visitor +{ + unsigned _position; + TextWriter *_writer; + QByteArray _name; + +public: + QString operator()(const QString &code, bool *ok = 0, bool *sharable = 0); + QString operator()(QDeclarativeJS::AST::Node *node, const QString &code, bool *sharable = 0); + + //name of the function: used for the debugger + void setName(const QByteArray &name) { _name = name; } + +protected: + using AST::Visitor::visit; + + void accept(AST::Node *node); + QString rewrite(QString code, unsigned position, AST::Statement *node); + + virtual bool visit(AST::Block *ast); + virtual bool visit(AST::ExpressionStatement *ast); + + virtual bool visit(AST::DoWhileStatement *ast); + virtual void endVisit(AST::DoWhileStatement *ast); + + virtual bool visit(AST::WhileStatement *ast); + virtual void endVisit(AST::WhileStatement *ast); + + virtual bool visit(AST::ForStatement *ast); + virtual void endVisit(AST::ForStatement *ast); + + virtual bool visit(AST::LocalForStatement *ast); + virtual void endVisit(AST::LocalForStatement *ast); + + virtual bool visit(AST::ForEachStatement *ast); + virtual void endVisit(AST::ForEachStatement *ast); + + virtual bool visit(AST::LocalForEachStatement *ast); + virtual void endVisit(AST::LocalForEachStatement *ast); + +private: + int _inLoop; +}; + +} // namespace QDeclarativeRewrite + +QT_END_NAMESPACE + +#endif // QDECLARATIVEREWRITE_P_H + diff --git a/src/declarative/qml/qdeclarativescriptparser.cpp b/src/declarative/qml/qdeclarativescriptparser.cpp new file mode 100644 index 00000000..373842cd --- /dev/null +++ b/src/declarative/qml/qdeclarativescriptparser.cpp @@ -0,0 +1,1206 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativescriptparser_p.h" + +#include "private/qdeclarativeparser_p.h" +#include "parser/qdeclarativejsengine_p.h" +#include "parser/qdeclarativejsparser_p.h" +#include "parser/qdeclarativejslexer_p.h" +#include "parser/qdeclarativejsnodepool_p.h" +#include "parser/qdeclarativejsastvisitor_p.h" +#include "parser/qdeclarativejsast_p.h" +#include "private/qdeclarativerewrite_p.h" + +#include <QStack> +#include <QCoreApplication> +#include <QtDebug> + +QT_BEGIN_NAMESPACE + +using namespace QDeclarativeJS; +using namespace QDeclarativeParser; + +namespace { + +class ProcessAST: protected AST::Visitor +{ + struct State { + State() : object(0), property(0) {} + State(QDeclarativeParser::Object *o) : object(o), property(0) {} + State(QDeclarativeParser::Object *o, Property *p) : object(o), property(p) {} + + QDeclarativeParser::Object *object; + Property *property; + }; + + struct StateStack : public QStack<State> + { + void pushObject(QDeclarativeParser::Object *obj) + { + push(State(obj)); + } + + void pushProperty(const QString &name, const LocationSpan &location) + { + const State &state = top(); + if (state.property) { + State s(state.property->getValue(location), + state.property->getValue(location)->getProperty(name.toUtf8())); + s.property->location = location; + push(s); + } else { + State s(state.object, + state.object->getProperty(name.toUtf8())); + + s.property->location = location; + push(s); + } + } + }; + +public: + ProcessAST(QDeclarativeScriptParser *parser); + virtual ~ProcessAST(); + + void operator()(const QString &code, AST::Node *node); + +protected: + + QDeclarativeParser::Object *defineObjectBinding(AST::UiQualifiedId *propertyName, bool onAssignment, + const QString &objectType, + AST::SourceLocation typeLocation, + LocationSpan location, + AST::UiObjectInitializer *initializer = 0); + + QDeclarativeParser::Variant getVariant(AST::ExpressionNode *expr); + + LocationSpan location(AST::SourceLocation start, AST::SourceLocation end); + LocationSpan location(AST::UiQualifiedId *); + + using AST::Visitor::visit; + using AST::Visitor::endVisit; + + virtual bool visit(AST::UiProgram *node); + virtual bool visit(AST::UiImport *node); + virtual bool visit(AST::UiObjectDefinition *node); + virtual bool visit(AST::UiPublicMember *node); + virtual bool visit(AST::UiObjectBinding *node); + + virtual bool visit(AST::UiScriptBinding *node); + virtual bool visit(AST::UiArrayBinding *node); + virtual bool visit(AST::UiSourceElement *node); + + void accept(AST::Node *node); + + QString asString(AST::UiQualifiedId *node) const; + + const State state() const; + QDeclarativeParser::Object *currentObject() const; + Property *currentProperty() const; + + QString qualifiedNameId() const; + + QString textAt(const AST::SourceLocation &loc) const + { return _contents.mid(loc.offset, loc.length); } + + + QString textAt(const AST::SourceLocation &first, + const AST::SourceLocation &last) const + { return _contents.mid(first.offset, last.offset + last.length - first.offset); } + + QString asString(AST::ExpressionNode *expr) + { + if (! expr) + return QString(); + + return textAt(expr->firstSourceLocation(), expr->lastSourceLocation()); + } + + QString asString(AST::Statement *stmt) + { + if (! stmt) + return QString(); + + QString s = textAt(stmt->firstSourceLocation(), stmt->lastSourceLocation()); + s += QLatin1Char('\n'); + return s; + } + +private: + QDeclarativeScriptParser *_parser; + StateStack _stateStack; + QStringList _scope; + QString _contents; +}; + +ProcessAST::ProcessAST(QDeclarativeScriptParser *parser) + : _parser(parser) +{ +} + +ProcessAST::~ProcessAST() +{ +} + +void ProcessAST::operator()(const QString &code, AST::Node *node) +{ + _contents = code; + accept(node); +} + +void ProcessAST::accept(AST::Node *node) +{ + AST::Node::acceptChild(node, this); +} + +const ProcessAST::State ProcessAST::state() const +{ + if (_stateStack.isEmpty()) + return State(); + + return _stateStack.back(); +} + +QDeclarativeParser::Object *ProcessAST::currentObject() const +{ + return state().object; +} + +Property *ProcessAST::currentProperty() const +{ + return state().property; +} + +QString ProcessAST::qualifiedNameId() const +{ + return _scope.join(QLatin1String("/")); +} + +QString ProcessAST::asString(AST::UiQualifiedId *node) const +{ + QString s; + + for (AST::UiQualifiedId *it = node; it; it = it->next) { + s.append(it->name->asString()); + + if (it->next) + s.append(QLatin1Char('.')); + } + + return s; +} + +QDeclarativeParser::Object * +ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName, + bool onAssignment, + const QString &objectType, + AST::SourceLocation typeLocation, + LocationSpan location, + AST::UiObjectInitializer *initializer) +{ + int lastTypeDot = objectType.lastIndexOf(QLatin1Char('.')); + bool isType = !objectType.isEmpty() && + (objectType.at(0).isUpper() || + (lastTypeDot >= 0 && objectType.at(lastTypeDot+1).isUpper())); + + int propertyCount = 0; + for (AST::UiQualifiedId *name = propertyName; name; name = name->next){ + ++propertyCount; + _stateStack.pushProperty(name->name->asString(), + this->location(name)); + } + + if (!onAssignment && propertyCount && currentProperty() && currentProperty()->values.count()) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Property value set multiple times")); + error.setLine(this->location(propertyName).start.line); + error.setColumn(this->location(propertyName).start.column); + _parser->_errors << error; + return 0; + } + + if (!isType) { + + if(propertyCount || !currentObject()) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Expected type name")); + error.setLine(typeLocation.startLine); + error.setColumn(typeLocation.startColumn); + _parser->_errors << error; + return 0; + } + + LocationSpan loc = ProcessAST::location(typeLocation, typeLocation); + if (propertyName) + loc = ProcessAST::location(propertyName); + + _stateStack.pushProperty(objectType, loc); + accept(initializer); + _stateStack.pop(); + + return 0; + + } else { + // Class + + QString resolvableObjectType = objectType; + if (lastTypeDot >= 0) + resolvableObjectType.replace(QLatin1Char('.'),QLatin1Char('/')); + + QDeclarativeParser::Object *obj = new QDeclarativeParser::Object; + + QDeclarativeScriptParser::TypeReference *typeRef = _parser->findOrCreateType(resolvableObjectType); + obj->type = typeRef->id; + + typeRef->refObjects.append(obj); + + // XXX this doesn't do anything (_scope never builds up) + _scope.append(resolvableObjectType); + obj->typeName = qualifiedNameId().toUtf8(); + _scope.removeLast(); + + obj->location = location; + + if (propertyCount) { + Property *prop = currentProperty(); + QDeclarativeParser::Value *v = new QDeclarativeParser::Value; + v->object = obj; + v->location = obj->location; + if (onAssignment) + prop->addOnValue(v); + else + prop->addValue(v); + + while (propertyCount--) + _stateStack.pop(); + + } else { + + if (! _parser->tree()) { + _parser->setTree(obj); + } else { + const State state = _stateStack.top(); + QDeclarativeParser::Value *v = new QDeclarativeParser::Value; + v->object = obj; + v->location = obj->location; + if (state.property) { + state.property->addValue(v); + } else { + Property *defaultProp = state.object->getDefaultProperty(); + if (defaultProp->location.start.line == -1) { + defaultProp->location = v->location; + defaultProp->location.end = defaultProp->location.start; + defaultProp->location.range.length = 0; + } + defaultProp->addValue(v); + } + } + } + + _stateStack.pushObject(obj); + accept(initializer); + _stateStack.pop(); + + return obj; + } +} + +LocationSpan ProcessAST::location(AST::UiQualifiedId *id) +{ + return location(id->identifierToken, id->identifierToken); +} + +LocationSpan ProcessAST::location(AST::SourceLocation start, AST::SourceLocation end) +{ + LocationSpan rv; + rv.start.line = start.startLine; + rv.start.column = start.startColumn; + rv.end.line = end.startLine; + rv.end.column = end.startColumn + end.length - 1; + rv.range.offset = start.offset; + rv.range.length = end.offset + end.length - start.offset; + return rv; +} + +// UiProgram: UiImportListOpt UiObjectMemberList ; +bool ProcessAST::visit(AST::UiProgram *node) +{ + accept(node->imports); + accept(node->members->member); + return false; +} + +// UiImport: T_IMPORT T_STRING_LITERAL ; +bool ProcessAST::visit(AST::UiImport *node) +{ + QString uri; + QDeclarativeScriptParser::Import import; + + if (node->fileName) { + uri = node->fileName->asString(); + + if (uri.endsWith(QLatin1String(".js"))) { + import.type = QDeclarativeScriptParser::Import::Script; + } else { + import.type = QDeclarativeScriptParser::Import::File; + } + } else { + import.type = QDeclarativeScriptParser::Import::Library; + uri = asString(node->importUri); + } + + AST::SourceLocation startLoc = node->importToken; + AST::SourceLocation endLoc = node->semicolonToken; + + // Qualifier + if (node->importId) { + import.qualifier = node->importId->asString(); + if (!import.qualifier.at(0).isUpper()) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Invalid import qualifier ID")); + error.setLine(node->importIdToken.startLine); + error.setColumn(node->importIdToken.startColumn); + _parser->_errors << error; + return false; + } + if (import.qualifier == QLatin1String("Qt")) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Reserved name \"Qt\" cannot be used as an qualifier")); + error.setLine(node->importIdToken.startLine); + error.setColumn(node->importIdToken.startColumn); + _parser->_errors << error; + return false; + } + + // Check for script qualifier clashes + bool isScript = import.type == QDeclarativeScriptParser::Import::Script; + for (int ii = 0; ii < _parser->_imports.count(); ++ii) { + const QDeclarativeScriptParser::Import &other = _parser->_imports.at(ii); + bool otherIsScript = other.type == QDeclarativeScriptParser::Import::Script; + + if ((isScript || otherIsScript) && import.qualifier == other.qualifier) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Script import qualifiers must be unique.")); + error.setLine(node->importIdToken.startLine); + error.setColumn(node->importIdToken.startColumn); + _parser->_errors << error; + return false; + } + } + + } else if (import.type == QDeclarativeScriptParser::Import::Script) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Script import requires a qualifier")); + error.setLine(node->fileNameToken.startLine); + error.setColumn(node->fileNameToken.startColumn); + _parser->_errors << error; + return false; + } + + if (node->versionToken.isValid()) { + import.version = textAt(node->versionToken); + } else if (import.type == QDeclarativeScriptParser::Import::Library) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Library import requires a version")); + error.setLine(node->importIdToken.startLine); + error.setColumn(node->importIdToken.startColumn); + _parser->_errors << error; + return false; + } + + + import.location = location(startLoc, endLoc); + import.uri = uri; + + _parser->_imports << import; + + return false; +} + +bool ProcessAST::visit(AST::UiPublicMember *node) +{ + const struct TypeNameToType { + const char *name; + Object::DynamicProperty::Type type; + const char *qtName; + } propTypeNameToTypes[] = { + { "int", Object::DynamicProperty::Int, "int" }, + { "bool", Object::DynamicProperty::Bool, "bool" }, + { "double", Object::DynamicProperty::Real, "double" }, + { "real", Object::DynamicProperty::Real, "qreal" }, + { "string", Object::DynamicProperty::String, "QString" }, + { "url", Object::DynamicProperty::Url, "QUrl" }, + { "color", Object::DynamicProperty::Color, "QColor" }, + // Internally QTime, QDate and QDateTime are all supported. + // To be more consistent with JavaScript we expose only + // QDateTime as it matches closely with the Date JS type. + // We also call it "date" to match. + // { "time", Object::DynamicProperty::Time, "QTime" }, + // { "date", Object::DynamicProperty::Date, "QDate" }, + { "date", Object::DynamicProperty::DateTime, "QDateTime" }, + { "variant", Object::DynamicProperty::Variant, "QVariant" } + }; + const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) / + sizeof(propTypeNameToTypes[0]); + + if(node->type == AST::UiPublicMember::Signal) { + const QString name = node->name->asString(); + + Object::DynamicSignal signal; + signal.name = name.toUtf8(); + + AST::UiParameterList *p = node->parameters; + while (p) { + const QString memberType = p->type->asString(); + const char *qtType = 0; + for(int ii = 0; !qtType && ii < propTypeNameToTypesCount; ++ii) { + if(QLatin1String(propTypeNameToTypes[ii].name) == memberType) + qtType = propTypeNameToTypes[ii].qtName; + } + + if (!qtType) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Expected parameter type")); + error.setLine(node->typeToken.startLine); + error.setColumn(node->typeToken.startColumn); + _parser->_errors << error; + return false; + } + + signal.parameterTypes << qtType; + signal.parameterNames << p->name->asString().toUtf8(); + p = p->finish(); + } + + _stateStack.top().object->dynamicSignals << signal; + } else { + const QString memberType = node->memberType->asString(); + const QString name = node->name->asString(); + + bool typeFound = false; + Object::DynamicProperty::Type type; + + if (memberType == QLatin1String("alias")) { + type = Object::DynamicProperty::Alias; + typeFound = true; + } + + for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) { + if(QLatin1String(propTypeNameToTypes[ii].name) == memberType) { + type = propTypeNameToTypes[ii].type; + typeFound = true; + } + } + + if (!typeFound && memberType.at(0).isUpper()) { + QString typemodifier; + if(node->typeModifier) + typemodifier = node->typeModifier->asString(); + if (typemodifier.isEmpty()) { + type = Object::DynamicProperty::Custom; + } else if(typemodifier == QLatin1String("list")) { + type = Object::DynamicProperty::CustomList; + } else { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Invalid property type modifier")); + error.setLine(node->typeModifierToken.startLine); + error.setColumn(node->typeModifierToken.startColumn); + _parser->_errors << error; + return false; + } + typeFound = true; + } else if (node->typeModifier) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Unexpected property type modifier")); + error.setLine(node->typeModifierToken.startLine); + error.setColumn(node->typeModifierToken.startColumn); + _parser->_errors << error; + return false; + } + + if(!typeFound) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Expected property type")); + error.setLine(node->typeToken.startLine); + error.setColumn(node->typeToken.startColumn); + _parser->_errors << error; + return false; + } + + if (node->isReadonlyMember) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Readonly not yet supported")); + error.setLine(node->readonlyToken.startLine); + error.setColumn(node->readonlyToken.startColumn); + _parser->_errors << error; + return false; + + } + Object::DynamicProperty property; + property.isDefaultProperty = node->isDefaultMember; + property.type = type; + if (type >= Object::DynamicProperty::Custom) { + QDeclarativeScriptParser::TypeReference *typeRef = + _parser->findOrCreateType(memberType); + typeRef->refObjects.append(_stateStack.top().object); + } + property.customType = memberType.toUtf8(); + property.name = name.toUtf8(); + property.location = location(node->firstSourceLocation(), + node->lastSourceLocation()); + + if (node->expression) { // default value + property.defaultValue = new Property; + property.defaultValue->parent = _stateStack.top().object; + property.defaultValue->location = + location(node->expression->firstSourceLocation(), + node->expression->lastSourceLocation()); + QDeclarativeParser::Value *value = new QDeclarativeParser::Value; + value->location = location(node->expression->firstSourceLocation(), + node->expression->lastSourceLocation()); + value->value = getVariant(node->expression); + property.defaultValue->values << value; + } + + _stateStack.top().object->dynamicProperties << property; + + // process QML-like initializers (e.g. property Object o: Object {}) + accept(node->binding); + } + + return false; +} + + +// UiObjectMember: UiQualifiedId UiObjectInitializer ; +bool ProcessAST::visit(AST::UiObjectDefinition *node) +{ + LocationSpan l = location(node->firstSourceLocation(), + node->lastSourceLocation()); + + const QString objectType = asString(node->qualifiedTypeNameId); + const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken; + + defineObjectBinding(/*propertyName = */ 0, false, objectType, + typeLocation, l, node->initializer); + + return false; +} + + +// UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ; +bool ProcessAST::visit(AST::UiObjectBinding *node) +{ + LocationSpan l = location(node->qualifiedTypeNameId->identifierToken, + node->initializer->rbraceToken); + + const QString objectType = asString(node->qualifiedTypeNameId); + const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken; + + defineObjectBinding(node->qualifiedId, node->hasOnToken, objectType, + typeLocation, l, node->initializer); + + return false; +} + +QDeclarativeParser::Variant ProcessAST::getVariant(AST::ExpressionNode *expr) +{ + if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(expr)) { + return QDeclarativeParser::Variant(lit->value->asString()); + } else if (expr->kind == AST::Node::Kind_TrueLiteral) { + return QDeclarativeParser::Variant(true); + } else if (expr->kind == AST::Node::Kind_FalseLiteral) { + return QDeclarativeParser::Variant(false); + } else if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(expr)) { + return QDeclarativeParser::Variant(lit->value, asString(expr)); + } else { + + if (AST::UnaryMinusExpression *unaryMinus = AST::cast<AST::UnaryMinusExpression *>(expr)) { + if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(unaryMinus->expression)) { + return QDeclarativeParser::Variant(-lit->value, asString(expr)); + } + } + + return QDeclarativeParser::Variant(asString(expr), expr); + } +} + + +// UiObjectMember: UiQualifiedId T_COLON Statement ; +bool ProcessAST::visit(AST::UiScriptBinding *node) +{ + int propertyCount = 0; + AST::UiQualifiedId *propertyName = node->qualifiedId; + for (AST::UiQualifiedId *name = propertyName; name; name = name->next){ + ++propertyCount; + _stateStack.pushProperty(name->name->asString(), + location(name)); + } + + Property *prop = currentProperty(); + + if (prop->values.count()) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Property value set multiple times")); + error.setLine(this->location(propertyName).start.line); + error.setColumn(this->location(propertyName).start.column); + _parser->_errors << error; + return 0; + } + + QDeclarativeParser::Variant primitive; + + if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(node->statement)) { + primitive = getVariant(stmt->expression); + } else { // do binding + primitive = QDeclarativeParser::Variant(asString(node->statement), + node->statement); + } + + prop->location.range.length = prop->location.range.offset + prop->location.range.length - node->qualifiedId->identifierToken.offset; + prop->location.range.offset = node->qualifiedId->identifierToken.offset; + QDeclarativeParser::Value *v = new QDeclarativeParser::Value; + v->value = primitive; + v->location = location(node->statement->firstSourceLocation(), + node->statement->lastSourceLocation()); + + prop->addValue(v); + + while (propertyCount--) + _stateStack.pop(); + + return true; +} + +static QList<int> collectCommas(AST::UiArrayMemberList *members) +{ + QList<int> commas; + + if (members) { + for (AST::UiArrayMemberList *it = members->next; it; it = it->next) { + commas.append(it->commaToken.offset); + } + } + + return commas; +} + +// UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ; +bool ProcessAST::visit(AST::UiArrayBinding *node) +{ + int propertyCount = 0; + AST::UiQualifiedId *propertyName = node->qualifiedId; + for (AST::UiQualifiedId *name = propertyName; name; name = name->next){ + ++propertyCount; + _stateStack.pushProperty(name->name->asString(), + location(name)); + } + + Property* prop = currentProperty(); + + if (prop->values.count()) { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","Property value set multiple times")); + error.setLine(this->location(propertyName).start.line); + error.setColumn(this->location(propertyName).start.column); + _parser->_errors << error; + return 0; + } + + accept(node->members); + + // For the DOM, store the position of the T_LBRACKET upto the T_RBRACKET as the range: + prop->listValueRange.offset = node->lbracketToken.offset; + prop->listValueRange.length = node->rbracketToken.offset + node->rbracketToken.length - node->lbracketToken.offset; + + // Store the positions of the comma token too, again for the DOM to be able to retrieve it. + prop->listCommaPositions = collectCommas(node->members); + + while (propertyCount--) + _stateStack.pop(); + + return false; +} + +bool ProcessAST::visit(AST::UiSourceElement *node) +{ + QDeclarativeParser::Object *obj = currentObject(); + + if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) { + + Object::DynamicSlot slot; + slot.location = location(funDecl->firstSourceLocation(), funDecl->lastSourceLocation()); + + AST::FormalParameterList *f = funDecl->formals; + while (f) { + slot.parameterNames << f->name->asString().toUtf8(); + f = f->finish(); + } + + AST::SourceLocation loc = funDecl->rparenToken; + loc.offset = loc.end(); + loc.startColumn += 1; + QString body = textAt(loc, funDecl->rbraceToken); + slot.name = funDecl->name->asString().toUtf8(); + slot.body = body; + obj->dynamicSlots << slot; + + } else { + QDeclarativeError error; + error.setDescription(QCoreApplication::translate("QDeclarativeParser","JavaScript declaration outside Script element")); + error.setLine(node->firstSourceLocation().startLine); + error.setColumn(node->firstSourceLocation().startColumn); + _parser->_errors << error; + } + return false; +} + +} // end of anonymous namespace + + +QDeclarativeScriptParser::QDeclarativeScriptParser() +: root(0), data(0) +{ + +} + +QDeclarativeScriptParser::~QDeclarativeScriptParser() +{ + clear(); +} + +class QDeclarativeScriptParserJsASTData +{ +public: + QDeclarativeScriptParserJsASTData(const QString &filename) + : nodePool(filename, &engine) {} + + Engine engine; + NodePool nodePool; +}; + +bool QDeclarativeScriptParser::parse(const QByteArray &qmldata, const QUrl &url) +{ + clear(); + + const QString fileName = url.toString(); + _scriptFile = fileName; + + QTextStream stream(qmldata, QIODevice::ReadOnly); +#ifndef QT_NO_TEXTCODEC + stream.setCodec("UTF-8"); +#endif + const QString code = stream.readAll(); + + data = new QDeclarativeScriptParserJsASTData(fileName); + + Lexer lexer(&data->engine); + lexer.setCode(code, /*line = */ 1); + + Parser parser(&data->engine); + + if (! parser.parse() || !_errors.isEmpty()) { + + // Extract errors from the parser + foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) { + + if (m.isWarning()) + continue; + + QDeclarativeError error; + error.setUrl(url); + error.setDescription(m.message); + error.setLine(m.loc.startLine); + error.setColumn(m.loc.startColumn); + _errors << error; + + } + } + + if (_errors.isEmpty()) { + ProcessAST process(this); + process(code, parser.ast()); + + // Set the url for process errors + for(int ii = 0; ii < _errors.count(); ++ii) + _errors[ii].setUrl(url); + } + + return _errors.isEmpty(); +} + +QList<QDeclarativeScriptParser::TypeReference*> QDeclarativeScriptParser::referencedTypes() const +{ + return _refTypes; +} + +QDeclarativeParser::Object *QDeclarativeScriptParser::tree() const +{ + return root; +} + +QList<QDeclarativeScriptParser::Import> QDeclarativeScriptParser::imports() const +{ + return _imports; +} + +QList<QDeclarativeError> QDeclarativeScriptParser::errors() const +{ + return _errors; +} + +static void replaceWithSpace(QString &str, int idx, int n) +{ + QChar *data = str.data() + idx; + const QChar space(QLatin1Char(' ')); + for (int ii = 0; ii < n; ++ii) + *data++ = space; +} + +/* +Searches for ".pragma <value>" declarations within \a script. Currently supported pragmas +are: + library +*/ +QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptParser::extractPragmas(QString &script) +{ + QDeclarativeParser::Object::ScriptBlock::Pragmas rv = QDeclarativeParser::Object::ScriptBlock::None; + + const QString pragma(QLatin1String("pragma")); + const QString library(QLatin1String("library")); + + QDeclarativeJS::Lexer l(0); + l.setCode(script, 0); + + int token = l.lex(); + + while (true) { + if (token != QDeclarativeJSGrammar::T_DOT) + return rv; + + int startOffset = l.tokenOffset(); + int startLine = l.currentLineNo(); + + token = l.lex(); + + if (token != QDeclarativeJSGrammar::T_IDENTIFIER || + l.currentLineNo() != startLine || + script.mid(l.tokenOffset(), l.tokenLength()) != pragma) + return rv; + + token = l.lex(); + + if (token != QDeclarativeJSGrammar::T_IDENTIFIER || + l.currentLineNo() != startLine) + return rv; + + QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength()); + int endOffset = l.tokenLength() + l.tokenOffset(); + + token = l.lex(); + if (l.currentLineNo() == startLine) + return rv; + + if (pragmaValue == library) { + rv |= QDeclarativeParser::Object::ScriptBlock::Shared; + replaceWithSpace(script, startOffset, endOffset - startOffset); + } else { + return rv; + } + } + return rv; +} + +#define CHECK_LINE if(l.currentLineNo() != startLine) return rv; +#define CHECK_TOKEN(t) if (token != QDeclarativeJSGrammar:: t) return rv; + +static const int uriTokens[] = { + QDeclarativeJSGrammar::T_IDENTIFIER, + QDeclarativeJSGrammar::T_PROPERTY, + QDeclarativeJSGrammar::T_SIGNAL, + QDeclarativeJSGrammar::T_READONLY, + QDeclarativeJSGrammar::T_ON, + QDeclarativeJSGrammar::T_BREAK, + QDeclarativeJSGrammar::T_CASE, + QDeclarativeJSGrammar::T_CATCH, + QDeclarativeJSGrammar::T_CONTINUE, + QDeclarativeJSGrammar::T_DEFAULT, + QDeclarativeJSGrammar::T_DELETE, + QDeclarativeJSGrammar::T_DO, + QDeclarativeJSGrammar::T_ELSE, + QDeclarativeJSGrammar::T_FALSE, + QDeclarativeJSGrammar::T_FINALLY, + QDeclarativeJSGrammar::T_FOR, + QDeclarativeJSGrammar::T_FUNCTION, + QDeclarativeJSGrammar::T_IF, + QDeclarativeJSGrammar::T_IN, + QDeclarativeJSGrammar::T_INSTANCEOF, + QDeclarativeJSGrammar::T_NEW, + QDeclarativeJSGrammar::T_NULL, + QDeclarativeJSGrammar::T_RETURN, + QDeclarativeJSGrammar::T_SWITCH, + QDeclarativeJSGrammar::T_THIS, + QDeclarativeJSGrammar::T_THROW, + QDeclarativeJSGrammar::T_TRUE, + QDeclarativeJSGrammar::T_TRY, + QDeclarativeJSGrammar::T_TYPEOF, + QDeclarativeJSGrammar::T_VAR, + QDeclarativeJSGrammar::T_VOID, + QDeclarativeJSGrammar::T_WHILE, + QDeclarativeJSGrammar::T_CONST, + QDeclarativeJSGrammar::T_DEBUGGER, + QDeclarativeJSGrammar::T_RESERVED_WORD, + QDeclarativeJSGrammar::T_WITH, + + QDeclarativeJSGrammar::EOF_SYMBOL +}; +static inline bool isUriToken(int token) +{ + const int *current = uriTokens; + while (*current != QDeclarativeJSGrammar::EOF_SYMBOL) { + if (*current == token) + return true; + ++current; + } + return false; +} + +QDeclarativeScriptParser::JavaScriptMetaData QDeclarativeScriptParser::extractMetaData(QString &script) +{ + JavaScriptMetaData rv; + + QDeclarativeParser::Object::ScriptBlock::Pragmas &pragmas = rv.pragmas; + + const QString pragma(QLatin1String("pragma")); + const QString js(QLatin1String(".js")); + const QString library(QLatin1String("library")); + + QDeclarativeJS::Lexer l(0); + l.setCode(script, 0); + + int token = l.lex(); + + while (true) { + if (token != QDeclarativeJSGrammar::T_DOT) + return rv; + + int startOffset = l.tokenOffset(); + int startLine = l.currentLineNo(); + + token = l.lex(); + + CHECK_LINE; + + if (token == QDeclarativeJSGrammar::T_IMPORT) { + + // .import <URI> <Version> as <Identifier> + // .import <file.js> as <Identifier> + + token = l.lex(); + + CHECK_LINE; + + if (token == QDeclarativeJSGrammar::T_STRING_LITERAL) { + + QString file(l.characterBuffer(), l.characterCount()); + if (!file.endsWith(js)) + return rv; + + token = l.lex(); + + CHECK_TOKEN(T_AS); + CHECK_LINE; + + token = l.lex(); + + CHECK_TOKEN(T_IDENTIFIER); + CHECK_LINE; + + int endOffset = l.tokenLength() + l.tokenOffset(); + + QString importId = script.mid(l.tokenOffset(), l.tokenLength()); + + if (!importId.at(0).isUpper()) + return rv; + + token = l.lex(); + if (l.currentLineNo() == startLine) + return rv; + + replaceWithSpace(script, startOffset, endOffset - startOffset); + + Import import; + import.type = Import::Script; + import.uri = file; + import.qualifier = importId; + + rv.imports << import; + + } else { + // URI + QString uri; + QString version; + + while (true) { + if (!isUriToken(token)) + return rv; + + uri.append(QString(l.characterBuffer(), l.characterCount())); + + token = l.lex(); + CHECK_LINE; + if (token != QDeclarativeJSGrammar::T_DOT) + break; + + uri.append(QLatin1Char('.')); + + token = l.lex(); + CHECK_LINE; + } + + CHECK_TOKEN(T_NUMERIC_LITERAL); + version = script.mid(l.tokenOffset(), l.tokenLength()); + + token = l.lex(); + + CHECK_TOKEN(T_AS); + CHECK_LINE; + + token = l.lex(); + + CHECK_TOKEN(T_IDENTIFIER); + CHECK_LINE; + + int endOffset = l.tokenLength() + l.tokenOffset(); + + QString importId = script.mid(l.tokenOffset(), l.tokenLength()); + + if (!importId.at(0).isUpper()) + return rv; + + token = l.lex(); + if (l.currentLineNo() == startLine) + return rv; + + replaceWithSpace(script, startOffset, endOffset - startOffset); + + Import import; + import.type = Import::Library; + import.uri = uri; + import.version = version; + import.qualifier = importId; + + rv.imports << import; + } + + } else if (token == QDeclarativeJSGrammar::T_IDENTIFIER && + script.mid(l.tokenOffset(), l.tokenLength()) == pragma) { + + token = l.lex(); + + CHECK_TOKEN(T_IDENTIFIER); + CHECK_LINE; + + QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength()); + int endOffset = l.tokenLength() + l.tokenOffset(); + + if (pragmaValue == QLatin1String("library")) { + pragmas |= QDeclarativeParser::Object::ScriptBlock::Shared; + replaceWithSpace(script, startOffset, endOffset - startOffset); + } else { + return rv; + } + + token = l.lex(); + if (l.currentLineNo() == startLine) + return rv; + + } else { + return rv; + } + } + return rv; +} + +void QDeclarativeScriptParser::clear() +{ + if (root) { + root->release(); + root = 0; + } + _imports.clear(); + qDeleteAll(_refTypes); + _refTypes.clear(); + _errors.clear(); + + if (data) { + delete data; + data = 0; + } +} + +QDeclarativeScriptParser::TypeReference *QDeclarativeScriptParser::findOrCreateType(const QString &name) +{ + TypeReference *type = 0; + int i = 0; + for (; i < _refTypes.size(); ++i) { + if (_refTypes.at(i)->name == name) { + type = _refTypes.at(i); + break; + } + } + if (!type) { + type = new TypeReference(i, name); + _refTypes.append(type); + } + + return type; +} + +void QDeclarativeScriptParser::setTree(QDeclarativeParser::Object *tree) +{ + Q_ASSERT(! root); + + root = tree; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativescriptparser_p.h b/src/declarative/qml/qdeclarativescriptparser_p.h new file mode 100644 index 00000000..39958e10 --- /dev/null +++ b/src/declarative/qml/qdeclarativescriptparser_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QDECLARATIVESCRIPTPARSER_P_H +#define QDECLARATIVESCRIPTPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativeerror.h" +#include "private/qdeclarativeparser_p.h" + +#include <QtCore/QList> +#include <QtCore/QUrl> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QByteArray; + +class QDeclarativeScriptParserJsASTData; +class QDeclarativeScriptParser +{ +public: + class Import + { + public: + Import() : type(Library) {} + + enum Type { Library, File, Script }; + Type type; + + QString uri; + QString qualifier; + QString version; + + QDeclarativeParser::LocationSpan location; + }; + + class TypeReference + { + public: + TypeReference(int typeId, const QString &typeName) : id(typeId), name(typeName) {} + + int id; + // type as it has been referenced in Qml + QString name; + // objects in parse tree referencing the type + QList<QDeclarativeParser::Object*> refObjects; + }; + + QDeclarativeScriptParser(); + ~QDeclarativeScriptParser(); + + bool parse(const QByteArray &data, const QUrl &url = QUrl()); + + QList<TypeReference*> referencedTypes() const; + + QDeclarativeParser::Object *tree() const; + QList<Import> imports() const; + + void clear(); + + QList<QDeclarativeError> errors() const; + + class JavaScriptMetaData { + public: + JavaScriptMetaData() + : pragmas(QDeclarativeParser::Object::ScriptBlock::None) {} + + QDeclarativeParser::Object::ScriptBlock::Pragmas pragmas; + QList<Import> imports; + }; + + static QDeclarativeParser::Object::ScriptBlock::Pragmas extractPragmas(QString &); + static JavaScriptMetaData extractMetaData(QString &); + + +// ### private: + TypeReference *findOrCreateType(const QString &name); + void setTree(QDeclarativeParser::Object *tree); + + void setScriptFile(const QString &filename) {_scriptFile = filename; } + QString scriptFile() const { return _scriptFile; } + +// ### private: + QList<QDeclarativeError> _errors; + + QDeclarativeParser::Object *root; + QList<Import> _imports; + QList<TypeReference*> _refTypes; + QString _scriptFile; + QDeclarativeScriptParserJsASTData *data; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVESCRIPTPARSER_P_H diff --git a/src/declarative/qml/qdeclarativescriptstring.cpp b/src/declarative/qml/qdeclarativescriptstring.cpp new file mode 100644 index 00000000..4f9da3a1 --- /dev/null +++ b/src/declarative/qml/qdeclarativescriptstring.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativescriptstring.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativeScriptStringPrivate : public QSharedData +{ +public: + QDeclarativeScriptStringPrivate() : context(0), scope(0) {} + + QDeclarativeContext *context; + QObject *scope; + QString script; +}; + +/*! +\class QDeclarativeScriptString +\since 4.7 +\brief The QDeclarativeScriptString class encapsulates a script and its context. + +QDeclarativeScriptString is used to create QObject properties that accept a script "assignment" from QML. + +Normally, the following QML would result in a binding being established for the \c script +property; i.e. \c script would be assigned the value obtained from running \c {myObj.value = Math.max(myValue, 100)} + +\qml +MyType { + script: myObj.value = Math.max(myValue, 100) +} +\endqml + +If instead the property had a type of QDeclarativeScriptString, +the script itself -- \e {myObj.value = Math.max(myValue, 100)} -- would be passed to the \c script property +and the class could choose how to handle it. Typically, the class will evaluate +the script at some later time using a QDeclarativeExpression. + +\code +QDeclarativeExpression expr(scriptString.context(), scriptString.script(), scriptStr.scopeObject()); +expr.value(); +\endcode + +\sa QDeclarativeExpression +*/ + +/*! +Constructs an empty instance. +*/ +QDeclarativeScriptString::QDeclarativeScriptString() +: d(new QDeclarativeScriptStringPrivate) +{ +} + +/*! +Copies \a other. +*/ +QDeclarativeScriptString::QDeclarativeScriptString(const QDeclarativeScriptString &other) +: d(other.d) +{ +} + +/*! +\internal +*/ +QDeclarativeScriptString::~QDeclarativeScriptString() +{ +} + +/*! +Assigns \a other to this. +*/ +QDeclarativeScriptString &QDeclarativeScriptString::operator=(const QDeclarativeScriptString &other) +{ + d = other.d; + return *this; +} + +/*! +Returns the context for the script. +*/ +QDeclarativeContext *QDeclarativeScriptString::context() const +{ + return d->context; +} + +/*! +Sets the \a context for the script. +*/ +void QDeclarativeScriptString::setContext(QDeclarativeContext *context) +{ + d->context = context; +} + +/*! +Returns the scope object for the script. +*/ +QObject *QDeclarativeScriptString::scopeObject() const +{ + return d->scope; +} + +/*! +Sets the scope \a object for the script. +*/ +void QDeclarativeScriptString::setScopeObject(QObject *object) +{ + d->scope = object; +} + +/*! +Returns the script text. +*/ +QString QDeclarativeScriptString::script() const +{ + return d->script; +} + +/*! +Sets the \a script text. +*/ +void QDeclarativeScriptString::setScript(const QString &script) +{ + d->script = script; +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativescriptstring.h b/src/declarative/qml/qdeclarativescriptstring.h new file mode 100644 index 00000000..cda847ff --- /dev/null +++ b/src/declarative/qml/qdeclarativescriptstring.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESCRIPTSTRING_H +#define QDECLARATIVESCRIPTSTRING_H + +#include <QtCore/qstring.h> +#include <QtCore/qshareddata.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QObject; +class QDeclarativeContext; +class QDeclarativeScriptStringPrivate; +class Q_DECLARATIVE_EXPORT QDeclarativeScriptString +{ +public: + QDeclarativeScriptString(); + QDeclarativeScriptString(const QDeclarativeScriptString &); + ~QDeclarativeScriptString(); + + QDeclarativeScriptString &operator=(const QDeclarativeScriptString &); + + QDeclarativeContext *context() const; + void setContext(QDeclarativeContext *); + + QObject *scopeObject() const; + void setScopeObject(QObject *); + + QString script() const; + void setScript(const QString &); + +private: + QSharedDataPointer<QDeclarativeScriptStringPrivate> d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDeclarativeScriptString) + +QT_END_HEADER + +#endif // QDECLARATIVESCRIPTSTRING_H + diff --git a/src/declarative/qml/qdeclarativesqldatabase.cpp b/src/declarative/qml/qdeclarativesqldatabase.cpp new file mode 100644 index 00000000..ed44b207 --- /dev/null +++ b/src/declarative/qml/qdeclarativesqldatabase.cpp @@ -0,0 +1,448 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativesqldatabase_p.h" + +#include "qdeclarativeengine.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativerefcount_p.h" +#include "private/qdeclarativeengine_p.h" + +#include <QtCore/qobject.h> +#include <QtScript/qscriptvalue.h> +#include <QtScript/qscriptvalueiterator.h> +#include <QtScript/qscriptcontext.h> +#include <QtScript/qscriptengine.h> +#include <QtScript/qscriptclasspropertyiterator.h> +#include <QtSql/qsqldatabase.h> +#include <QtSql/qsqlquery.h> +#include <QtSql/qsqlerror.h> +#include <QtSql/qsqlrecord.h> +#include <QtCore/qstack.h> +#include <QtCore/qcryptographichash.h> +#include <QtCore/qsettings.h> +#include <QtCore/qdir.h> +#include <QtCore/qdebug.h> + +Q_DECLARE_METATYPE(QSqlDatabase) +Q_DECLARE_METATYPE(QSqlQuery) + +QT_BEGIN_NAMESPACE + +class QDeclarativeSqlQueryScriptClass: public QScriptClass { +public: + QDeclarativeSqlQueryScriptClass(QScriptEngine *engine) : QScriptClass(engine) + { + str_length = engine->toStringHandle(QLatin1String("length")); + str_forwardOnly = engine->toStringHandle(QLatin1String("forwardOnly")); // not in HTML5 (an optimization) + } + + QueryFlags queryProperty(const QScriptValue &, + const QScriptString &name, + QueryFlags flags, uint *) + { + if (flags & HandlesReadAccess) { + if (name == str_length) { + return HandlesReadAccess; + } else if (name == str_forwardOnly) { + return flags; + } + } + if (flags & HandlesWriteAccess) + if (name == str_forwardOnly) + return flags; + return 0; + } + + QScriptValue property(const QScriptValue &object, + const QScriptString &name, uint) + { + QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data()); + if (name == str_length) { + int s = query.size(); + if (s<0) { + // Inefficient. + if (query.last()) { + return query.at()+1; + } else { + return 0; + } + } else { + return s; + } + } else if (name == str_forwardOnly) { + return query.isForwardOnly(); + } + return engine()->undefinedValue(); + } + + void setProperty(QScriptValue &object, + const QScriptString &name, uint, const QScriptValue & value) + { + if (name == str_forwardOnly) { + QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data()); + query.setForwardOnly(value.toBool()); + } + } + + QScriptValue::PropertyFlags propertyFlags(const QScriptValue &/*object*/, const QScriptString &name, uint /*id*/) + { + if (name == str_length) { + return QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration; + } + return QScriptValue::Undeletable; + } + +private: + QScriptString str_length; + QScriptString str_forwardOnly; +}; + +// If the spec changes to allow iteration, check git history... +// class QDeclarativeSqlQueryScriptClassPropertyIterator : public QScriptClassPropertyIterator + + + +enum SqlException { + UNKNOWN_ERR, + DATABASE_ERR, + VERSION_ERR, + TOO_LARGE_ERR, + QUOTA_ERR, + SYNTAX_ERR, + CONSTRAINT_ERR, + TIMEOUT_ERR +}; + +static const char* sqlerror[] = { + "UNKNOWN_ERR", + "DATABASE_ERR", + "VERSION_ERR", + "TOO_LARGE_ERR", + "QUOTA_ERR", + "SYNTAX_ERR", + "CONSTRAINT_ERR", + "TIMEOUT_ERR", + 0 +}; + +#define THROW_SQL(error, desc) \ +{ \ + QScriptValue errorValue = context->throwError(desc); \ + errorValue.setProperty(QLatin1String("code"), error); \ + return errorValue; \ +} + +static QString qmlsqldatabase_databasesPath(QScriptEngine *engine) +{ + QDeclarativeScriptEngine *qmlengine = static_cast<QDeclarativeScriptEngine*>(engine); + return QDir::toNativeSeparators(qmlengine->offlineStoragePath) + + QDir::separator() + QLatin1String("Databases"); +} + +static void qmlsqldatabase_initDatabasesPath(QScriptEngine *engine) +{ + QDir().mkpath(qmlsqldatabase_databasesPath(engine)); +} + +static QString qmlsqldatabase_databaseFile(const QString& connectionName, QScriptEngine *engine) +{ + return qmlsqldatabase_databasesPath(engine) + QDir::separator() + + connectionName; +} + + +static QScriptValue qmlsqldatabase_item(QScriptContext *context, QScriptEngine *engine) +{ + QSqlQuery query = qscriptvalue_cast<QSqlQuery>(context->thisObject().data()); + int i = context->argument(0).toNumber(); + if (query.at() == i || query.seek(i)) { // Qt 4.6 doesn't optimize seek(at()) + QSqlRecord r = query.record(); + QScriptValue row = engine->newObject(); + for (int j=0; j<r.count(); ++j) { + row.setProperty(r.fieldName(j), QScriptValue(engine,r.value(j).toString())); + } + return row; + } + return engine->undefinedValue(); +} + +static QScriptValue qmlsqldatabase_executeSql_outsidetransaction(QScriptContext *context, QScriptEngine * /*engine*/) +{ + THROW_SQL(DATABASE_ERR,QDeclarativeEngine::tr("executeSql called outside transaction()")); +} + +static QScriptValue qmlsqldatabase_executeSql(QScriptContext *context, QScriptEngine *engine) +{ + QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject()); + QString sql = context->argument(0).toString(); + QSqlQuery query(db); + bool err = false; + + QScriptValue result; + + if (query.prepare(sql)) { + if (context->argumentCount() > 1) { + QScriptValue values = context->argument(1); + if (values.isObject()) { + if (values.isArray()) { + int size = values.property(QLatin1String("length")).toInt32(); + for (int i = 0; i < size; ++i) + query.bindValue(i, values.property(i).toVariant()); + } else { + for (QScriptValueIterator it(values); it.hasNext();) { + it.next(); + query.bindValue(it.name(),it.value().toVariant()); + } + } + } else { + query.bindValue(0,values.toVariant()); + } + } + if (query.exec()) { + result = engine->newObject(); + QDeclarativeScriptEngine *qmlengine = static_cast<QDeclarativeScriptEngine*>(engine); + if (!qmlengine->sqlQueryClass) + qmlengine->sqlQueryClass = new QDeclarativeSqlQueryScriptClass(engine); + QScriptValue rows = engine->newObject(qmlengine->sqlQueryClass); + rows.setData(engine->newVariant(QVariant::fromValue(query))); + rows.setProperty(QLatin1String("item"), engine->newFunction(qmlsqldatabase_item,1), QScriptValue::SkipInEnumeration); + result.setProperty(QLatin1String("rows"),rows); + result.setProperty(QLatin1String("rowsAffected"),query.numRowsAffected()); + result.setProperty(QLatin1String("insertId"),query.lastInsertId().toString()); + } else { + err = true; + } + } else { + err = true; + } + if (err) + THROW_SQL(DATABASE_ERR,query.lastError().text()); + return result; +} + +static QScriptValue qmlsqldatabase_executeSql_readonly(QScriptContext *context, QScriptEngine *engine) +{ + QString sql = context->argument(0).toString(); + if (sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) { + return qmlsqldatabase_executeSql(context,engine); + } else { + THROW_SQL(SYNTAX_ERR,QDeclarativeEngine::tr("Read-only Transaction")) + } +} + +static QScriptValue qmlsqldatabase_change_version(QScriptContext *context, QScriptEngine *engine) +{ + if (context->argumentCount() < 2) + return engine->undefinedValue(); + + QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject()); + QString from_version = context->argument(0).toString(); + QString to_version = context->argument(1).toString(); + QScriptValue callback = context->argument(2); + + QScriptValue instance = engine->newObject(); + instance.setProperty(QLatin1String("executeSql"), engine->newFunction(qmlsqldatabase_executeSql,1)); + QScriptValue tx = engine->newVariant(instance,QVariant::fromValue(db)); + + QString foundvers = context->thisObject().property(QLatin1String("version")).toString(); + if (from_version!=foundvers) { + THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(foundvers)); + return engine->undefinedValue(); + } + + bool ok = true; + if (callback.isFunction()) { + ok = false; + db.transaction(); + callback.call(QScriptValue(), QScriptValueList() << tx); + if (engine->hasUncaughtException()) { + db.rollback(); + } else { + if (!db.commit()) { + db.rollback(); + THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("SQL transaction failed")); + } else { + ok = true; + } + } + } + + if (ok) { + context->thisObject().setProperty(QLatin1String("version"), to_version, QScriptValue::ReadOnly); +#ifndef QT_NO_SETTINGS + QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(),engine) + QLatin1String(".ini"), QSettings::IniFormat); + ini.setValue(QLatin1String("Version"), to_version); +#endif + } + + return engine->undefinedValue(); +} + +static QScriptValue qmlsqldatabase_transaction_shared(QScriptContext *context, QScriptEngine *engine, bool readOnly) +{ + QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject()); + QScriptValue callback = context->argument(0); + if (!callback.isFunction()) + THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("transaction: missing callback")); + + QScriptValue instance = engine->newObject(); + instance.setProperty(QLatin1String("executeSql"), + engine->newFunction(readOnly ? qmlsqldatabase_executeSql_readonly : qmlsqldatabase_executeSql,1)); + QScriptValue tx = engine->newVariant(instance,QVariant::fromValue(db)); + + db.transaction(); + callback.call(QScriptValue(), QScriptValueList() << tx); + instance.setProperty(QLatin1String("executeSql"), + engine->newFunction(qmlsqldatabase_executeSql_outsidetransaction)); + if (engine->hasUncaughtException()) { + db.rollback(); + } else { + if (!db.commit()) + db.rollback(); + } + return engine->undefinedValue(); +} + +static QScriptValue qmlsqldatabase_transaction(QScriptContext *context, QScriptEngine *engine) +{ + return qmlsqldatabase_transaction_shared(context,engine,false); +} +static QScriptValue qmlsqldatabase_read_transaction(QScriptContext *context, QScriptEngine *engine) +{ + return qmlsqldatabase_transaction_shared(context,engine,true); +} + +/* + Currently documented in doc/src/declarative/globalobject.qdoc +*/ +static QScriptValue qmlsqldatabase_open_sync(QScriptContext *context, QScriptEngine *engine) +{ +#ifndef QT_NO_SETTINGS + qmlsqldatabase_initDatabasesPath(engine); + + QSqlDatabase database; + + QString dbname = context->argument(0).toString(); + QString dbversion = context->argument(1).toString(); + QString dbdescription = context->argument(2).toString(); + int dbestimatedsize = context->argument(3).toNumber(); + QScriptValue dbcreationCallback = context->argument(4); + + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(dbname.toUtf8()); + QString dbid(QLatin1String(md5.result().toHex())); + + QString basename = qmlsqldatabase_databaseFile(dbid, engine); + bool created = false; + QString version = dbversion; + + { + QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat); + + if (QSqlDatabase::connectionNames().contains(dbid)) { + database = QSqlDatabase::database(dbid); + version = ini.value(QLatin1String("Version")).toString(); + if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty()) + THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch")); + } else { + created = !QFile::exists(basename+QLatin1String(".sqlite")); + database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid); + if (created) { + ini.setValue(QLatin1String("Name"), dbname); + if (dbcreationCallback.isFunction()) + version = QString(); + ini.setValue(QLatin1String("Version"), version); + ini.setValue(QLatin1String("Description"), dbdescription); + ini.setValue(QLatin1String("EstimatedSize"), dbestimatedsize); + ini.setValue(QLatin1String("Driver"), QLatin1String("QSQLITE")); + } else { + if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) { + // Incompatible + THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch")); + } + version = ini.value(QLatin1String("Version")).toString(); + } + database.setDatabaseName(basename+QLatin1String(".sqlite")); + } + if (!database.isOpen()) + database.open(); + } + + QScriptValue instance = engine->newObject(); + instance.setProperty(QLatin1String("transaction"), engine->newFunction(qmlsqldatabase_transaction,1)); + instance.setProperty(QLatin1String("readTransaction"), engine->newFunction(qmlsqldatabase_read_transaction,1)); + instance.setProperty(QLatin1String("version"), version, QScriptValue::ReadOnly); + instance.setProperty(QLatin1String("changeVersion"), engine->newFunction(qmlsqldatabase_change_version,3)); + + QScriptValue result = engine->newVariant(instance,QVariant::fromValue(database)); + + if (created && dbcreationCallback.isFunction()) { + dbcreationCallback.call(QScriptValue(), QScriptValueList() << result); + } + + return result; +#else + return engine->undefinedValue(); +#endif // QT_NO_SETTINGS +} + +void qt_add_qmlsqldatabase(QScriptEngine *engine) +{ + QScriptValue openDatabase = engine->newFunction(qmlsqldatabase_open_sync, 4); + engine->globalObject().setProperty(QLatin1String("openDatabaseSync"), openDatabase); + + QScriptValue sqlExceptionPrototype = engine->newObject(); + for (int i=0; sqlerror[i]; ++i) + sqlExceptionPrototype.setProperty(QLatin1String(sqlerror[i]), + i,QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + + engine->globalObject().setProperty(QLatin1String("SQLException"), sqlExceptionPrototype); +} + +/* +HTML5 "spec" says "rs.rows[n]", but WebKit only impelments "rs.rows.item(n)". We do both (and property iterator). +We add a "forwardOnly" property that stops Qt caching results (code promises to only go forward +through the data. +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativesqldatabase_p.h b/src/declarative/qml/qdeclarativesqldatabase_p.h new file mode 100644 index 00000000..cad0f3cd --- /dev/null +++ b/src/declarative/qml/qdeclarativesqldatabase_p.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESQLDATABASE_P_H +#define QDECLARATIVESQLDATABASE_P_H + +#include <QtScript/qscriptengine.h> +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QScriptEngine; +void qt_add_qmlsqldatabase(QScriptEngine *engine); + +QT_END_NAMESPACE + +#endif // QDECLARATIVESQLDATABASE_P_H + diff --git a/src/declarative/qml/qdeclarativestringconverters.cpp b/src/declarative/qml/qdeclarativestringconverters.cpp new file mode 100644 index 00000000..0ffae2f0 --- /dev/null +++ b/src/declarative/qml/qdeclarativestringconverters.cpp @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativestringconverters_p.h" + +#include <QtGui/qcolor.h> +#include <QtGui/qvector3d.h> +#include <QtCore/qpoint.h> +#include <QtCore/qrect.h> +#include <QtCore/qsize.h> +#include <QtCore/qvariant.h> +#include <QtCore/qdatetime.h> + +QT_BEGIN_NAMESPACE + +static uchar fromHex(const uchar c, const uchar c2) +{ + uchar rv = 0; + if (c >= '0' && c <= '9') + rv += (c - '0') * 16; + else if (c >= 'A' && c <= 'F') + rv += (c - 'A' + 10) * 16; + else if (c >= 'a' && c <= 'f') + rv += (c - 'a' + 10) * 16; + + if (c2 >= '0' && c2 <= '9') + rv += (c2 - '0'); + else if (c2 >= 'A' && c2 <= 'F') + rv += (c2 - 'A' + 10); + else if (c2 >= 'a' && c2 <= 'f') + rv += (c2 - 'a' + 10); + + return rv; +} + +static uchar fromHex(const QString &s, int idx) +{ + uchar c = s.at(idx).toAscii(); + uchar c2 = s.at(idx + 1).toAscii(); + return fromHex(c, c2); +} + +QVariant QDeclarativeStringConverters::variantFromString(const QString &s) +{ + if (s.isEmpty()) + return QVariant(s); + bool ok = false; + QRectF r = rectFFromString(s, &ok); + if (ok) return QVariant(r); + QColor c = colorFromString(s, &ok); + if (ok) return QVariant(c); + QPointF p = pointFFromString(s, &ok); + if (ok) return QVariant(p); + QSizeF sz = sizeFFromString(s, &ok); + if (ok) return QVariant(sz); + QVector3D v = vector3DFromString(s, &ok); + if (ok) return QVariant::fromValue(v); + + return QVariant(s); +} + +QVariant QDeclarativeStringConverters::variantFromString(const QString &s, int preferredType, bool *ok) +{ + switch (preferredType) { + case QMetaType::Int: + return QVariant(int(qRound(s.toDouble(ok)))); + case QMetaType::UInt: + return QVariant(uint(qRound(s.toDouble(ok)))); + case QMetaType::QColor: + return QVariant::fromValue(colorFromString(s, ok)); +#ifndef QT_NO_DATESTRING + case QMetaType::QDate: + return QVariant::fromValue(dateFromString(s, ok)); + case QMetaType::QTime: + return QVariant::fromValue(timeFromString(s, ok)); + case QMetaType::QDateTime: + return QVariant::fromValue(dateTimeFromString(s, ok)); +#endif // QT_NO_DATESTRING + case QMetaType::QPointF: + return QVariant::fromValue(pointFFromString(s, ok)); + case QMetaType::QPoint: + return QVariant::fromValue(pointFFromString(s, ok).toPoint()); + case QMetaType::QSizeF: + return QVariant::fromValue(sizeFFromString(s, ok)); + case QMetaType::QSize: + return QVariant::fromValue(sizeFFromString(s, ok).toSize()); + case QMetaType::QRectF: + return QVariant::fromValue(rectFFromString(s, ok)); + case QMetaType::QRect: + return QVariant::fromValue(rectFFromString(s, ok).toRect()); + case QMetaType::QVector3D: + return QVariant::fromValue(vector3DFromString(s, ok)); + default: + if (ok) *ok = false; + return QVariant(); + } +} + +QColor QDeclarativeStringConverters::colorFromString(const QString &s, bool *ok) +{ + if (s.length() == 9 && s.startsWith(QLatin1Char('#'))) { + uchar a = fromHex(s, 1); + uchar r = fromHex(s, 3); + uchar g = fromHex(s, 5); + uchar b = fromHex(s, 7); + if (ok) *ok = true; + return QColor(r, g, b, a); + } else { + QColor rv(s); + if (ok) *ok = rv.isValid(); + return rv; + } +} + +#ifndef QT_NO_DATESTRING +QDate QDeclarativeStringConverters::dateFromString(const QString &s, bool *ok) +{ + QDate d = QDate::fromString(s, Qt::ISODate); + if (ok) *ok = d.isValid(); + return d; +} + +QTime QDeclarativeStringConverters::timeFromString(const QString &s, bool *ok) +{ + QTime t = QTime::fromString(s, Qt::ISODate); + if (ok) *ok = t.isValid(); + return t; +} + +QDateTime QDeclarativeStringConverters::dateTimeFromString(const QString &s, bool *ok) +{ + QDateTime d = QDateTime::fromString(s, Qt::ISODate); + if (ok) *ok = d.isValid(); + return d; +} +#endif // QT_NO_DATESTRING + +//expects input of "x,y" +QPointF QDeclarativeStringConverters::pointFFromString(const QString &s, bool *ok) +{ + if (s.count(QLatin1Char(',')) != 1) { + if (ok) + *ok = false; + return QPointF(); + } + + bool xGood, yGood; + int index = s.indexOf(QLatin1Char(',')); + qreal xCoord = s.left(index).toDouble(&xGood); + qreal yCoord = s.mid(index+1).toDouble(&yGood); + if (!xGood || !yGood) { + if (ok) + *ok = false; + return QPointF(); + } + + if (ok) + *ok = true; + return QPointF(xCoord, yCoord); +} + +//expects input of "widthxheight" +QSizeF QDeclarativeStringConverters::sizeFFromString(const QString &s, bool *ok) +{ + if (s.count(QLatin1Char('x')) != 1) { + if (ok) + *ok = false; + return QSizeF(); + } + + bool wGood, hGood; + int index = s.indexOf(QLatin1Char('x')); + qreal width = s.left(index).toDouble(&wGood); + qreal height = s.mid(index+1).toDouble(&hGood); + if (!wGood || !hGood) { + if (ok) + *ok = false; + return QSizeF(); + } + + if (ok) + *ok = true; + return QSizeF(width, height); +} + +//expects input of "x,y,widthxheight" //### use space instead of second comma? +QRectF QDeclarativeStringConverters::rectFFromString(const QString &s, bool *ok) +{ + if (s.count(QLatin1Char(',')) != 2 || s.count(QLatin1Char('x')) != 1) { + if (ok) + *ok = false; + return QRectF(); + } + + bool xGood, yGood, wGood, hGood; + int index = s.indexOf(QLatin1Char(',')); + qreal x = s.left(index).toDouble(&xGood); + int index2 = s.indexOf(QLatin1Char(','), index+1); + qreal y = s.mid(index+1, index2-index-1).toDouble(&yGood); + index = s.indexOf(QLatin1Char('x'), index2+1); + qreal width = s.mid(index2+1, index-index2-1).toDouble(&wGood); + qreal height = s.mid(index+1).toDouble(&hGood); + if (!xGood || !yGood || !wGood || !hGood) { + if (ok) + *ok = false; + return QRectF(); + } + + if (ok) + *ok = true; + return QRectF(x, y, width, height); +} + +//expects input of "x,y,z" +QVector3D QDeclarativeStringConverters::vector3DFromString(const QString &s, bool *ok) +{ + if (s.count(QLatin1Char(',')) != 2) { + if (ok) + *ok = false; + return QVector3D(); + } + + bool xGood, yGood, zGood; + int index = s.indexOf(QLatin1Char(',')); + int index2 = s.indexOf(QLatin1Char(','), index+1); + qreal xCoord = s.left(index).toDouble(&xGood); + qreal yCoord = s.mid(index+1, index2-index-1).toDouble(&yGood); + qreal zCoord = s.mid(index2+1).toDouble(&zGood); + if (!xGood || !yGood || !zGood) { + if (ok) + *ok = false; + return QVector3D(); + } + + if (ok) + *ok = true; + return QVector3D(xCoord, yCoord, zCoord); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativestringconverters_p.h b/src/declarative/qml/qdeclarativestringconverters_p.h new file mode 100644 index 00000000..afb519ec --- /dev/null +++ b/src/declarative/qml/qdeclarativestringconverters_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESTRINGCONVERTERS_P_H +#define QDECLARATIVESTRINGCONVERTERS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QtCore/qvariant.h> + +#include <private/qdeclarativeglobal_p.h> + +QT_BEGIN_NAMESPACE + +class QColor; +class QPointF; +class QSizeF; +class QRectF; +class QString; +class QByteArray; +class QVector3D; + +// XXX - Bauhaus currently uses these methods which is why they're exported +namespace QDeclarativeStringConverters +{ + QVariant Q_DECLARATIVE_PRIVATE_EXPORT variantFromString(const QString &); + QVariant Q_DECLARATIVE_PRIVATE_EXPORT variantFromString(const QString &, int preferredType, bool *ok = 0); + + QColor Q_DECLARATIVE_PRIVATE_EXPORT colorFromString(const QString &, bool *ok = 0); +#ifndef QT_NO_DATESTRING + QDate Q_DECLARATIVE_PRIVATE_EXPORT dateFromString(const QString &, bool *ok = 0); + QTime Q_DECLARATIVE_PRIVATE_EXPORT timeFromString(const QString &, bool *ok = 0); + QDateTime Q_DECLARATIVE_PRIVATE_EXPORT dateTimeFromString(const QString &, bool *ok = 0); +#endif + QPointF Q_DECLARATIVE_PRIVATE_EXPORT pointFFromString(const QString &, bool *ok = 0); + QSizeF Q_DECLARATIVE_PRIVATE_EXPORT sizeFFromString(const QString &, bool *ok = 0); + QRectF Q_DECLARATIVE_PRIVATE_EXPORT rectFFromString(const QString &, bool *ok = 0); + QVector3D Q_DECLARATIVE_PRIVATE_EXPORT vector3DFromString(const QString &, bool *ok = 0); +} + +QT_END_NAMESPACE + +#endif // QDECLARATIVESTRINGCONVERTERS_P_H diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp new file mode 100644 index 00000000..4fa45102 --- /dev/null +++ b/src/declarative/qml/qdeclarativetypeloader.cpp @@ -0,0 +1,1196 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativetypeloader_p.h" + +#include <private/qdeclarativeengine_p.h> +#include <private/qdeclarativecompiler_p.h> +#include <private/qdeclarativecomponent_p.h> +#include <private/qdeclarativeglobal_p.h> +#include <private/qdeclarativedebugtrace_p.h> + +#include <QtDeclarative/qdeclarativecomponent.h> +#include <QtCore/qdebug.h> +#include <QtCore/qdir.h> +#include <QtCore/qdiriterator.h> +#include <QtCore/qfile.h> + +QT_BEGIN_NAMESPACE + +/* +Returns the set of QML files in path (qmldir, *.qml, *.js). The caller +is responsible for deleting the returned data. +*/ +static QSet<QString> *qmlFilesInDirectory(const QString &path) +{ + QDirIterator dir(path, QDir::Files); + if (!dir.hasNext()) + return 0; + QSet<QString> *files = new QSet<QString>; + while (dir.hasNext()) { + dir.next(); + QString fileName = dir.fileName(); + if (fileName == QLatin1String("qmldir") + || fileName.endsWith(QLatin1String(".qml")) + || fileName.endsWith(QLatin1String(".js"))) { +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_DARWIN) || defined(Q_OS_SYMBIAN) + fileName = fileName.toLower(); +#endif + files->insert(fileName); + } + } + return files; +} + + +/*! +\class QDeclarativeDataBlob +\brief The QDeclarativeDataBlob encapsulates a data request that can be issued to a QDeclarativeDataLoader. +\internal + +QDeclarativeDataBlob's are loaded by a QDeclarativeDataLoader. The user creates the QDeclarativeDataBlob +and then calls QDeclarativeDataLoader::load() or QDeclarativeDataLoader::loadWithStaticData() to load it. +The QDeclarativeDataLoader invokes callbacks on the QDeclarativeDataBlob as data becomes available. +*/ + +/*! + \class QDeclarativeTypeLoader + \internal +*/ + +/*! +\enum QDeclarativeDataBlob::Status + +This enum describes the status of the data blob. + +\list +\o Null The blob has not yet been loaded by a QDeclarativeDataLoader +\o Loading The blob is loading network data. The QDeclarativeDataBlob::setData() callback has not yet been +invoked or has not yet returned. +\o WaitingForDependencies The blob is waiting for dependencies to be done before continueing. This status +only occurs after the QDeclarativeDataBlob::setData() callback has been made, and when the blob has outstanding +dependencies. +\o Complete The blob's data has been loaded and all dependencies are done. +\o Error An error has been set on this blob. +\endlist +*/ + +/*! +\enum QDeclarativeDataBlob::Type + +This enum describes the type of the data blob. + +\list +\o QmlFile This is a QDeclarativeTypeData +\o JavaScriptFile This is a QDeclarativeScriptData +\o QmldirFile This is a QDeclarativeQmldirData +\endlist +*/ + +/*! +Create a new QDeclarativeDataBlob for \a url and of the provided \a type. +*/ +QDeclarativeDataBlob::QDeclarativeDataBlob(const QUrl &url, Type type) +: m_type(type), m_status(Null), m_progress(0), m_url(url), m_finalUrl(url), m_manager(0), + m_redirectCount(0), m_inCallback(false), m_isDone(false) +{ +} + +/*! \internal */ +QDeclarativeDataBlob::~QDeclarativeDataBlob() +{ + Q_ASSERT(m_waitingOnMe.isEmpty()); + + cancelAllWaitingFor(); +} + +/*! +Returns the type provided to the constructor. +*/ +QDeclarativeDataBlob::Type QDeclarativeDataBlob::type() const +{ + return m_type; +} + +/*! +Returns the blob's status. +*/ +QDeclarativeDataBlob::Status QDeclarativeDataBlob::status() const +{ + return m_status; +} + +/*! +Returns true if the status is Null. +*/ +bool QDeclarativeDataBlob::isNull() const +{ + return m_status == Null; +} + +/*! +Returns true if the status is Loading. +*/ +bool QDeclarativeDataBlob::isLoading() const +{ + return m_status == Loading; +} + +/*! +Returns true if the status is WaitingForDependencies. +*/ +bool QDeclarativeDataBlob::isWaiting() const +{ + return m_status == WaitingForDependencies; +} + +/*! +Returns true if the status is Complete. +*/ +bool QDeclarativeDataBlob::isComplete() const +{ + return m_status == Complete; +} + +/*! +Returns true if the status is Error. +*/ +bool QDeclarativeDataBlob::isError() const +{ + return m_status == Error; +} + +/*! +Returns true if the status is Complete or Error. +*/ +bool QDeclarativeDataBlob::isCompleteOrError() const +{ + return isComplete() || isError(); +} + +/*! +Returns the data download progress from 0 to 1. +*/ +qreal QDeclarativeDataBlob::progress() const +{ + return m_progress; +} + +/*! +Returns the blob url passed to the constructor. If a network redirect +happens while fetching the data, this url remains the same. + +\sa finalUrl() +*/ +QUrl QDeclarativeDataBlob::url() const +{ + return m_url; +} + +/*! +Returns the final url of the data. Initially this is the same as +url(), but if a network redirect happens while fetching the data, this url +is updated to reflect the new location. +*/ +QUrl QDeclarativeDataBlob::finalUrl() const +{ + return m_finalUrl; +} + +/*! +Return the errors on this blob. +*/ +QList<QDeclarativeError> QDeclarativeDataBlob::errors() const +{ + return m_errors; +} + +/*! +Mark this blob as having \a errors. + +All outstanding dependencies will be cancelled. Requests to add new dependencies +will be ignored. Entry into the Error state is irreversable, although you can change the +specific errors by additional calls to setError. +*/ +void QDeclarativeDataBlob::setError(const QDeclarativeError &errors) +{ + QList<QDeclarativeError> l; + l << errors; + setError(l); +} + +/*! +\overload +*/ +void QDeclarativeDataBlob::setError(const QList<QDeclarativeError> &errors) +{ + m_status = Error; + m_errors = errors; + + cancelAllWaitingFor(); + + if (!m_inCallback) + tryDone(); +} + +/*! +Wait for \a blob to become complete or to error. If \a blob is already +complete or in error, or this blob is already complete, this has no effect. +*/ +void QDeclarativeDataBlob::addDependency(QDeclarativeDataBlob *blob) +{ + Q_ASSERT(status() != Null); + + if (!blob || + blob->status() == Error || blob->status() == Complete || + status() == Error || status() == Complete || + m_waitingFor.contains(blob)) + return; + + blob->addref(); + m_status = WaitingForDependencies; + m_waitingFor.append(blob); + blob->m_waitingOnMe.append(this); +} + +/*! +\fn void QDeclarativeDataBlob::dataReceived(const QByteArray &data) + +Invoked when data for the blob is received. Implementors should use this callback +to determine a blob's dependencies. Within this callback you may call setError() +or addDependency(). +*/ + +/*! +Invoked once data has either been received or a network error occurred, and all +dependencies are complete. + +You can set an error in this method, but you cannot add new dependencies. Implementors +should use this callback to finalize processing of data. + +The default implementation does nothing. +*/ +void QDeclarativeDataBlob::done() +{ +} + +/*! +Invoked if there is a network error while fetching this blob. + +The default implementation sets an appropriate QDeclarativeError. +*/ +void QDeclarativeDataBlob::networkError(QNetworkReply::NetworkError networkError) +{ + Q_UNUSED(networkError); + + QDeclarativeError error; + error.setUrl(m_finalUrl); + + const char *errorString = 0; + switch (networkError) { + default: + errorString = "Network error"; + break; + case QNetworkReply::ConnectionRefusedError: + errorString = "Connection refused"; + break; + case QNetworkReply::RemoteHostClosedError: + errorString = "Remote host closed the connection"; + break; + case QNetworkReply::HostNotFoundError: + errorString = "Host not found"; + break; + case QNetworkReply::TimeoutError: + errorString = "Timeout"; + break; + case QNetworkReply::ProxyConnectionRefusedError: + case QNetworkReply::ProxyConnectionClosedError: + case QNetworkReply::ProxyNotFoundError: + case QNetworkReply::ProxyTimeoutError: + case QNetworkReply::ProxyAuthenticationRequiredError: + case QNetworkReply::UnknownProxyError: + errorString = "Proxy error"; + break; + case QNetworkReply::ContentAccessDenied: + errorString = "Access denied"; + break; + case QNetworkReply::ContentNotFoundError: + errorString = "File not found"; + break; + case QNetworkReply::AuthenticationRequiredError: + errorString = "Authentication required"; + break; + }; + + error.setDescription(QLatin1String(errorString)); + + setError(error); +} + +/*! +Called if \a blob, which was previously waited for, has an error. + +The default implementation does nothing. +*/ +void QDeclarativeDataBlob::dependencyError(QDeclarativeDataBlob *blob) +{ + Q_UNUSED(blob); +} + +/*! +Called if \a blob, which was previously waited for, has completed. + +The default implementation does nothing. +*/ +void QDeclarativeDataBlob::dependencyComplete(QDeclarativeDataBlob *blob) +{ + Q_UNUSED(blob); +} + +/*! +Called when all blobs waited for have completed. This occurs regardless of +whether they are in error, or complete state. + +The default implementation does nothing. +*/ +void QDeclarativeDataBlob::allDependenciesDone() +{ +} + +/*! +Called when the download progress of this blob changes. \a progress goes +from 0 to 1. +*/ +void QDeclarativeDataBlob::downloadProgressChanged(qreal progress) +{ + Q_UNUSED(progress); +} + +void QDeclarativeDataBlob::tryDone() +{ + if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) { + if (status() != Error) + m_status = Complete; + + m_isDone = true; + done(); + notifyAllWaitingOnMe(); + } +} + +void QDeclarativeDataBlob::cancelAllWaitingFor() +{ + while (m_waitingFor.count()) { + QDeclarativeDataBlob *blob = m_waitingFor.takeLast(); + + Q_ASSERT(blob->m_waitingOnMe.contains(this)); + + blob->m_waitingOnMe.removeOne(this); + + blob->release(); + } +} + +void QDeclarativeDataBlob::notifyAllWaitingOnMe() +{ + while (m_waitingOnMe.count()) { + QDeclarativeDataBlob *blob = m_waitingOnMe.takeLast(); + + Q_ASSERT(blob->m_waitingFor.contains(this)); + + blob->notifyComplete(this); + } +} + +void QDeclarativeDataBlob::notifyComplete(QDeclarativeDataBlob *blob) +{ + Q_ASSERT(m_waitingFor.contains(blob)); + Q_ASSERT(blob->status() == Error || blob->status() == Complete); + + m_inCallback = true; + + if (blob->status() == Error) { + dependencyError(blob); + } else if (blob->status() == Complete) { + dependencyComplete(blob); + } + + m_waitingFor.removeOne(blob); + blob->release(); + + if (!isError() && m_waitingFor.isEmpty()) + allDependenciesDone(); + + m_inCallback = false; + + tryDone(); +} + +/*! +\class QDeclarativeDataLoader +\brief The QDeclarativeDataLoader class abstracts loading files and their dependencies over the network. +\internal + +The QDeclarativeDataLoader class is provided for the exclusive use of the QDeclarativeTypeLoader class. + +Clients create QDeclarativeDataBlob instances and submit them to the QDeclarativeDataLoader class +through the QDeclarativeDataLoader::load() or QDeclarativeDataLoader::loadWithStaticData() methods. +The loader then fetches the data over the network or from the local file system in an efficient way. +QDeclarativeDataBlob is an abstract class, so should always be specialized. + +Once data is received, the QDeclarativeDataBlob::dataReceived() method is invoked on the blob. The +derived class should use this callback to process the received data. Processing of the data can +result in an error being set (QDeclarativeDataBlob::setError()), or one or more dependencies being +created (QDeclarativeDataBlob::addDependency()). Dependencies are other QDeclarativeDataBlob's that +are required before processing can fully complete. + +To complete processing, the QDeclarativeDataBlob::done() callback is invoked. done() is called when +one of these three preconditions are met. + +\list 1 +\o The QDeclarativeDataBlob has no dependencies. +\o The QDeclarativeDataBlob has an error set. +\o All the QDeclarativeDataBlob's dependencies are themselves "done()". +\endlist + +Thus QDeclarativeDataBlob::done() will always eventually be called, even if the blob has an error set. +*/ + +/*! +Create a new QDeclarativeDataLoader for \a engine. +*/ +QDeclarativeDataLoader::QDeclarativeDataLoader(QDeclarativeEngine *engine) +: m_engine(engine) +{ +} + +/*! \internal */ +QDeclarativeDataLoader::~QDeclarativeDataLoader() +{ + for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter) + (*iter)->release(); +} + +/*! +Load the provided \a blob from the network or filesystem. +*/ +void QDeclarativeDataLoader::load(QDeclarativeDataBlob *blob) +{ + Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null); + Q_ASSERT(blob->m_manager == 0); + + blob->m_status = QDeclarativeDataBlob::Loading; + + if (blob->m_url.isEmpty()) { + QDeclarativeError error; + error.setDescription(QLatin1String("Invalid null URL")); + blob->setError(error); + return; + } + + QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(blob->m_url); + + if (!lf.isEmpty()) { + if (!QDeclarative_isFileCaseCorrect(lf)) { + QDeclarativeError error; + error.setUrl(blob->m_url); + error.setDescription(QLatin1String("File name case mismatch")); + blob->setError(error); + return; + } + QFile file(lf); + if (file.open(QFile::ReadOnly)) { + QByteArray data = file.readAll(); + + blob->m_progress = 1.; + blob->downloadProgressChanged(1.); + + setData(blob, data); + } else { + blob->networkError(QNetworkReply::ContentNotFoundError); + } + + } else { + + blob->m_manager = this; + QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(blob->m_url)); + QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(networkReplyProgress(qint64,qint64))); + QObject::connect(reply, SIGNAL(finished()), + this, SLOT(networkReplyFinished())); + m_networkReplies.insert(reply, blob); + + blob->addref(); + } +} + +#define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16 + +void QDeclarativeDataLoader::networkReplyFinished() +{ + QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); + reply->deleteLater(); + + QDeclarativeDataBlob *blob = m_networkReplies.take(reply); + + Q_ASSERT(blob); + + blob->m_redirectCount++; + + if (blob->m_redirectCount < DATALOADER_MAXIMUM_REDIRECT_RECURSION) { + QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (redirect.isValid()) { + QUrl url = reply->url().resolved(redirect.toUrl()); + blob->m_finalUrl = url; + + QNetworkReply *reply = m_engine->networkAccessManager()->get(QNetworkRequest(url)); + QObject::connect(reply, SIGNAL(finished()), this, SLOT(networkReplyFinished())); + m_networkReplies.insert(reply, blob); + return; + } + } + + if (reply->error()) { + blob->networkError(reply->error()); + } else { + QByteArray data = reply->readAll(); + setData(blob, data); + } + + blob->release(); +} + +void QDeclarativeDataLoader::networkReplyProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); + QDeclarativeDataBlob *blob = m_networkReplies.value(reply); + + Q_ASSERT(blob); + + if (bytesTotal != 0) { + blob->m_progress = bytesReceived / bytesTotal; + blob->downloadProgressChanged(blob->m_progress); + } +} + +/*! +Load the provided \a blob with \a data. The blob's URL is not used by the data loader in this case. +*/ +void QDeclarativeDataLoader::loadWithStaticData(QDeclarativeDataBlob *blob, const QByteArray &data) +{ + Q_ASSERT(blob->status() == QDeclarativeDataBlob::Null); + Q_ASSERT(blob->m_manager == 0); + + blob->m_status = QDeclarativeDataBlob::Loading; + + setData(blob, data); +} + +/*! +Return the QDeclarativeEngine associated with this loader +*/ +QDeclarativeEngine *QDeclarativeDataLoader::engine() const +{ + return m_engine; +} + +void QDeclarativeDataLoader::setData(QDeclarativeDataBlob *blob, const QByteArray &data) +{ + blob->m_inCallback = true; + + blob->dataReceived(data); + + if (!blob->isError() && !blob->isWaiting()) + blob->allDependenciesDone(); + + if (blob->status() != QDeclarativeDataBlob::Error) + blob->m_status = QDeclarativeDataBlob::WaitingForDependencies; + + blob->m_inCallback = false; + + blob->tryDone(); +} + +/*! +Constructs a new type loader that uses the given \a engine. +*/ +QDeclarativeTypeLoader::QDeclarativeTypeLoader(QDeclarativeEngine *engine) +: QDeclarativeDataLoader(engine) +{ +} + +/*! +Destroys the type loader, first clearing the cache of any information about +loaded files. +*/ +QDeclarativeTypeLoader::~QDeclarativeTypeLoader() +{ + clearCache(); +} + +/*! +\enum QDeclarativeTypeLoader::Option + +This enum defines the options that control the way type data is handled. + +\value None The default value, indicating that no other options + are enabled. +\value PreserveParser The parser used to handle the type data is preserved + after the data has been parsed. +*/ + +/*! +Returns a QDeclarativeTypeData for the specified \a url. The QDeclarativeTypeData may be cached. +*/ +QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QUrl &url) +{ + Q_ASSERT(!url.isRelative() && + (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() || + !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url)))); + + QDeclarativeTypeData *typeData = m_typeCache.value(url); + + if (!typeData) { + typeData = new QDeclarativeTypeData(url, None, this); + m_typeCache.insert(url, typeData); + QDeclarativeDataLoader::load(typeData); + } + + typeData->addref(); + return typeData; +} + +/*! +Returns a QDeclarativeTypeData for the given \a data with the provided base \a url. The +QDeclarativeTypeData will not be cached. + +The specified \a options control how the loader handles type data. +*/ +QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QByteArray &data, const QUrl &url, Options options) +{ + QDeclarativeTypeData *typeData = new QDeclarativeTypeData(url, options, this); + QDeclarativeDataLoader::loadWithStaticData(typeData, data); + return typeData; +} + +/*! +Returns a QDeclarativeScriptData for \a url. The QDeclarativeScriptData may be cached. +*/ +QDeclarativeScriptData *QDeclarativeTypeLoader::getScript(const QUrl &url) +{ + Q_ASSERT(!url.isRelative() && + (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() || + !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url)))); + + QDeclarativeScriptData *scriptData = m_scriptCache.value(url); + + if (!scriptData) { + scriptData = new QDeclarativeScriptData(url); + m_scriptCache.insert(url, scriptData); + QDeclarativeDataLoader::load(scriptData); + } + + scriptData->addref(); + return scriptData; +} + +/*! +Returns a QDeclarativeQmldirData for \a url. The QDeclarativeQmldirData may be cached. +*/ +QDeclarativeQmldirData *QDeclarativeTypeLoader::getQmldir(const QUrl &url) +{ + Q_ASSERT(!url.isRelative() && + (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url).isEmpty() || + !QDir::isRelativePath(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url)))); + + QDeclarativeQmldirData *qmldirData = m_qmldirCache.value(url); + + if (!qmldirData) { + qmldirData = new QDeclarativeQmldirData(url); + m_qmldirCache.insert(url, qmldirData); + QDeclarativeDataLoader::load(qmldirData); + } + + qmldirData->addref(); + return qmldirData; +} + +/*! +Returns the absolute filename of path via a directory cache for files named +"qmldir", "*.qml", "*.js" +Returns a empty string if the path does not exist. +*/ +QString QDeclarativeTypeLoader::absoluteFilePath(const QString &path) +{ + if (path.isEmpty()) + return QString(); + if (path.at(0) == QLatin1Char(':')) { + // qrc resource + QFileInfo fileInfo(path); + return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString(); + } +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_DARWIN) || defined(Q_OS_SYMBIAN) + QString lowPath(path.toLower()); +#else + QString lowPath(path); +#endif + int lastSlash = lowPath.lastIndexOf(QLatin1Char('/')); + QString dirPath = lowPath.left(lastSlash); + + StringSet *fileSet = 0; + QHash<QString,StringSet*>::const_iterator it = m_importDirCache.find(dirPath); + if (it == m_importDirCache.end()) { + StringSet *files = qmlFilesInDirectory(path.left(lastSlash)); + m_importDirCache.insert(dirPath, files); + fileSet = files; + } else { + fileSet = *it; + } + if (!fileSet) + return QString(); + + QString absoluteFilePath = fileSet->contains(QString(lowPath.constData()+lastSlash+1, lowPath.length()-lastSlash-1)) ? path : QString(); + if (absoluteFilePath.length() > 2 && absoluteFilePath.at(0) != QLatin1Char('/') && absoluteFilePath.at(1) != QLatin1Char(':')) + absoluteFilePath = QFileInfo(absoluteFilePath).absoluteFilePath(); + + return absoluteFilePath; +} + +/*! +Return a QDeclarativeDirParser for absoluteFilePath. The QDeclarativeDirParser may be cached. +*/ +const QDeclarativeDirParser *QDeclarativeTypeLoader::qmlDirParser(const QString &absoluteFilePath) +{ + QDeclarativeDirParser *qmldirParser; + QHash<QString,QDeclarativeDirParser*>::const_iterator it = m_importQmlDirCache.find(absoluteFilePath); + if (it == m_importQmlDirCache.end()) { + qmldirParser = new QDeclarativeDirParser; + qmldirParser->setFileSource(absoluteFilePath); + qmldirParser->setUrl(QUrl::fromLocalFile(absoluteFilePath)); + qmldirParser->parse(); + m_importQmlDirCache.insert(absoluteFilePath, qmldirParser); + } else { + qmldirParser = *it; + } + + return qmldirParser; +} + +/* +Clears cached information about loaded files, including any type data, scripts +and qmldir information. +*/ +void QDeclarativeTypeLoader::clearCache() +{ + for (TypeCache::Iterator iter = m_typeCache.begin(); iter != m_typeCache.end(); ++iter) + (*iter)->release(); + for (ScriptCache::Iterator iter = m_scriptCache.begin(); iter != m_scriptCache.end(); ++iter) + (*iter)->release(); + for (QmldirCache::Iterator iter = m_qmldirCache.begin(); iter != m_qmldirCache.end(); ++iter) + (*iter)->release(); + qDeleteAll(m_importDirCache); + qDeleteAll(m_importQmlDirCache); + + m_typeCache.clear(); + m_scriptCache.clear(); + m_qmldirCache.clear(); + m_importDirCache.clear(); + m_importQmlDirCache.clear(); +} + + +QDeclarativeTypeData::QDeclarativeTypeData(const QUrl &url, QDeclarativeTypeLoader::Options options, + QDeclarativeTypeLoader *manager) +: QDeclarativeDataBlob(url, QmlFile), m_options(options), m_imports(manager), m_typesResolved(false), + m_compiledData(0), m_typeLoader(manager) +{ +} + +QDeclarativeTypeData::~QDeclarativeTypeData() +{ + for (int ii = 0; ii < m_scripts.count(); ++ii) + m_scripts.at(ii).script->release(); + for (int ii = 0; ii < m_qmldirs.count(); ++ii) + m_qmldirs.at(ii)->release(); + for (int ii = 0; ii < m_types.count(); ++ii) + if (m_types.at(ii).typeData) m_types.at(ii).typeData->release(); + if (m_compiledData) + m_compiledData->release(); +} + +QDeclarativeTypeLoader *QDeclarativeTypeData::typeLoader() const +{ + return m_typeLoader; +} + +const QDeclarativeImports &QDeclarativeTypeData::imports() const +{ + return m_imports; +} + +const QDeclarativeScriptParser &QDeclarativeTypeData::parser() const +{ + return scriptParser; +} + +const QList<QDeclarativeTypeData::TypeReference> &QDeclarativeTypeData::resolvedTypes() const +{ + return m_types; +} + +const QList<QDeclarativeTypeData::ScriptReference> &QDeclarativeTypeData::resolvedScripts() const +{ + return m_scripts; +} + +QDeclarativeCompiledData *QDeclarativeTypeData::compiledData() const +{ + if (m_compiledData) + m_compiledData->addref(); + + return m_compiledData; +} + +void QDeclarativeTypeData::registerCallback(TypeDataCallback *callback) +{ + Q_ASSERT(!m_callbacks.contains(callback)); + m_callbacks.append(callback); +} + +void QDeclarativeTypeData::unregisterCallback(TypeDataCallback *callback) +{ + Q_ASSERT(m_callbacks.contains(callback)); + m_callbacks.removeOne(callback); + Q_ASSERT(!m_callbacks.contains(callback)); +} + +void QDeclarativeTypeData::done() +{ + addref(); + + // Check all script dependencies for errors + for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) { + const ScriptReference &script = m_scripts.at(ii); + Q_ASSERT(script.script->isCompleteOrError()); + if (script.script->isError()) { + QList<QDeclarativeError> errors = script.script->errors(); + QDeclarativeError error; + error.setUrl(finalUrl()); + error.setLine(script.location.line); + error.setColumn(script.location.column); + error.setDescription(QDeclarativeTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString())); + errors.prepend(error); + setError(errors); + } + } + + // Check all type dependencies for errors + for (int ii = 0; !isError() && ii < m_types.count(); ++ii) { + const TypeReference &type = m_types.at(ii); + Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError()); + if (type.typeData && type.typeData->isError()) { + QString typeName = scriptParser.referencedTypes().at(ii)->name; + + QList<QDeclarativeError> errors = type.typeData->errors(); + QDeclarativeError error; + error.setUrl(finalUrl()); + error.setLine(type.location.line); + error.setColumn(type.location.column); + error.setDescription(QDeclarativeTypeLoader::tr("Type %1 unavailable").arg(typeName)); + errors.prepend(error); + setError(errors); + } + } + + // Compile component + if (!isError()) + compile(); + + if (!(m_options & QDeclarativeTypeLoader::PreserveParser)) + scriptParser.clear(); + + // Notify callbacks + while (!m_callbacks.isEmpty()) { + TypeDataCallback *callback = m_callbacks.takeFirst(); + callback->typeDataReady(this); + } + + release(); +} + +void QDeclarativeTypeData::dataReceived(const QByteArray &data) +{ + if (!scriptParser.parse(data, finalUrl())) { + setError(scriptParser.errors()); + return; + } + + m_imports.setBaseUrl(finalUrl()); + + foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) { + if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) { + QUrl importUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir"))); + if (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) { + QDeclarativeQmldirData *data = typeLoader()->getQmldir(importUrl); + addDependency(data); + m_qmldirs << data; + } + } else if (import.type == QDeclarativeScriptParser::Import::Script) { + QUrl scriptUrl = finalUrl().resolved(QUrl(import.uri)); + QDeclarativeScriptData *data = typeLoader()->getScript(scriptUrl); + addDependency(data); + + ScriptReference ref; + ref.location = import.location.start; + ref.qualifier = import.qualifier; + ref.script = data; + m_scripts << ref; + + } + } + + if (!finalUrl().scheme().isEmpty()) { + QUrl importUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir"))); + if (QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl).isEmpty()) { + QDeclarativeQmldirData *data = typeLoader()->getQmldir(importUrl); + addDependency(data); + m_qmldirs << data; + } + } +} + +void QDeclarativeTypeData::allDependenciesDone() +{ + if (!m_typesResolved) { + resolveTypes(); + m_typesResolved = true; + } +} + +void QDeclarativeTypeData::downloadProgressChanged(qreal p) +{ + for (int ii = 0; ii < m_callbacks.count(); ++ii) { + TypeDataCallback *callback = m_callbacks.at(ii); + callback->typeDataProgress(this, p); + } +} + +void QDeclarativeTypeData::compile() +{ + Q_ASSERT(m_compiledData == 0); + QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Compiling); + + m_compiledData = new QDeclarativeCompiledData(typeLoader()->engine()); + m_compiledData->url = m_imports.baseUrl(); + m_compiledData->name = m_compiledData->url.toString(); + QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Compiling, m_compiledData->name); + + QDeclarativeCompiler compiler; + if (!compiler.compile(typeLoader()->engine(), this, m_compiledData)) { + setError(compiler.errors()); + m_compiledData->release(); + m_compiledData = 0; + } + QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Compiling); +} + +void QDeclarativeTypeData::resolveTypes() +{ + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_typeLoader->engine()); + QDeclarativeImportDatabase *importDatabase = &ep->importDatabase; + + // For local urls, add an implicit import "." as first (most overridden) lookup. + // This will also trigger the loading of the qmldir and the import of any native + // types from available plugins. + if (QDeclarativeQmldirData *qmldir = qmldirForUrl(finalUrl().resolved(QUrl(QLatin1String("./qmldir"))))) { + m_imports.addImport(importDatabase, QLatin1String("."), + QString(), -1, -1, QDeclarativeScriptParser::Import::File, + qmldir->dirComponents(), 0); + } else { + m_imports.addImport(importDatabase, QLatin1String("."), + QString(), -1, -1, QDeclarativeScriptParser::Import::File, + QDeclarativeDirComponents(), 0); + } + + foreach (const QDeclarativeScriptParser::Import &import, scriptParser.imports()) { + QDeclarativeDirComponents qmldircomponentsnetwork; + if (import.type == QDeclarativeScriptParser::Import::Script) + continue; + + if (import.type == QDeclarativeScriptParser::Import::File && import.qualifier.isEmpty()) { + QUrl qmldirUrl = finalUrl().resolved(QUrl(import.uri + QLatin1String("/qmldir"))); + if (QDeclarativeQmldirData *qmldir = qmldirForUrl(qmldirUrl)) + qmldircomponentsnetwork = qmldir->dirComponents(); + } + + int vmaj = -1; + int vmin = -1; + + if (!import.version.isEmpty()) { + int dot = import.version.indexOf(QLatin1Char('.')); + if (dot < 0) { + vmaj = import.version.toInt(); + vmin = 0; + } else { + vmaj = import.version.left(dot).toInt(); + vmin = import.version.mid(dot+1).toInt(); + } + } + + QString errorString; + if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, + vmaj, vmin, import.type, qmldircomponentsnetwork, &errorString)) { + QDeclarativeError error; + error.setUrl(m_imports.baseUrl()); + error.setDescription(errorString); + error.setLine(import.location.start.line); + error.setColumn(import.location.start.column); + + setError(error); + return; + } + } + + foreach (QDeclarativeScriptParser::TypeReference *parserRef, scriptParser.referencedTypes()) { + QByteArray typeName = parserRef->name.toUtf8(); + + TypeReference ref; + + QUrl url; + int majorVersion; + int minorVersion; + QDeclarativeImportedNamespace *typeNamespace = 0; + QString errorString; + + if (!m_imports.resolveType(typeName, &ref.type, &url, &majorVersion, &minorVersion, + &typeNamespace, &errorString) || typeNamespace) { + // Known to not be a type: + // - known to be a namespace (Namespace {}) + // - type with unknown namespace (UnknownNamespace.SomeType {}) + QDeclarativeError error; + error.setUrl(m_imports.baseUrl()); + QString userTypeName = parserRef->name; + userTypeName.replace(QLatin1Char('/'),QLatin1Char('.')); + if (typeNamespace) + error.setDescription(QDeclarativeTypeLoader::tr("Namespace %1 cannot be used as a type").arg(userTypeName)); + else + error.setDescription(QDeclarativeTypeLoader::tr("%1 %2").arg(userTypeName).arg(errorString)); + + if (!parserRef->refObjects.isEmpty()) { + QDeclarativeParser::Object *obj = parserRef->refObjects.first(); + error.setLine(obj->location.start.line); + error.setColumn(obj->location.start.column); + } + + setError(error); + return; + } + + if (ref.type) { + ref.majorVersion = majorVersion; + ref.minorVersion = minorVersion; + foreach (QDeclarativeParser::Object *obj, parserRef->refObjects) { + // store namespace for DOM + obj->majorVersion = majorVersion; + obj->minorVersion = minorVersion; + } + } else { + ref.typeData = typeLoader()->get(url); + addDependency(ref.typeData); + } + + if (parserRef->refObjects.count()) + ref.location = parserRef->refObjects.first()->location.start; + + m_types << ref; + } +} + +QDeclarativeQmldirData *QDeclarativeTypeData::qmldirForUrl(const QUrl &url) +{ + for (int ii = 0; ii < m_qmldirs.count(); ++ii) { + if (m_qmldirs.at(ii)->url() == url) + return m_qmldirs.at(ii); + } + return 0; +} + +QDeclarativeScriptData::QDeclarativeScriptData(const QUrl &url) +: QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None) +{ +} + +QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptData::pragmas() const +{ + return m_pragmas; +} + +QString QDeclarativeScriptData::scriptSource() const +{ + return m_source; +} + +void QDeclarativeScriptData::dataReceived(const QByteArray &data) +{ + m_source = QString::fromUtf8(data); + m_pragmas = QDeclarativeScriptParser::extractPragmas(m_source); +} + +QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url) +: QDeclarativeDataBlob(url, QmldirFile) +{ +} + +const QDeclarativeDirComponents &QDeclarativeQmldirData::dirComponents() const +{ + return m_components; +} + +void QDeclarativeQmldirData::dataReceived(const QByteArray &data) +{ + QDeclarativeDirParser parser; + parser.setSource(QString::fromUtf8(data)); + parser.parse(); + m_components = parser.components(); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h new file mode 100644 index 00000000..d377b4b9 --- /dev/null +++ b/src/declarative/qml/qdeclarativetypeloader_p.h @@ -0,0 +1,330 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVETYPELOADER_P_H +#define QDECLARATIVETYPELOADER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtNetwork/qnetworkreply.h> +#include <QtDeclarative/qdeclarativeerror.h> +#include <QtDeclarative/qdeclarativeengine.h> +#include <private/qdeclarativescriptparser_p.h> +#include <private/qdeclarativedirparser_p.h> +#include <private/qdeclarativeimport_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeScriptData; +class QDeclarativeQmldirData; +class QDeclarativeTypeLoader; +class QDeclarativeCompiledData; +class QDeclarativeComponentPrivate; +class QDeclarativeTypeData; +class QDeclarativeDataLoader; + +class Q_AUTOTEST_EXPORT QDeclarativeDataBlob : public QDeclarativeRefCount +{ +public: + enum Status { + Null, // Prior to QDeclarativeDataLoader::load() + Loading, // Prior to data being received and dataReceived() being called + WaitingForDependencies, // While there are outstanding addDependency()s + Complete, // Finished + Error // Error + }; + + enum Type { + QmlFile, + JavaScriptFile, + QmldirFile + }; + + QDeclarativeDataBlob(const QUrl &, Type); + virtual ~QDeclarativeDataBlob(); + + Type type() const; + + Status status() const; + bool isNull() const; + bool isLoading() const; + bool isWaiting() const; + bool isComplete() const; + bool isError() const; + bool isCompleteOrError() const; + + qreal progress() const; + + QUrl url() const; + QUrl finalUrl() const; + + QList<QDeclarativeError> errors() const; + + void setError(const QDeclarativeError &); + void setError(const QList<QDeclarativeError> &errors); + + void addDependency(QDeclarativeDataBlob *); + +protected: + virtual void dataReceived(const QByteArray &) = 0; + + virtual void done(); + virtual void networkError(QNetworkReply::NetworkError); + + virtual void dependencyError(QDeclarativeDataBlob *); + virtual void dependencyComplete(QDeclarativeDataBlob *); + virtual void allDependenciesDone(); + + virtual void downloadProgressChanged(qreal); + +private: + friend class QDeclarativeDataLoader; + void tryDone(); + void cancelAllWaitingFor(); + void notifyAllWaitingOnMe(); + void notifyComplete(QDeclarativeDataBlob *); + + Type m_type; + Status m_status; + qreal m_progress; + + QUrl m_url; + QUrl m_finalUrl; + + // List of QDeclarativeDataBlob's that are waiting for me to complete. + QList<QDeclarativeDataBlob *> m_waitingOnMe; + + // List of QDeclarativeDataBlob's that I am waiting for to complete. + QList<QDeclarativeDataBlob *> m_waitingFor; + + // Manager that is currently fetching data for me + QDeclarativeDataLoader *m_manager; + int m_redirectCount:30; + bool m_inCallback:1; + bool m_isDone:1; + + QList<QDeclarativeError> m_errors; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeDataLoader : public QObject +{ + Q_OBJECT +public: + QDeclarativeDataLoader(QDeclarativeEngine *); + ~QDeclarativeDataLoader(); + + void load(QDeclarativeDataBlob *); + void loadWithStaticData(QDeclarativeDataBlob *, const QByteArray &); + + QDeclarativeEngine *engine() const; + +private slots: + void networkReplyFinished(); + void networkReplyProgress(qint64,qint64); + +private: + void setData(QDeclarativeDataBlob *, const QByteArray &); + + QDeclarativeEngine *m_engine; + typedef QHash<QNetworkReply *, QDeclarativeDataBlob *> NetworkReplies; + NetworkReplies m_networkReplies; +}; + + +class Q_AUTOTEST_EXPORT QDeclarativeTypeLoader : public QDeclarativeDataLoader +{ + Q_OBJECT +public: + QDeclarativeTypeLoader(QDeclarativeEngine *); + ~QDeclarativeTypeLoader(); + + enum Option { + None, + PreserveParser + }; + Q_DECLARE_FLAGS(Options, Option) + + QDeclarativeTypeData *get(const QUrl &url); + QDeclarativeTypeData *get(const QByteArray &, const QUrl &url, Options = None); + void clearCache(); + + QDeclarativeScriptData *getScript(const QUrl &); + QDeclarativeQmldirData *getQmldir(const QUrl &); + + QString absoluteFilePath(const QString &path); + const QDeclarativeDirParser *qmlDirParser(const QString &absoluteFilePath); + +private: + typedef QHash<QUrl, QDeclarativeTypeData *> TypeCache; + typedef QHash<QUrl, QDeclarativeScriptData *> ScriptCache; + typedef QHash<QUrl, QDeclarativeQmldirData *> QmldirCache; + typedef QSet<QString> StringSet; + typedef QHash<QString, StringSet*> ImportDirCache; + typedef QHash<QString, QDeclarativeDirParser*> ImportQmlDirCache; + + TypeCache m_typeCache; + ScriptCache m_scriptCache; + QmldirCache m_qmldirCache; + ImportDirCache m_importDirCache; + ImportQmlDirCache m_importQmlDirCache; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeTypeLoader::Options) + +class Q_AUTOTEST_EXPORT QDeclarativeTypeData : public QDeclarativeDataBlob +{ +public: + struct TypeReference + { + TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0) {} + + QDeclarativeParser::Location location; + QDeclarativeType *type; + int majorVersion; + int minorVersion; + QDeclarativeTypeData *typeData; + }; + + struct ScriptReference + { + ScriptReference() : script(0) {} + + QDeclarativeParser::Location location; + QString qualifier; + QDeclarativeScriptData *script; + }; + + QDeclarativeTypeData(const QUrl &, QDeclarativeTypeLoader::Options, QDeclarativeTypeLoader *); + ~QDeclarativeTypeData(); + + QDeclarativeTypeLoader *typeLoader() const; + + const QDeclarativeImports &imports() const; + const QDeclarativeScriptParser &parser() const; + + const QList<TypeReference> &resolvedTypes() const; + const QList<ScriptReference> &resolvedScripts() const; + + QDeclarativeCompiledData *compiledData() const; + + // Used by QDeclarativeComponent to get notifications + struct TypeDataCallback { + ~TypeDataCallback() {} + virtual void typeDataProgress(QDeclarativeTypeData *, qreal) {} + virtual void typeDataReady(QDeclarativeTypeData *) {} + }; + void registerCallback(TypeDataCallback *); + void unregisterCallback(TypeDataCallback *); + +protected: + virtual void done(); + virtual void dataReceived(const QByteArray &); + virtual void allDependenciesDone(); + virtual void downloadProgressChanged(qreal); + +private: + void resolveTypes(); + void compile(); + + QDeclarativeTypeLoader::Options m_options; + + QDeclarativeQmldirData *qmldirForUrl(const QUrl &); + + QDeclarativeScriptParser scriptParser; + QDeclarativeImports m_imports; + + QList<ScriptReference> m_scripts; + QList<QDeclarativeQmldirData *> m_qmldirs; + + QList<TypeReference> m_types; + bool m_typesResolved:1; + + QDeclarativeCompiledData *m_compiledData; + + QList<TypeDataCallback *> m_callbacks; + + QDeclarativeTypeLoader *m_typeLoader; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeScriptData : public QDeclarativeDataBlob +{ +public: + QDeclarativeScriptData(const QUrl &); + + QDeclarativeParser::Object::ScriptBlock::Pragmas pragmas() const; + QString scriptSource() const; + +protected: + virtual void dataReceived(const QByteArray &); + +private: + QDeclarativeParser::Object::ScriptBlock::Pragmas m_pragmas; + QString m_source; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeQmldirData : public QDeclarativeDataBlob +{ +public: + QDeclarativeQmldirData(const QUrl &); + + const QDeclarativeDirComponents &dirComponents() const; + +protected: + virtual void dataReceived(const QByteArray &); + +private: + QDeclarativeDirComponents m_components; + +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVETYPELOADER_P_H diff --git a/src/declarative/qml/qdeclarativetypenamecache.cpp b/src/declarative/qml/qdeclarativetypenamecache.cpp new file mode 100644 index 00000000..29b88750 --- /dev/null +++ b/src/declarative/qml/qdeclarativetypenamecache.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativetypenamecache_p.h" + +#include "private/qdeclarativeengine_p.h" + +QT_BEGIN_NAMESPACE + +QDeclarativeTypeNameCache::QDeclarativeTypeNameCache(QDeclarativeEngine *e) +: QDeclarativeCleanup(e), engine(e) +{ +} + +QDeclarativeTypeNameCache::~QDeclarativeTypeNameCache() +{ + clear(); +} + +void QDeclarativeTypeNameCache::clear() +{ + qDeleteAll(stringCache); + stringCache.clear(); + identifierCache.clear(); + engine = 0; +} + +void QDeclarativeTypeNameCache::add(const QString &name, int importedScriptIndex) +{ + if (stringCache.contains(name)) + return; + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + + RData *data = new RData; + // ### Use typename class + data->identifier = ep->objectClass->createPersistentIdentifier(name); + data->importedScriptIndex = importedScriptIndex; + stringCache.insert(name, data); + identifierCache.insert(data->identifier.identifier, data); +} + +void QDeclarativeTypeNameCache::add(const QString &name, QDeclarativeType *type) +{ + if (stringCache.contains(name)) + return; + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + + RData *data = new RData; + // ### Use typename class + data->identifier = ep->objectClass->createPersistentIdentifier(name); + data->type = type; + stringCache.insert(name, data); + identifierCache.insert(data->identifier.identifier, data); +} + +void QDeclarativeTypeNameCache::add(const QString &name, QDeclarativeTypeNameCache *typeNamespace) +{ + if (stringCache.contains(name)) + return; + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + + RData *data = new RData; + // ### Use typename class + data->identifier = ep->objectClass->createPersistentIdentifier(name); + data->typeNamespace = typeNamespace; + stringCache.insert(name, data); + identifierCache.insert(data->identifier.identifier, data); + typeNamespace->addref(); +} + +QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QString &id) const +{ + return stringCache.value(id); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativetypenamecache_p.h b/src/declarative/qml/qdeclarativetypenamecache_p.h new file mode 100644 index 00000000..f86629bb --- /dev/null +++ b/src/declarative/qml/qdeclarativetypenamecache_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVETYPENAMECACHE_P_H +#define QDECLARATIVETYPENAMECACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdeclarativerefcount_p.h" +#include "private/qdeclarativecleanup_p.h" + +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeType; +class QDeclarativeEngine; +class QDeclarativeTypeNameCache : public QDeclarativeRefCount, public QDeclarativeCleanup +{ +public: + QDeclarativeTypeNameCache(QDeclarativeEngine *); + virtual ~QDeclarativeTypeNameCache(); + + struct Data { + inline Data(); + inline ~Data(); + QDeclarativeType *type; + QDeclarativeTypeNameCache *typeNamespace; + int importedScriptIndex; + }; + + void add(const QString &, int); + void add(const QString &, QDeclarativeType *); + void add(const QString &, QDeclarativeTypeNameCache *); + + Data *data(const QString &) const; + inline Data *data(const QScriptDeclarativeClass::Identifier &id) const; + +protected: + virtual void clear(); + +private: + struct RData : public Data { + QScriptDeclarativeClass::PersistentIdentifier identifier; + }; + typedef QHash<QString, RData *> StringCache; + typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache; + + StringCache stringCache; + IdentifierCache identifierCache; + QDeclarativeEngine *engine; +}; + +QDeclarativeTypeNameCache::Data::Data() +: type(0), typeNamespace(0), importedScriptIndex(-1) +{ +} + +QDeclarativeTypeNameCache::Data::~Data() +{ + if (typeNamespace) typeNamespace->release(); +} + +QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QScriptDeclarativeClass::Identifier &id) const +{ + return identifierCache.value(id); +} + +QT_END_NAMESPACE + +#endif // QDECLARATIVETYPENAMECACHE_P_H + diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp new file mode 100644 index 00000000..585f12d6 --- /dev/null +++ b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativetypenamescriptclass_p.h" + +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativetypenamecache_p.h" + +QT_BEGIN_NAMESPACE + +struct TypeNameData : public QScriptDeclarativeClass::Object { + TypeNameData(QObject *o, QDeclarativeType *t, QDeclarativeTypeNameScriptClass::TypeNameMode m) : object(o), type(t), typeNamespace(0), mode(m) {} + TypeNameData(QObject *o, QDeclarativeTypeNameCache *n, QDeclarativeTypeNameScriptClass::TypeNameMode m) : object(o), type(0), typeNamespace(n), mode(m) { + if (typeNamespace) typeNamespace->addref(); + } + ~TypeNameData() { + if (typeNamespace) typeNamespace->release(); + } + + QObject *object; + QDeclarativeType *type; + QDeclarativeTypeNameCache *typeNamespace; + QDeclarativeTypeNameScriptClass::TypeNameMode mode; +}; + +QDeclarativeTypeNameScriptClass::QDeclarativeTypeNameScriptClass(QDeclarativeEngine *bindEngine) +: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), + engine(bindEngine), object(0), type(0) +{ +} + +QDeclarativeTypeNameScriptClass::~QDeclarativeTypeNameScriptClass() +{ +} + +QScriptValue QDeclarativeTypeNameScriptClass::newObject(QObject *object, QDeclarativeType *type, TypeNameMode mode) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, type, mode)); +} + +QScriptValue QDeclarativeTypeNameScriptClass::newObject(QObject *object, QDeclarativeTypeNameCache *ns, TypeNameMode mode) +{ + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + + return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, ns, mode)); +} + +QScriptClass::QueryFlags +QDeclarativeTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + + TypeNameData *data = (TypeNameData *)obj; + + object = 0; + type = 0; + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + + if (data->typeNamespace) { + + QDeclarativeTypeNameCache::Data *d = data->typeNamespace->data(name); + if (d && d->type) { + type = d->type; + return QScriptClass::HandlesReadAccess; + } else { + return 0; + } + + } else if (data->type) { + + if (startsWithUpper(name)) { + QString strName = toString(name); + // Must be an enum + if (data->mode == IncludeEnums) { + // ### Optimize + QByteArray enumName = strName.toUtf8(); + const QMetaObject *metaObject = data->type->baseMetaObject(); + for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { + QMetaEnum e = metaObject->enumerator(ii); + int value = e.keyToValue(enumName.constData()); + if (value != -1) { + enumValue = value; + return QScriptClass::HandlesReadAccess; + } + } + } + return 0; + } else if (data->object) { + // Must be an attached property + object = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), data->object); + if (!object) return 0; + return ep->objectClass->queryProperty(object, name, flags, 0); + } + + } + + return 0; +} + +QDeclarativeTypeNameScriptClass::Value +QDeclarativeTypeNameScriptClass::property(Object *obj, const Identifier &name) +{ + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + if (type) { + return Value(scriptEngine, newObject(((TypeNameData *)obj)->object, type, ((TypeNameData *)obj)->mode)); + } else if (object) { + return ep->objectClass->property(object, name); + } else { + return Value(scriptEngine, enumValue); + } +} + +void QDeclarativeTypeNameScriptClass::setProperty(Object *, const Identifier &n, const QScriptValue &v) +{ + Q_ASSERT(object); + Q_ASSERT(!type); + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + ep->objectClass->setProperty(object, n, v, context()); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass_p.h b/src/declarative/qml/qdeclarativetypenamescriptclass_p.h new file mode 100644 index 00000000..292e8934 --- /dev/null +++ b/src/declarative/qml/qdeclarativetypenamescriptclass_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVETYPENAMESCRIPTCLASS_P_H +#define QDECLARATIVETYPENAMESCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// +#include "private/qdeclarativeengine_p.h" + +#include <private/qscriptdeclarativeclass_p.h> +#include <QtScript/qscriptclass.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeEngine; +class QDeclarativeType; +class QDeclarativeTypeNameCache; +class QDeclarativeTypeNameScriptClass : public QScriptDeclarativeClass +{ +public: + QDeclarativeTypeNameScriptClass(QDeclarativeEngine *); + ~QDeclarativeTypeNameScriptClass(); + + enum TypeNameMode { IncludeEnums, ExcludeEnums }; + QScriptValue newObject(QObject *, QDeclarativeType *, TypeNameMode = IncludeEnums); + QScriptValue newObject(QObject *, QDeclarativeTypeNameCache *, TypeNameMode = IncludeEnums); + +protected: + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + + virtual Value property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); + +private: + QDeclarativeEngine *engine; + QObject *object; + QDeclarativeType *type; + quint32 enumValue; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVETYPENAMESCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qdeclarativetypenotavailable.cpp b/src/declarative/qml/qdeclarativetypenotavailable.cpp new file mode 100644 index 00000000..20be6d4d --- /dev/null +++ b/src/declarative/qml/qdeclarativetypenotavailable.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativetypenotavailable_p.h" + +QT_BEGIN_NAMESPACE + +int qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message) +{ + return qmlRegisterUncreatableType<QDeclarativeTypeNotAvailable>(uri,versionMajor,versionMinor,qmlName,message); +} + +QDeclarativeTypeNotAvailable::QDeclarativeTypeNotAvailable() { } + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativetypenotavailable_p.h b/src/declarative/qml/qdeclarativetypenotavailable_p.h new file mode 100644 index 00000000..7adce6c9 --- /dev/null +++ b/src/declarative/qml/qdeclarativetypenotavailable_p.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVETYPENOTAVAILABLE_H +#define QDECLARATIVETYPENOTAVAILABLE_H + +#include <qdeclarative.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeTypeNotAvailable : public QObject { + Q_OBJECT +public: + QDeclarativeTypeNotAvailable(); +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeTypeNotAvailable) + +QT_END_HEADER + +#endif // QDECLARATIVETYPENOTAVAILABLE_H diff --git a/src/declarative/qml/qdeclarativevaluetype.cpp b/src/declarative/qml/qdeclarativevaluetype.cpp new file mode 100644 index 00000000..850928e3 --- /dev/null +++ b/src/declarative/qml/qdeclarativevaluetype.cpp @@ -0,0 +1,1011 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativevaluetype_p.h" + +#include "private/qdeclarativemetatype_p.h" +#include "private/qfont_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +template<typename T> +int qmlRegisterValueTypeEnums(const char *uri, int versionMajor, int versionMinor, const char *qmlName) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + + QDeclarativePrivate::RegisterType type = { + 0, + + qRegisterMetaType<T *>(pointerName.constData()), 0, 0, 0, + + QString(), + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + 0, 0, + + 0, 0, 0, + + 0, 0, + + 0, + 0 + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); +} + +QDeclarativeValueTypeFactory::QDeclarativeValueTypeFactory() +{ + // ### Optimize + for (unsigned int ii = 0; ii < (QVariant::UserType - 1); ++ii) + valueTypes[ii] = valueType(ii); +} + +QDeclarativeValueTypeFactory::~QDeclarativeValueTypeFactory() +{ + for (unsigned int ii = 0; ii < (QVariant::UserType - 1); ++ii) + delete valueTypes[ii]; +} + +bool QDeclarativeValueTypeFactory::isValueType(int idx) +{ + if ((uint)idx < QVariant::UserType) + return true; + return false; +} + +void QDeclarativeValueTypeFactory::registerValueTypes() +{ + qmlRegisterValueTypeEnums<QDeclarativeEasingValueType>("QtQuick",1,0,"Easing"); + qmlRegisterValueTypeEnums<QDeclarativeFontValueType>("QtQuick",1,0,"Font"); +#ifndef QT_NO_IMPORT_QT47_QML + qmlRegisterValueTypeEnums<QDeclarativeEasingValueType>("Qt",4,7,"Easing"); + qmlRegisterValueTypeEnums<QDeclarativeFontValueType>("Qt",4,7,"Font"); +#endif +} + +QDeclarativeValueType *QDeclarativeValueTypeFactory::valueType(int t) +{ + QDeclarativeValueType *rv = 0; + + switch (t) { + case QVariant::Point: + rv = new QDeclarativePointValueType; + break; + case QVariant::PointF: + rv = new QDeclarativePointFValueType; + break; + case QVariant::Size: + rv = new QDeclarativeSizeValueType; + break; + case QVariant::SizeF: + rv = new QDeclarativeSizeFValueType; + break; + case QVariant::Rect: + rv = new QDeclarativeRectValueType; + break; + case QVariant::RectF: + rv = new QDeclarativeRectFValueType; + break; + case QVariant::Vector2D: + rv = new QDeclarativeVector2DValueType; + break; + case QVariant::Vector3D: + rv = new QDeclarativeVector3DValueType; + break; + case QVariant::Vector4D: + rv = new QDeclarativeVector4DValueType; + break; + case QVariant::Quaternion: + rv = new QDeclarativeQuaternionValueType; + break; + case QVariant::Matrix4x4: + rv = new QDeclarativeMatrix4x4ValueType; + break; + case QVariant::EasingCurve: + rv = new QDeclarativeEasingValueType; + break; + case QVariant::Font: + rv = new QDeclarativeFontValueType; + break; + default: + break; + } + + Q_ASSERT(!rv || rv->metaObject()->propertyCount() < 32); + return rv; +} + +QDeclarativeValueType::QDeclarativeValueType(QObject *parent) +: QObject(parent) +{ +} + +QDeclarativePointFValueType::QDeclarativePointFValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativePointFValueType::read(QObject *obj, int idx) +{ + void *a[] = { &point, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativePointFValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &point, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativePointFValueType::value() +{ + return QVariant(point); +} + +void QDeclarativePointFValueType::setValue(QVariant value) +{ + point = qvariant_cast<QPointF>(value); +} + +qreal QDeclarativePointFValueType::x() const +{ + return point.x(); +} + +qreal QDeclarativePointFValueType::y() const +{ + return point.y(); +} + +void QDeclarativePointFValueType::setX(qreal x) +{ + point.setX(x); +} + +void QDeclarativePointFValueType::setY(qreal y) +{ + point.setY(y); +} + +QDeclarativePointValueType::QDeclarativePointValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativePointValueType::read(QObject *obj, int idx) +{ + void *a[] = { &point, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativePointValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &point, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativePointValueType::value() +{ + return QVariant(point); +} + +void QDeclarativePointValueType::setValue(QVariant value) +{ + point = qvariant_cast<QPoint>(value); +} + +int QDeclarativePointValueType::x() const +{ + return point.x(); +} + +int QDeclarativePointValueType::y() const +{ + return point.y(); +} + +void QDeclarativePointValueType::setX(int x) +{ + point.setX(x); +} + +void QDeclarativePointValueType::setY(int y) +{ + point.setY(y); +} + +QDeclarativeSizeFValueType::QDeclarativeSizeFValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativeSizeFValueType::read(QObject *obj, int idx) +{ + void *a[] = { &size, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativeSizeFValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &size, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativeSizeFValueType::value() +{ + return QVariant(size); +} + +void QDeclarativeSizeFValueType::setValue(QVariant value) +{ + size = qvariant_cast<QSizeF>(value); +} + +qreal QDeclarativeSizeFValueType::width() const +{ + return size.width(); +} + +qreal QDeclarativeSizeFValueType::height() const +{ + return size.height(); +} + +void QDeclarativeSizeFValueType::setWidth(qreal w) +{ + size.setWidth(w); +} + +void QDeclarativeSizeFValueType::setHeight(qreal h) +{ + size.setHeight(h); +} + +QDeclarativeSizeValueType::QDeclarativeSizeValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativeSizeValueType::read(QObject *obj, int idx) +{ + void *a[] = { &size, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativeSizeValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &size, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativeSizeValueType::value() +{ + return QVariant(size); +} + +void QDeclarativeSizeValueType::setValue(QVariant value) +{ + size = qvariant_cast<QSize>(value); +} + +int QDeclarativeSizeValueType::width() const +{ + return size.width(); +} + +int QDeclarativeSizeValueType::height() const +{ + return size.height(); +} + +void QDeclarativeSizeValueType::setWidth(int w) +{ + size.setWidth(w); +} + +void QDeclarativeSizeValueType::setHeight(int h) +{ + size.setHeight(h); +} + +QDeclarativeRectFValueType::QDeclarativeRectFValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativeRectFValueType::read(QObject *obj, int idx) +{ + void *a[] = { &rect, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativeRectFValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &rect, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativeRectFValueType::value() +{ + return QVariant(rect); +} + +void QDeclarativeRectFValueType::setValue(QVariant value) +{ + rect = qvariant_cast<QRectF>(value); +} + +qreal QDeclarativeRectFValueType::x() const +{ + return rect.x(); +} + +qreal QDeclarativeRectFValueType::y() const +{ + return rect.y(); +} + +void QDeclarativeRectFValueType::setX(qreal x) +{ + rect.moveLeft(x); +} + +void QDeclarativeRectFValueType::setY(qreal y) +{ + rect.moveTop(y); +} + +qreal QDeclarativeRectFValueType::width() const +{ + return rect.width(); +} + +qreal QDeclarativeRectFValueType::height() const +{ + return rect.height(); +} + +void QDeclarativeRectFValueType::setWidth(qreal w) +{ + rect.setWidth(w); +} + +void QDeclarativeRectFValueType::setHeight(qreal h) +{ + rect.setHeight(h); +} + +QDeclarativeRectValueType::QDeclarativeRectValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativeRectValueType::read(QObject *obj, int idx) +{ + void *a[] = { &rect, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativeRectValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &rect, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativeRectValueType::value() +{ + return QVariant(rect); +} + +void QDeclarativeRectValueType::setValue(QVariant value) +{ + rect = qvariant_cast<QRect>(value); +} + +int QDeclarativeRectValueType::x() const +{ + return rect.x(); +} + +int QDeclarativeRectValueType::y() const +{ + return rect.y(); +} + +void QDeclarativeRectValueType::setX(int x) +{ + rect.moveLeft(x); +} + +void QDeclarativeRectValueType::setY(int y) +{ + rect.moveTop(y); +} + +int QDeclarativeRectValueType::width() const +{ + return rect.width(); +} + +int QDeclarativeRectValueType::height() const +{ + return rect.height(); +} + +void QDeclarativeRectValueType::setWidth(int w) +{ + rect.setWidth(w); +} + +void QDeclarativeRectValueType::setHeight(int h) +{ + rect.setHeight(h); +} + +QDeclarativeVector2DValueType::QDeclarativeVector2DValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativeVector2DValueType::read(QObject *obj, int idx) +{ + void *a[] = { &vector, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativeVector2DValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &vector, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativeVector2DValueType::value() +{ + return QVariant(vector); +} + +void QDeclarativeVector2DValueType::setValue(QVariant value) +{ + vector = qvariant_cast<QVector2D>(value); +} + +qreal QDeclarativeVector2DValueType::x() const +{ + return vector.x(); +} + +qreal QDeclarativeVector2DValueType::y() const +{ + return vector.y(); +} + +void QDeclarativeVector2DValueType::setX(qreal x) +{ + vector.setX(x); +} + +void QDeclarativeVector2DValueType::setY(qreal y) +{ + vector.setY(y); +} + +QDeclarativeVector3DValueType::QDeclarativeVector3DValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativeVector3DValueType::read(QObject *obj, int idx) +{ + void *a[] = { &vector, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativeVector3DValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &vector, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativeVector3DValueType::value() +{ + return QVariant(vector); +} + +void QDeclarativeVector3DValueType::setValue(QVariant value) +{ + vector = qvariant_cast<QVector3D>(value); +} + +qreal QDeclarativeVector3DValueType::x() const +{ + return vector.x(); +} + +qreal QDeclarativeVector3DValueType::y() const +{ + return vector.y(); +} + +qreal QDeclarativeVector3DValueType::z() const +{ + return vector.z(); +} + +void QDeclarativeVector3DValueType::setX(qreal x) +{ + vector.setX(x); +} + +void QDeclarativeVector3DValueType::setY(qreal y) +{ + vector.setY(y); +} + +void QDeclarativeVector3DValueType::setZ(qreal z) +{ + vector.setZ(z); +} + +QDeclarativeVector4DValueType::QDeclarativeVector4DValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativeVector4DValueType::read(QObject *obj, int idx) +{ + void *a[] = { &vector, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativeVector4DValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &vector, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativeVector4DValueType::value() +{ + return QVariant(vector); +} + +void QDeclarativeVector4DValueType::setValue(QVariant value) +{ + vector = qvariant_cast<QVector4D>(value); +} + +qreal QDeclarativeVector4DValueType::x() const +{ + return vector.x(); +} + +qreal QDeclarativeVector4DValueType::y() const +{ + return vector.y(); +} + +qreal QDeclarativeVector4DValueType::z() const +{ + return vector.z(); +} + +qreal QDeclarativeVector4DValueType::w() const +{ + return vector.w(); +} + +void QDeclarativeVector4DValueType::setX(qreal x) +{ + vector.setX(x); +} + +void QDeclarativeVector4DValueType::setY(qreal y) +{ + vector.setY(y); +} + +void QDeclarativeVector4DValueType::setZ(qreal z) +{ + vector.setZ(z); +} + +void QDeclarativeVector4DValueType::setW(qreal w) +{ + vector.setW(w); +} + +QDeclarativeQuaternionValueType::QDeclarativeQuaternionValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativeQuaternionValueType::read(QObject *obj, int idx) +{ + void *a[] = { &quaternion, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativeQuaternionValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &quaternion, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativeQuaternionValueType::value() +{ + return QVariant(quaternion); +} + +void QDeclarativeQuaternionValueType::setValue(QVariant value) +{ + quaternion = qvariant_cast<QQuaternion>(value); +} + +qreal QDeclarativeQuaternionValueType::scalar() const +{ + return quaternion.scalar(); +} + +qreal QDeclarativeQuaternionValueType::x() const +{ + return quaternion.x(); +} + +qreal QDeclarativeQuaternionValueType::y() const +{ + return quaternion.y(); +} + +qreal QDeclarativeQuaternionValueType::z() const +{ + return quaternion.z(); +} + +void QDeclarativeQuaternionValueType::setScalar(qreal scalar) +{ + quaternion.setScalar(scalar); +} + +void QDeclarativeQuaternionValueType::setX(qreal x) +{ + quaternion.setX(x); +} + +void QDeclarativeQuaternionValueType::setY(qreal y) +{ + quaternion.setY(y); +} + +void QDeclarativeQuaternionValueType::setZ(qreal z) +{ + quaternion.setZ(z); +} + +QDeclarativeMatrix4x4ValueType::QDeclarativeMatrix4x4ValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativeMatrix4x4ValueType::read(QObject *obj, int idx) +{ + void *a[] = { &matrix, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativeMatrix4x4ValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &matrix, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativeMatrix4x4ValueType::value() +{ + return QVariant(matrix); +} + +void QDeclarativeMatrix4x4ValueType::setValue(QVariant value) +{ + matrix = qvariant_cast<QMatrix4x4>(value); +} + +QDeclarativeEasingValueType::QDeclarativeEasingValueType(QObject *parent) +: QDeclarativeValueType(parent) +{ +} + +void QDeclarativeEasingValueType::read(QObject *obj, int idx) +{ + void *a[] = { &easing, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); +} + +void QDeclarativeEasingValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &easing, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativeEasingValueType::value() +{ + return QVariant(easing); +} + +void QDeclarativeEasingValueType::setValue(QVariant value) +{ + easing = qvariant_cast<QEasingCurve>(value); +} + +QDeclarativeEasingValueType::Type QDeclarativeEasingValueType::type() const +{ + return (QDeclarativeEasingValueType::Type)easing.type(); +} + +qreal QDeclarativeEasingValueType::amplitude() const +{ + return easing.amplitude(); +} + +qreal QDeclarativeEasingValueType::overshoot() const +{ + return easing.overshoot(); +} + +qreal QDeclarativeEasingValueType::period() const +{ + return easing.period(); +} + +void QDeclarativeEasingValueType::setType(QDeclarativeEasingValueType::Type type) +{ + easing.setType((QEasingCurve::Type)type); +} + +void QDeclarativeEasingValueType::setAmplitude(qreal amplitude) +{ + easing.setAmplitude(amplitude); +} + +void QDeclarativeEasingValueType::setOvershoot(qreal overshoot) +{ + easing.setOvershoot(overshoot); +} + +void QDeclarativeEasingValueType::setPeriod(qreal period) +{ + easing.setPeriod(period); +} + +QDeclarativeFontValueType::QDeclarativeFontValueType(QObject *parent) +: QDeclarativeValueType(parent), pixelSizeSet(false), pointSizeSet(false) +{ +} + +void QDeclarativeFontValueType::read(QObject *obj, int idx) +{ + void *a[] = { &font, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); + pixelSizeSet = false; + pointSizeSet = false; +} + +void QDeclarativeFontValueType::write(QObject *obj, int idx, QDeclarativePropertyPrivate::WriteFlags flags) +{ + int status = -1; + void *a[] = { &font, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); +} + +QVariant QDeclarativeFontValueType::value() +{ + return QVariant(font); +} + +void QDeclarativeFontValueType::setValue(QVariant value) +{ + font = qvariant_cast<QFont>(value); +} + + +QString QDeclarativeFontValueType::family() const +{ + return font.family(); +} + +void QDeclarativeFontValueType::setFamily(const QString &family) +{ + font.setFamily(family); +} + +bool QDeclarativeFontValueType::bold() const +{ + return font.bold(); +} + +void QDeclarativeFontValueType::setBold(bool b) +{ + font.setBold(b); +} + +QDeclarativeFontValueType::FontWeight QDeclarativeFontValueType::weight() const +{ + return (QDeclarativeFontValueType::FontWeight)font.weight(); +} + +void QDeclarativeFontValueType::setWeight(QDeclarativeFontValueType::FontWeight w) +{ + font.setWeight((QFont::Weight)w); +} + +bool QDeclarativeFontValueType::italic() const +{ + return font.italic(); +} + +void QDeclarativeFontValueType::setItalic(bool b) +{ + font.setItalic(b); +} + +bool QDeclarativeFontValueType::underline() const +{ + return font.underline(); +} + +void QDeclarativeFontValueType::setUnderline(bool b) +{ + font.setUnderline(b); +} + +bool QDeclarativeFontValueType::overline() const +{ + return font.overline(); +} + +void QDeclarativeFontValueType::setOverline(bool b) +{ + font.setOverline(b); +} + +bool QDeclarativeFontValueType::strikeout() const +{ + return font.strikeOut(); +} + +void QDeclarativeFontValueType::setStrikeout(bool b) +{ + font.setStrikeOut(b); +} + +qreal QDeclarativeFontValueType::pointSize() const +{ + if (font.pointSizeF() == -1) { + if (dpi.isNull) + dpi = qt_defaultDpi(); + return font.pixelSize() * qreal(72.) / qreal(dpi); + } + return font.pointSizeF(); +} + +void QDeclarativeFontValueType::setPointSize(qreal size) +{ + if (pixelSizeSet) { + qWarning() << "Both point size and pixel size set. Using pixel size."; + return; + } + + if (size >= 0.0) { + pointSizeSet = true; + font.setPointSizeF(size); + } else { + pointSizeSet = false; + } +} + +int QDeclarativeFontValueType::pixelSize() const +{ + if (font.pixelSize() == -1) { + if (dpi.isNull) + dpi = qt_defaultDpi(); + return (font.pointSizeF() * dpi) / qreal(72.); + } + return font.pixelSize(); +} + +void QDeclarativeFontValueType::setPixelSize(int size) +{ + if (size >0) { + if (pointSizeSet) + qWarning() << "Both point size and pixel size set. Using pixel size."; + font.setPixelSize(size); + pixelSizeSet = true; + } else { + pixelSizeSet = false; + } +} + +QDeclarativeFontValueType::Capitalization QDeclarativeFontValueType::capitalization() const +{ + return (QDeclarativeFontValueType::Capitalization)font.capitalization(); +} + +void QDeclarativeFontValueType::setCapitalization(QDeclarativeFontValueType::Capitalization c) +{ + font.setCapitalization((QFont::Capitalization)c); +} + +qreal QDeclarativeFontValueType::letterSpacing() const +{ + return font.letterSpacing(); +} + +void QDeclarativeFontValueType::setLetterSpacing(qreal size) +{ + font.setLetterSpacing(QFont::AbsoluteSpacing, size); +} + +qreal QDeclarativeFontValueType::wordSpacing() const +{ + return font.wordSpacing(); +} + +void QDeclarativeFontValueType::setWordSpacing(qreal size) +{ + font.setWordSpacing(size); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativevaluetype_p.h b/src/declarative/qml/qdeclarativevaluetype_p.h new file mode 100644 index 00000000..5c2cda7f --- /dev/null +++ b/src/declarative/qml/qdeclarativevaluetype_p.h @@ -0,0 +1,556 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEVALUETYPE_P_H +#define QDECLARATIVEVALUETYPE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativeproperty.h" +#include "private/qdeclarativeproperty_p.h" +#include "private/qdeclarativenullablevalue_p_p.h" + +#include <QtCore/qobject.h> +#include <QtCore/qrect.h> +#include <QtCore/qeasingcurve.h> +#include <QtCore/qvariant.h> +#include <QtGui/qvector2d.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qvector4d.h> +#include <QtGui/qmatrix4x4.h> +#include <QtGui/qquaternion.h> +#include <QtGui/qfont.h> + +QT_BEGIN_NAMESPACE + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeValueType : public QObject +{ + Q_OBJECT +public: + QDeclarativeValueType(QObject *parent = 0); + virtual void read(QObject *, int) = 0; + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags flags) = 0; + virtual QVariant value() = 0; + virtual void setValue(QVariant) = 0; +}; + +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeValueTypeFactory +{ +public: + QDeclarativeValueTypeFactory(); + ~QDeclarativeValueTypeFactory(); + static bool isValueType(int); + static QDeclarativeValueType *valueType(int); + + static void registerValueTypes(); + + QDeclarativeValueType *operator[](int idx) const { + if (idx >= (int)QVariant::UserType) return 0; + else return valueTypes[idx]; + } + +private: + QDeclarativeValueType *valueTypes[QVariant::UserType - 1]; +}; + +class Q_AUTOTEST_EXPORT QDeclarativePointFValueType : public QDeclarativeValueType +{ + Q_PROPERTY(qreal x READ x WRITE setX) + Q_PROPERTY(qreal y READ y WRITE setY) + Q_OBJECT +public: + QDeclarativePointFValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal x() const; + qreal y() const; + void setX(qreal); + void setY(qreal); + +private: + QPointF point; +}; + +class Q_AUTOTEST_EXPORT QDeclarativePointValueType : public QDeclarativeValueType +{ + Q_PROPERTY(int x READ x WRITE setX) + Q_PROPERTY(int y READ y WRITE setY) + Q_OBJECT +public: + QDeclarativePointValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + int x() const; + int y() const; + void setX(int); + void setY(int); + +private: + QPoint point; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeSizeFValueType : public QDeclarativeValueType +{ + Q_PROPERTY(qreal width READ width WRITE setWidth) + Q_PROPERTY(qreal height READ height WRITE setHeight) + Q_OBJECT +public: + QDeclarativeSizeFValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal width() const; + qreal height() const; + void setWidth(qreal); + void setHeight(qreal); + +private: + QSizeF size; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeSizeValueType : public QDeclarativeValueType +{ + Q_PROPERTY(int width READ width WRITE setWidth) + Q_PROPERTY(int height READ height WRITE setHeight) + Q_OBJECT +public: + QDeclarativeSizeValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + int width() const; + int height() const; + void setWidth(int); + void setHeight(int); + +private: + QSize size; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeRectFValueType : public QDeclarativeValueType +{ + Q_PROPERTY(qreal x READ x WRITE setX) + Q_PROPERTY(qreal y READ y WRITE setY) + Q_PROPERTY(qreal width READ width WRITE setWidth) + Q_PROPERTY(qreal height READ height WRITE setHeight) + Q_OBJECT +public: + QDeclarativeRectFValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal x() const; + qreal y() const; + void setX(qreal); + void setY(qreal); + + qreal width() const; + qreal height() const; + void setWidth(qreal); + void setHeight(qreal); + +private: + QRectF rect; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeRectValueType : public QDeclarativeValueType +{ + Q_PROPERTY(int x READ x WRITE setX) + Q_PROPERTY(int y READ y WRITE setY) + Q_PROPERTY(int width READ width WRITE setWidth) + Q_PROPERTY(int height READ height WRITE setHeight) + Q_OBJECT +public: + QDeclarativeRectValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + int x() const; + int y() const; + void setX(int); + void setY(int); + + int width() const; + int height() const; + void setWidth(int); + void setHeight(int); + +private: + QRect rect; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeVector2DValueType : public QDeclarativeValueType +{ + Q_PROPERTY(qreal x READ x WRITE setX) + Q_PROPERTY(qreal y READ y WRITE setY) + Q_OBJECT +public: + QDeclarativeVector2DValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal x() const; + qreal y() const; + void setX(qreal); + void setY(qreal); + +private: + QVector2D vector; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeVector3DValueType : public QDeclarativeValueType +{ + Q_PROPERTY(qreal x READ x WRITE setX) + Q_PROPERTY(qreal y READ y WRITE setY) + Q_PROPERTY(qreal z READ z WRITE setZ) + Q_OBJECT +public: + QDeclarativeVector3DValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal x() const; + qreal y() const; + qreal z() const; + void setX(qreal); + void setY(qreal); + void setZ(qreal); + +private: + QVector3D vector; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeVector4DValueType : public QDeclarativeValueType +{ + Q_PROPERTY(qreal x READ x WRITE setX) + Q_PROPERTY(qreal y READ y WRITE setY) + Q_PROPERTY(qreal z READ z WRITE setZ) + Q_PROPERTY(qreal w READ w WRITE setW) + Q_OBJECT +public: + QDeclarativeVector4DValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal x() const; + qreal y() const; + qreal z() const; + qreal w() const; + void setX(qreal); + void setY(qreal); + void setZ(qreal); + void setW(qreal); + +private: + QVector4D vector; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeQuaternionValueType : public QDeclarativeValueType +{ + Q_PROPERTY(qreal scalar READ scalar WRITE setScalar) + Q_PROPERTY(qreal x READ x WRITE setX) + Q_PROPERTY(qreal y READ y WRITE setY) + Q_PROPERTY(qreal z READ z WRITE setZ) + Q_OBJECT +public: + QDeclarativeQuaternionValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal scalar() const; + qreal x() const; + qreal y() const; + qreal z() const; + void setScalar(qreal); + void setX(qreal); + void setY(qreal); + void setZ(qreal); + +private: + QQuaternion quaternion; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeMatrix4x4ValueType : public QDeclarativeValueType +{ + Q_PROPERTY(qreal m11 READ m11 WRITE setM11) + Q_PROPERTY(qreal m12 READ m12 WRITE setM12) + Q_PROPERTY(qreal m13 READ m13 WRITE setM13) + Q_PROPERTY(qreal m14 READ m14 WRITE setM14) + Q_PROPERTY(qreal m21 READ m21 WRITE setM21) + Q_PROPERTY(qreal m22 READ m22 WRITE setM22) + Q_PROPERTY(qreal m23 READ m23 WRITE setM23) + Q_PROPERTY(qreal m24 READ m24 WRITE setM24) + Q_PROPERTY(qreal m31 READ m31 WRITE setM31) + Q_PROPERTY(qreal m32 READ m32 WRITE setM32) + Q_PROPERTY(qreal m33 READ m33 WRITE setM33) + Q_PROPERTY(qreal m34 READ m34 WRITE setM34) + Q_PROPERTY(qreal m41 READ m41 WRITE setM41) + Q_PROPERTY(qreal m42 READ m42 WRITE setM42) + Q_PROPERTY(qreal m43 READ m43 WRITE setM43) + Q_PROPERTY(qreal m44 READ m44 WRITE setM44) + Q_OBJECT +public: + QDeclarativeMatrix4x4ValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + qreal m11() const { return matrix(0, 0); } + qreal m12() const { return matrix(0, 1); } + qreal m13() const { return matrix(0, 2); } + qreal m14() const { return matrix(0, 3); } + qreal m21() const { return matrix(1, 0); } + qreal m22() const { return matrix(1, 1); } + qreal m23() const { return matrix(1, 2); } + qreal m24() const { return matrix(1, 3); } + qreal m31() const { return matrix(2, 0); } + qreal m32() const { return matrix(2, 1); } + qreal m33() const { return matrix(2, 2); } + qreal m34() const { return matrix(2, 3); } + qreal m41() const { return matrix(3, 0); } + qreal m42() const { return matrix(3, 1); } + qreal m43() const { return matrix(3, 2); } + qreal m44() const { return matrix(3, 3); } + + void setM11(qreal value) { matrix(0, 0) = value; } + void setM12(qreal value) { matrix(0, 1) = value; } + void setM13(qreal value) { matrix(0, 2) = value; } + void setM14(qreal value) { matrix(0, 3) = value; } + void setM21(qreal value) { matrix(1, 0) = value; } + void setM22(qreal value) { matrix(1, 1) = value; } + void setM23(qreal value) { matrix(1, 2) = value; } + void setM24(qreal value) { matrix(1, 3) = value; } + void setM31(qreal value) { matrix(2, 0) = value; } + void setM32(qreal value) { matrix(2, 1) = value; } + void setM33(qreal value) { matrix(2, 2) = value; } + void setM34(qreal value) { matrix(2, 3) = value; } + void setM41(qreal value) { matrix(3, 0) = value; } + void setM42(qreal value) { matrix(3, 1) = value; } + void setM43(qreal value) { matrix(3, 2) = value; } + void setM44(qreal value) { matrix(3, 3) = value; } + +private: + QMatrix4x4 matrix; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeEasingValueType : public QDeclarativeValueType +{ + Q_OBJECT + Q_ENUMS(Type) + + Q_PROPERTY(QDeclarativeEasingValueType::Type type READ type WRITE setType) + Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude) + Q_PROPERTY(qreal overshoot READ overshoot WRITE setOvershoot) + Q_PROPERTY(qreal period READ period WRITE setPeriod) +public: + enum Type { + Linear = QEasingCurve::Linear, + InQuad = QEasingCurve::InQuad, OutQuad = QEasingCurve::OutQuad, + InOutQuad = QEasingCurve::InOutQuad, OutInQuad = QEasingCurve::OutInQuad, + InCubic = QEasingCurve::InCubic, OutCubic = QEasingCurve::OutCubic, + InOutCubic = QEasingCurve::InOutCubic, OutInCubic = QEasingCurve::OutInCubic, + InQuart = QEasingCurve::InQuart, OutQuart = QEasingCurve::OutQuart, + InOutQuart = QEasingCurve::InOutQuart, OutInQuart = QEasingCurve::OutInQuart, + InQuint = QEasingCurve::InQuint, OutQuint = QEasingCurve::OutQuint, + InOutQuint = QEasingCurve::InOutQuint, OutInQuint = QEasingCurve::OutInQuint, + InSine = QEasingCurve::InSine, OutSine = QEasingCurve::OutSine, + InOutSine = QEasingCurve::InOutSine, OutInSine = QEasingCurve::OutInSine, + InExpo = QEasingCurve::InExpo, OutExpo = QEasingCurve::OutExpo, + InOutExpo = QEasingCurve::InOutExpo, OutInExpo = QEasingCurve::OutInExpo, + InCirc = QEasingCurve::InCirc, OutCirc = QEasingCurve::OutCirc, + InOutCirc = QEasingCurve::InOutCirc, OutInCirc = QEasingCurve::OutInCirc, + InElastic = QEasingCurve::InElastic, OutElastic = QEasingCurve::OutElastic, + InOutElastic = QEasingCurve::InOutElastic, OutInElastic = QEasingCurve::OutInElastic, + InBack = QEasingCurve::InBack, OutBack = QEasingCurve::OutBack, + InOutBack = QEasingCurve::InOutBack, OutInBack = QEasingCurve::OutInBack, + InBounce = QEasingCurve::InBounce, OutBounce = QEasingCurve::OutBounce, + InOutBounce = QEasingCurve::InOutBounce, OutInBounce = QEasingCurve::OutInBounce, + InCurve = QEasingCurve::InCurve, OutCurve = QEasingCurve::OutCurve, + SineCurve = QEasingCurve::SineCurve, CosineCurve = QEasingCurve::CosineCurve + }; + + QDeclarativeEasingValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + Type type() const; + qreal amplitude() const; + qreal overshoot() const; + qreal period() const; + void setType(Type); + void setAmplitude(qreal); + void setOvershoot(qreal); + void setPeriod(qreal); + +private: + QEasingCurve easing; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeFontValueType : public QDeclarativeValueType +{ + Q_OBJECT + Q_ENUMS(FontWeight) + Q_ENUMS(Capitalization) + + Q_PROPERTY(QString family READ family WRITE setFamily) + Q_PROPERTY(bool bold READ bold WRITE setBold) + Q_PROPERTY(FontWeight weight READ weight WRITE setWeight) + Q_PROPERTY(bool italic READ italic WRITE setItalic) + Q_PROPERTY(bool underline READ underline WRITE setUnderline) + Q_PROPERTY(bool overline READ overline WRITE setOverline) + Q_PROPERTY(bool strikeout READ strikeout WRITE setStrikeout) + Q_PROPERTY(qreal pointSize READ pointSize WRITE setPointSize) + Q_PROPERTY(int pixelSize READ pixelSize WRITE setPixelSize) + Q_PROPERTY(Capitalization capitalization READ capitalization WRITE setCapitalization) + Q_PROPERTY(qreal letterSpacing READ letterSpacing WRITE setLetterSpacing) + Q_PROPERTY(qreal wordSpacing READ wordSpacing WRITE setWordSpacing) + +public: + enum FontWeight { Light = QFont::Light, + Normal = QFont::Normal, + DemiBold = QFont::DemiBold, + Bold = QFont::Bold, + Black = QFont::Black }; + enum Capitalization { MixedCase = QFont::MixedCase, + AllUppercase = QFont::AllUppercase, + AllLowercase = QFont::AllLowercase, + SmallCaps = QFont::SmallCaps, + Capitalize = QFont::Capitalize }; + + QDeclarativeFontValueType(QObject *parent = 0); + + virtual void read(QObject *, int); + virtual void write(QObject *, int, QDeclarativePropertyPrivate::WriteFlags); + virtual QVariant value(); + virtual void setValue(QVariant value); + + QString family() const; + void setFamily(const QString &); + + bool bold() const; + void setBold(bool b); + + FontWeight weight() const; + void setWeight(FontWeight); + + bool italic() const; + void setItalic(bool b); + + bool underline() const; + void setUnderline(bool b); + + bool overline() const; + void setOverline(bool b); + + bool strikeout() const; + void setStrikeout(bool b); + + qreal pointSize() const; + void setPointSize(qreal size); + + int pixelSize() const; + void setPixelSize(int size); + + Capitalization capitalization() const; + void setCapitalization(Capitalization); + + qreal letterSpacing() const; + void setLetterSpacing(qreal spacing); + + qreal wordSpacing() const; + void setWordSpacing(qreal spacing); + +private: + QFont font; + bool pixelSizeSet; + bool pointSizeSet; + mutable QDeclarativeNullableValue<int> dpi; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEVALUETYPE_P_H diff --git a/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp b/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp new file mode 100644 index 00000000..b1d4221d --- /dev/null +++ b/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativevaluetypescriptclass_p.h" + +#include "private/qdeclarativebinding_p.h" +#include "private/qdeclarativeproperty_p.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativeguard_p.h" + +#include <QtScript/qscriptcontextinfo.h> + +QT_BEGIN_NAMESPACE + +struct QDeclarativeValueTypeObject : public QScriptDeclarativeClass::Object { + enum Type { Reference, Copy }; + QDeclarativeValueTypeObject(Type t) : objectType(t) {} + Type objectType; + QDeclarativeValueType *type; +}; + +struct QDeclarativeValueTypeReference : public QDeclarativeValueTypeObject { + QDeclarativeValueTypeReference() : QDeclarativeValueTypeObject(Reference) {} + QDeclarativeGuard<QObject> object; + int property; +}; + +struct QDeclarativeValueTypeCopy : public QDeclarativeValueTypeObject { + QDeclarativeValueTypeCopy() : QDeclarativeValueTypeObject(Copy) {} + QVariant value; +}; + +QDeclarativeValueTypeScriptClass::QDeclarativeValueTypeScriptClass(QDeclarativeEngine *bindEngine) +: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine) +{ +} + +QDeclarativeValueTypeScriptClass::~QDeclarativeValueTypeScriptClass() +{ +} + +QScriptValue QDeclarativeValueTypeScriptClass::newObject(QObject *object, int coreIndex, QDeclarativeValueType *type) +{ + QDeclarativeValueTypeReference *ref = new QDeclarativeValueTypeReference; + ref->type = type; + ref->object = object; + ref->property = coreIndex; + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + return QScriptDeclarativeClass::newObject(scriptEngine, this, ref); +} + +QScriptValue QDeclarativeValueTypeScriptClass::newObject(const QVariant &v, QDeclarativeValueType *type) +{ + QDeclarativeValueTypeCopy *copy = new QDeclarativeValueTypeCopy; + copy->type = type; + copy->value = v; + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + return QScriptDeclarativeClass::newObject(scriptEngine, this, copy); +} + +QScriptClass::QueryFlags +QDeclarativeValueTypeScriptClass::queryProperty(Object *obj, const Identifier &name, + QScriptClass::QueryFlags) +{ + QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj); + + m_lastIndex = -1; + + QByteArray propName = toString(name).toUtf8(); + + m_lastIndex = o->type->metaObject()->indexOfProperty(propName.constData()); + if (m_lastIndex == -1) + return 0; + + QScriptClass::QueryFlags rv = 0; + + if (o->objectType == QDeclarativeValueTypeObject::Reference) { + QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(o); + + if (!ref->object) + return 0; + + QMetaProperty prop = ref->object->metaObject()->property(m_lastIndex); + + rv = QScriptClass::HandlesReadAccess; + if (prop.isWritable()) + rv |= QScriptClass::HandlesWriteAccess; + } else { + rv = QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; + } + + return rv; +} + +QDeclarativeValueTypeScriptClass::Value QDeclarativeValueTypeScriptClass::property(Object *obj, const Identifier &) +{ + QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj); + + QVariant rv; + if (o->objectType == QDeclarativeValueTypeObject::Reference) { + QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj); + + QMetaProperty p = ref->type->metaObject()->property(m_lastIndex); + ref->type->read(ref->object, ref->property); + rv = p.read(ref->type); + } else { + QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj); + + QMetaProperty p = copy->type->metaObject()->property(m_lastIndex); + copy->type->setValue(copy->value); + rv = p.read(copy->type); + } + + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + return Value(scriptEngine, static_cast<QDeclarativeEnginePrivate *>(QObjectPrivate::get(engine))->scriptValueFromVariant(rv)); +} + +void QDeclarativeValueTypeScriptClass::setProperty(Object *obj, const Identifier &, + const QScriptValue &value) +{ + QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj); + + QVariant v = QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value); + + if (o->objectType == QDeclarativeValueTypeObject::Reference) { + QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj); + + ref->type->read(ref->object, ref->property); + QMetaProperty p = ref->type->metaObject()->property(m_lastIndex); + + QDeclarativeBinding *newBinding = 0; + if (value.isFunction() && !value.isRegExp()) { + QDeclarativeContextData *ctxt = QDeclarativeEnginePrivate::get(engine)->getContext(context()); + + QDeclarativePropertyCache::Data cacheData; + cacheData.flags = QDeclarativePropertyCache::Data::IsWritable; + cacheData.propType = ref->object->metaObject()->property(ref->property).userType(); + cacheData.coreIndex = ref->property; + + QDeclarativePropertyCache::ValueTypeData valueTypeData; + valueTypeData.valueTypeCoreIdx = m_lastIndex; + valueTypeData.valueTypePropType = p.userType(); + + newBinding = new QDeclarativeBinding(value, ref->object, ctxt); + QScriptContextInfo ctxtInfo(context()); + newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber()); + QDeclarativeProperty prop = QDeclarativePropertyPrivate::restore(cacheData, valueTypeData, ref->object, ctxt); + newBinding->setTarget(prop); + if (newBinding->expression().contains(QLatin1String("this"))) + newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject); + } + + QDeclarativeAbstractBinding *delBinding = + QDeclarativePropertyPrivate::setBinding(ref->object, ref->property, m_lastIndex, newBinding); + if (delBinding) + delBinding->destroy(); + + if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double) + v = v.toInt(); + p.write(ref->type, v); + ref->type->write(ref->object, ref->property, 0); + + } else { + QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj); + copy->type->setValue(copy->value); + QMetaProperty p = copy->type->metaObject()->property(m_lastIndex); + p.write(copy->type, v); + copy->value = copy->type->value(); + } +} + +QVariant QDeclarativeValueTypeScriptClass::toVariant(Object *obj, bool *ok) +{ + QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj); + + if (o->objectType == QDeclarativeValueTypeObject::Reference) { + QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj); + + if (ok) *ok = true; + + if (ref->object) { + ref->type->read(ref->object, ref->property); + return ref->type->value(); + } + } else { + QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj); + + if (ok) *ok = true; + + return copy->value; + } + + return QVariant(); +} + +QVariant QDeclarativeValueTypeScriptClass::toVariant(const QScriptValue &value) +{ + Q_ASSERT(scriptClass(value) == this); + + return toVariant(object(value), 0); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativevaluetypescriptclass_p.h b/src/declarative/qml/qdeclarativevaluetypescriptclass_p.h new file mode 100644 index 00000000..781b7711 --- /dev/null +++ b/src/declarative/qml/qdeclarativevaluetypescriptclass_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEVALUETYPESCRIPTCLASS_P_H +#define QDECLARATIVEVALUETYPESCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include <private/qscriptdeclarativeclass_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeEngine; +class QDeclarativeValueType; +class QDeclarativeValueTypeScriptClass : public QScriptDeclarativeClass +{ +public: + QDeclarativeValueTypeScriptClass(QDeclarativeEngine *); + ~QDeclarativeValueTypeScriptClass(); + + QScriptValue newObject(QObject *object, int coreIndex, QDeclarativeValueType *); + QScriptValue newObject(const QVariant &, QDeclarativeValueType *); + + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, + QScriptClass::QueryFlags flags); + virtual Value property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); + + virtual QVariant toVariant(Object *, bool *ok = 0); + QVariant toVariant(const QScriptValue &); +private: + QDeclarativeEngine *engine; + int m_lastIndex; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEVALUETYPESCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp new file mode 100644 index 00000000..59c9d2bc --- /dev/null +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -0,0 +1,1124 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativevme_p.h" + +#include "private/qdeclarativecompiler_p.h" +#include "private/qdeclarativeboundsignal_p.h" +#include "private/qdeclarativestringconverters_p.h" +#include "private/qmetaobjectbuilder_p.h" +#include "private/qdeclarativedata_p.h" +#include "qdeclarative.h" +#include "private/qdeclarativecustomparser_p.h" +#include "qdeclarativeengine.h" +#include "qdeclarativecontext.h" +#include "qdeclarativecomponent.h" +#include "private/qdeclarativebinding_p.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativecomponent_p.h" +#include "private/qdeclarativevmemetaobject_p.h" +#include "private/qdeclarativebinding_p_p.h" +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativecompiledbindings_p.h" +#include "private/qdeclarativeglobal_p.h" +#include "qdeclarativescriptstring.h" + +#include <QStack> +#include <QWidget> +#include <QColor> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <QtCore/qdebug.h> +#include <QtCore/qvarlengtharray.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdatetime.h> + +QT_BEGIN_NAMESPACE + +// A simple stack wrapper around QVarLengthArray +template<typename T> +class QDeclarativeVMEStack : private QVarLengthArray<T, 128> +{ +private: + typedef QVarLengthArray<T, 128> VLA; + int _index; + +public: + inline QDeclarativeVMEStack(); + inline bool isEmpty() const; + inline const T &top() const; + inline void push(const T &o); + inline T pop(); + inline int count() const; + inline const T &at(int index) const; +}; + +// We do this so we can forward declare the type in the qdeclarativevme_p.h header +class QDeclarativeVMEObjectStack : public QDeclarativeVMEStack<QObject *> {}; + +QDeclarativeVME::QDeclarativeVME() +{ +} + +#define VME_EXCEPTION(desc) \ + { \ + QDeclarativeError error; \ + error.setDescription(desc.trimmed()); \ + error.setLine(instr.line); \ + error.setUrl(comp->url); \ + vmeErrors << error; \ + break; \ + } + +struct ListInstance +{ + ListInstance() + : type(0) {} + ListInstance(int t) + : type(t) {} + + int type; + QDeclarativeListProperty<void> qListProperty; +}; + +Q_DECLARE_TYPEINFO(ListInstance, Q_PRIMITIVE_TYPE | Q_MOVABLE_TYPE); + +QObject *QDeclarativeVME::run(QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp, + int start, int count, const QBitField &bindingSkipList) +{ + QDeclarativeVMEObjectStack stack; + + if (start == -1) start = 0; + if (count == -1) count = comp->bytecode.count(); + + return run(stack, ctxt, comp, start, count, bindingSkipList); +} + +void QDeclarativeVME::runDeferred(QObject *object) +{ + QDeclarativeData *data = QDeclarativeData::get(object); + + if (!data || !data->context || !data->deferredComponent) + return; + + QDeclarativeContextData *ctxt = data->context; + QDeclarativeCompiledData *comp = data->deferredComponent; + int start = data->deferredIdx + 1; + int count = data->deferredComponent->bytecode.at(data->deferredIdx).defer.deferCount; + QDeclarativeVMEObjectStack stack; + stack.push(object); + + run(stack, ctxt, comp, start, count, QBitField()); +} + +inline bool fastHasBinding(QObject *o, int index) +{ + QDeclarativeData *ddata = static_cast<QDeclarativeData *>(QObjectPrivate::get(o)->declarativeData); + + return ddata && (ddata->bindingBitsSize > index) && + (ddata->bindingBits[index / 32] & (1 << (index % 32))); +} + +static void removeBindingOnProperty(QObject *o, int index) +{ + QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::setBinding(o, index, -1, 0); + if (binding) binding->destroy(); +} + +#define CLEAN_PROPERTY(o, index) if (fastHasBinding(o, index)) removeBindingOnProperty(o, index) + +QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack, + QDeclarativeContextData *ctxt, + QDeclarativeCompiledData *comp, + int start, int count, + const QBitField &bindingSkipList) +{ + Q_ASSERT(comp); + Q_ASSERT(ctxt); + const QList<QDeclarativeCompiledData::TypeReference> &types = comp->types; + const QList<QString> &primitives = comp->primitives; + const QList<QByteArray> &datas = comp->datas; + const QList<QDeclarativeCompiledData::CustomTypeData> &customTypeData = comp->customTypeData; + const QList<int> &intData = comp->intData; + const QList<float> &floatData = comp->floatData; + const QList<QDeclarativePropertyCache *> &propertyCaches = comp->propertyCaches; + const QList<QDeclarativeParser::Object::ScriptBlock> &scripts = comp->scripts; + const QList<QUrl> &urls = comp->urls; + + QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bindValues; + QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> parserStatus; + + QDeclarativeVMEStack<ListInstance> qliststack; + + vmeErrors.clear(); + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine); + + int status = -1; //for dbus + QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::BypassInterceptor | + QDeclarativePropertyPrivate::RemoveBindingOnAliasWrite; + + for (int ii = start; !isError() && ii < (start + count); ++ii) { + const QDeclarativeInstruction &instr = comp->bytecode.at(ii); + + switch(instr.type) { + case QDeclarativeInstruction::Init: + { + if (instr.init.bindingsSize) + bindValues = QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding>(instr.init.bindingsSize); + if (instr.init.parserStatusSize) + parserStatus = QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus>(instr.init.parserStatusSize); + if (instr.init.contextCache != -1) + ctxt->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache)); + if (instr.init.compiledBinding != -1) + ctxt->optimizedBindings = new QDeclarativeCompiledBindings(datas.at(instr.init.compiledBinding).constData(), ctxt, comp); + } + break; + + case QDeclarativeInstruction::CreateObject: + { + QBitField bindings; + if (instr.create.bindingBits != -1) { + const QByteArray &bits = datas.at(instr.create.bindingBits); + bindings = QBitField((const quint32*)bits.constData(), + bits.size() * 8); + } + if (stack.isEmpty()) + bindings = bindings.united(bindingSkipList); + + QObject *o = + types.at(instr.create.type).createInstance(ctxt, bindings, &vmeErrors); + + if (!o) { + VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create object of type %1").arg(QString::fromLatin1(types.at(instr.create.type).className))); + } + + QDeclarativeData *ddata = QDeclarativeData::get(o); + Q_ASSERT(ddata); + + if (stack.isEmpty()) { + if (ddata->context) { + Q_ASSERT(ddata->context != ctxt); + Q_ASSERT(ddata->outerContext); + Q_ASSERT(ddata->outerContext != ctxt); + QDeclarativeContextData *c = ddata->context; + while (c->linkedContext) c = c->linkedContext; + c->linkedContext = ctxt; + } else { + ctxt->addObject(o); + } + + ddata->ownContext = true; + } else if (!ddata->context) { + ctxt->addObject(o); + } + + ddata->setImplicitDestructible(); + ddata->outerContext = ctxt; + ddata->lineNumber = instr.line; + ddata->columnNumber = instr.create.column; + + if (instr.create.data != -1) { + QDeclarativeCustomParser *customParser = + types.at(instr.create.type).type->customParser(); + customParser->setCustomData(o, datas.at(instr.create.data)); + } + if (!stack.isEmpty()) { + QObject *parent = stack.top(); + if (o->isWidgetType()) { + QWidget *widget = static_cast<QWidget*>(o); + if (parent->isWidgetType()) { + QWidget *parentWidget = static_cast<QWidget*>(parent); + widget->setParent(parentWidget); + } else { + // TODO: parent might be a layout + } + } else { + QDeclarative_setParent_noEvent(o, parent); + } + } + stack.push(o); + } + break; + + case QDeclarativeInstruction::CreateSimpleObject: + { + QObject *o = (QObject *)operator new(instr.createSimple.typeSize + + sizeof(QDeclarativeData)); + ::memset(o, 0, instr.createSimple.typeSize + sizeof(QDeclarativeData)); + instr.createSimple.create(o); + + QDeclarativeData *ddata = (QDeclarativeData *)(((const char *)o) + instr.createSimple.typeSize); + const QDeclarativeCompiledData::TypeReference &ref = types.at(instr.createSimple.type); + if (!ddata->propertyCache && ref.typePropertyCache) { + ddata->propertyCache = ref.typePropertyCache; + ddata->propertyCache->addref(); + } + ddata->lineNumber = instr.line; + ddata->columnNumber = instr.createSimple.column; + + QObjectPrivate::get(o)->declarativeData = ddata; + ddata->context = ddata->outerContext = ctxt; + ddata->nextContextObject = ctxt->contextObjects; + if (ddata->nextContextObject) + ddata->nextContextObject->prevContextObject = &ddata->nextContextObject; + ddata->prevContextObject = &ctxt->contextObjects; + ctxt->contextObjects = ddata; + + QObject *parent = stack.top(); + QDeclarative_setParent_noEvent(o, parent); + + stack.push(o); + } + break; + + case QDeclarativeInstruction::SetId: + { + QObject *target = stack.top(); + ctxt->setIdProperty(instr.setId.index, target); + } + break; + + + case QDeclarativeInstruction::SetDefault: + { + ctxt->contextObject = stack.top(); + } + break; + + case QDeclarativeInstruction::CreateComponent: + { + QDeclarativeComponent *qcomp = + new QDeclarativeComponent(ctxt->engine, comp, ii + 1, instr.createComponent.count, + stack.isEmpty() ? 0 : stack.top()); + + QDeclarativeData *ddata = QDeclarativeData::get(qcomp, true); + Q_ASSERT(ddata); + + ctxt->addObject(qcomp); + + if (stack.isEmpty()) + ddata->ownContext = true; + + ddata->setImplicitDestructible(); + ddata->outerContext = ctxt; + ddata->lineNumber = instr.line; + ddata->columnNumber = instr.create.column; + + QDeclarativeComponentPrivate::get(qcomp)->creationContext = ctxt; + + stack.push(qcomp); + ii += instr.createComponent.count; + } + break; + + case QDeclarativeInstruction::StoreMetaObject: + { + QObject *target = stack.top(); + + QMetaObject mo; + const QByteArray &metadata = datas.at(instr.storeMeta.data); + QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata); + + const QDeclarativeVMEMetaData *data = + (const QDeclarativeVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); + + (void)new QDeclarativeVMEMetaObject(target, &mo, data, comp); + + if (instr.storeMeta.propertyCache != -1) { + QDeclarativeData *ddata = QDeclarativeData::get(target, true); + if (ddata->propertyCache) ddata->propertyCache->release(); + ddata->propertyCache = propertyCaches.at(instr.storeMeta.propertyCache); + ddata->propertyCache->addref(); + } + } + break; + + case QDeclarativeInstruction::StoreVariant: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeString.propertyIndex); + + // XXX - can be more efficient + QVariant v = QDeclarativeStringConverters::variantFromString(primitives.at(instr.storeString.value)); + void *a[] = { &v, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeString.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreVariantInteger: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeString.propertyIndex); + + QVariant v(instr.storeInteger.value); + void *a[] = { &v, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeString.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreVariantDouble: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeString.propertyIndex); + + QVariant v(instr.storeDouble.value); + void *a[] = { &v, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeString.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreVariantBool: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeString.propertyIndex); + + QVariant v(instr.storeBool.value); + void *a[] = { &v, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeString.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreString: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeString.propertyIndex); + + void *a[] = { (void *)&primitives.at(instr.storeString.value), 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeString.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreUrl: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeUrl.propertyIndex); + + void *a[] = { (void *)&urls.at(instr.storeUrl.value), 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeUrl.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreFloat: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeFloat.propertyIndex); + + float f = instr.storeFloat.value; + void *a[] = { &f, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeFloat.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreDouble: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeDouble.propertyIndex); + + double d = instr.storeDouble.value; + void *a[] = { &d, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeDouble.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreBool: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeBool.propertyIndex); + + void *a[] = { (void *)&instr.storeBool.value, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeBool.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreInteger: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeInteger.propertyIndex); + + void *a[] = { (void *)&instr.storeInteger.value, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeInteger.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreColor: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeColor.propertyIndex); + + QColor c = QColor::fromRgba(instr.storeColor.value); + void *a[] = { &c, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeColor.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreDate: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeDate.propertyIndex); + + QDate d = QDate::fromJulianDay(instr.storeDate.value); + void *a[] = { &d, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeDate.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreTime: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeTime.propertyIndex); + + QTime t; + t.setHMS(intData.at(instr.storeTime.valueIndex), + intData.at(instr.storeTime.valueIndex+1), + intData.at(instr.storeTime.valueIndex+2), + intData.at(instr.storeTime.valueIndex+3)); + void *a[] = { &t, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeTime.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreDateTime: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeDateTime.propertyIndex); + + QTime t; + t.setHMS(intData.at(instr.storeDateTime.valueIndex+1), + intData.at(instr.storeDateTime.valueIndex+2), + intData.at(instr.storeDateTime.valueIndex+3), + intData.at(instr.storeDateTime.valueIndex+4)); + QDateTime dt(QDate::fromJulianDay(intData.at(instr.storeDateTime.valueIndex)), t); + void *a[] = { &dt, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeDateTime.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StorePoint: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); + + QPoint p = QPointF(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)).toPoint(); + void *a[] = { &p, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StorePointF: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); + + QPointF p(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)); + void *a[] = { &p, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreSize: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); + + QSize p = QSizeF(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)).toSize(); + void *a[] = { &p, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreSizeF: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); + + QSizeF s(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)); + void *a[] = { &s, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreRect: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRect.propertyIndex); + + QRect r = QRectF(floatData.at(instr.storeRect.valueIndex), + floatData.at(instr.storeRect.valueIndex+1), + floatData.at(instr.storeRect.valueIndex+2), + floatData.at(instr.storeRect.valueIndex+3)).toRect(); + void *a[] = { &r, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRect.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreRectF: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRect.propertyIndex); + + QRectF r(floatData.at(instr.storeRect.valueIndex), + floatData.at(instr.storeRect.valueIndex+1), + floatData.at(instr.storeRect.valueIndex+2), + floatData.at(instr.storeRect.valueIndex+3)); + void *a[] = { &r, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRect.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreVector3D: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeVector3D.propertyIndex); + + QVector3D p(floatData.at(instr.storeVector3D.valueIndex), + floatData.at(instr.storeVector3D.valueIndex+1), + floatData.at(instr.storeVector3D.valueIndex+2)); + void *a[] = { &p, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeVector3D.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreObject: + { + QObject *assignObj = stack.pop(); + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeObject.propertyIndex); + + void *a[] = { (void *)&assignObj, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeObject.propertyIndex, a); + } + break; + + + case QDeclarativeInstruction::AssignCustomType: + { + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.assignCustomType.propertyIndex); + + QDeclarativeCompiledData::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex); + const QString &primitive = primitives.at(data.index); + QDeclarativeMetaType::StringConverter converter = + QDeclarativeMetaType::customStringConverter(data.type); + QVariant v = (*converter)(primitive); + + QMetaProperty prop = + target->metaObject()->property(instr.assignCustomType.propertyIndex); + if (v.isNull() || ((int)prop.type() != data.type && prop.userType() != data.type)) + VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign value %1 to property %2").arg(primitive).arg(QString::fromUtf8(prop.name()))); + + void *a[] = { (void *)v.data(), 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.assignCustomType.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::AssignSignalObject: + { + // XXX optimize + + QObject *assign = stack.pop(); + QObject *target = stack.top(); + int sigIdx = instr.assignSignalObject.signal; + const QByteArray &pr = datas.at(sigIdx); + + QDeclarativeProperty prop(target, QString::fromUtf8(pr)); + if (prop.type() & QDeclarativeProperty::SignalProperty) { + + QMetaMethod method = QDeclarativeMetaType::defaultMethod(assign); + if (method.signature() == 0) + VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className()))); + + if (!QMetaObject::checkConnectArgs(prop.method().signature(), method.signature())) + VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot connect mismatched signal/slot %1 %vs. %2").arg(QString::fromLatin1(method.signature())).arg(QString::fromLatin1(prop.method().signature()))); + + QDeclarativePropertyPrivate::connect(target, prop.index(), assign, method.methodIndex()); + + } else { + VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign an object to signal property %1").arg(QString::fromUtf8(pr))); + } + + + } + break; + + case QDeclarativeInstruction::StoreSignal: + { + QObject *target = stack.top(); + QObject *context = stack.at(stack.count() - 1 - instr.storeSignal.context); + + QMetaMethod signal = target->metaObject()->method(instr.storeSignal.signalIndex); + + QDeclarativeBoundSignal *bs = new QDeclarativeBoundSignal(target, signal, target); + QDeclarativeExpression *expr = + new QDeclarativeExpression(ctxt, context, primitives.at(instr.storeSignal.value)); + expr->setSourceLocation(comp->name, instr.line); + static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr))->name = datas.at(instr.storeSignal.name); + bs->setExpression(expr); + } + break; + + case QDeclarativeInstruction::StoreImportedScript: + { + ctxt->addImportedScript(scripts.at(instr.storeScript.value)); + } + break; + + case QDeclarativeInstruction::StoreScriptString: + { + QObject *target = stack.top(); + QObject *scope = stack.at(stack.count() - 1 - instr.storeScriptString.scope); + QDeclarativeScriptString ss; + ss.setContext(ctxt->asQDeclarativeContext()); + ss.setScopeObject(scope); + ss.setScript(primitives.at(instr.storeScriptString.value)); + + void *a[] = { &ss, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeScriptString.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::BeginObject: + { + QObject *target = stack.top(); + QDeclarativeParserStatus *status = reinterpret_cast<QDeclarativeParserStatus *>(reinterpret_cast<char *>(target) + instr.begin.castValue); + parserStatus.append(status); + status->d = &parserStatus.values[parserStatus.count - 1]; + + status->classBegin(); + } + break; + + case QDeclarativeInstruction::StoreBinding: + case QDeclarativeInstruction::StoreBindingOnAlias: + { + QObject *target = + stack.at(stack.count() - 1 - instr.assignBinding.owner); + QObject *context = + stack.at(stack.count() - 1 - instr.assignBinding.context); + + QDeclarativeProperty mp = + QDeclarativePropertyPrivate::restore(datas.at(instr.assignBinding.property), target, ctxt); + + int coreIndex = mp.index(); + + if ((stack.count() - instr.assignBinding.owner) == 1 && bindingSkipList.testBit(coreIndex)) + break; + + QDeclarativeBinding *bind = new QDeclarativeBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, comp->name, instr.line, 0); + bindValues.append(bind); + bind->m_mePtr = &bindValues.values[bindValues.count - 1]; + bind->setTarget(mp); + + if (instr.type == QDeclarativeInstruction::StoreBindingOnAlias) { + QDeclarativeAbstractBinding *old = QDeclarativePropertyPrivate::setBindingNoEnable(target, coreIndex, QDeclarativePropertyPrivate::valueTypeCoreIndex(mp), bind); + if (old) { old->destroy(); } + } else { + bind->addToObject(target, QDeclarativePropertyPrivate::bindingIndex(mp)); + } + } + break; + + case QDeclarativeInstruction::StoreCompiledBinding: + { + QObject *target = + stack.at(stack.count() - 1 - instr.assignBinding.owner); + QObject *scope = + stack.at(stack.count() - 1 - instr.assignBinding.context); + + int property = instr.assignBinding.property; + if (stack.count() == 1 && bindingSkipList.testBit(property & 0xFFFF)) + break; + + QDeclarativeAbstractBinding *binding = + ctxt->optimizedBindings->configBinding(instr.assignBinding.value, target, scope, property); + bindValues.append(binding); + binding->m_mePtr = &bindValues.values[bindValues.count - 1]; + binding->addToObject(target, property); + } + break; + + case QDeclarativeInstruction::StoreValueSource: + { + QObject *obj = stack.pop(); + QDeclarativePropertyValueSource *vs = reinterpret_cast<QDeclarativePropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.assignValueSource.castValue); + QObject *target = stack.at(stack.count() - 1 - instr.assignValueSource.owner); + + QDeclarativeProperty prop = + QDeclarativePropertyPrivate::restore(datas.at(instr.assignValueSource.property), target, ctxt); + obj->setParent(target); + vs->setTarget(prop); + } + break; + + case QDeclarativeInstruction::StoreValueInterceptor: + { + QObject *obj = stack.pop(); + QDeclarativePropertyValueInterceptor *vi = reinterpret_cast<QDeclarativePropertyValueInterceptor *>(reinterpret_cast<char *>(obj) + instr.assignValueInterceptor.castValue); + QObject *target = stack.at(stack.count() - 1 - instr.assignValueInterceptor.owner); + QDeclarativeProperty prop = + QDeclarativePropertyPrivate::restore(datas.at(instr.assignValueInterceptor.property), target, ctxt); + obj->setParent(target); + vi->setTarget(prop); + QDeclarativeVMEMetaObject *mo = static_cast<QDeclarativeVMEMetaObject *>((QMetaObject*)target->metaObject()); + mo->registerInterceptor(prop.index(), QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), vi); + } + break; + + case QDeclarativeInstruction::StoreObjectQList: + { + QObject *assign = stack.pop(); + + const ListInstance &list = qliststack.top(); + list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, assign); + } + break; + + case QDeclarativeInstruction::AssignObjectList: + { + // This is only used for assigning interfaces + QObject *assign = stack.pop(); + const ListInstance &list = qliststack.top(); + + int type = list.type; + + void *ptr = 0; + + const char *iid = QDeclarativeMetaType::interfaceIId(type); + if (iid) + ptr = assign->qt_metacast(iid); + if (!ptr) + VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to list")); + + + list.qListProperty.append((QDeclarativeListProperty<void>*)&list.qListProperty, ptr); + } + break; + + case QDeclarativeInstruction::StoreVariantObject: + { + QObject *assign = stack.pop(); + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeObject.propertyIndex); + + QVariant v = QVariant::fromValue(assign); + void *a[] = { &v, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeObject.propertyIndex, a); + } + break; + + case QDeclarativeInstruction::StoreInterface: + { + QObject *assign = stack.pop(); + QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeObject.propertyIndex); + + int coreIdx = instr.storeObject.propertyIndex; + QMetaProperty prop = target->metaObject()->property(coreIdx); + int t = prop.userType(); + const char *iid = QDeclarativeMetaType::interfaceIId(t); + bool ok = false; + if (iid) { + void *ptr = assign->qt_metacast(iid); + if (ptr) { + void *a[] = { &ptr, 0, &status, &flags }; + QMetaObject::metacall(target, + QMetaObject::WriteProperty, + coreIdx, a); + ok = true; + } + } + + if (!ok) + VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot assign object to interface property")); + } + break; + + case QDeclarativeInstruction::FetchAttached: + { + QObject *target = stack.top(); + + QObject *qmlObject = qmlAttachedPropertiesObjectById(instr.fetchAttached.id, target); + + if (!qmlObject) + VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Unable to create attached object")); + + stack.push(qmlObject); + } + break; + + case QDeclarativeInstruction::FetchQList: + { + QObject *target = stack.top(); + + qliststack.push(ListInstance(instr.fetchQmlList.type)); + + void *a[1]; + a[0] = (void *)&(qliststack.top().qListProperty); + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetchQmlList.property, a); + } + break; + + case QDeclarativeInstruction::FetchObject: + { + QObject *target = stack.top(); + + QObject *obj = 0; + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + void *a[1]; + a[0] = &obj; + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetch.property, a); + + if (!obj) + VME_EXCEPTION(QCoreApplication::translate("QDeclarativeVME","Cannot set properties on %1 as it is null").arg(QString::fromUtf8(target->metaObject()->property(instr.fetch.property).name()))); + + stack.push(obj); + } + break; + + case QDeclarativeInstruction::PopQList: + { + qliststack.pop(); + } + break; + + case QDeclarativeInstruction::Defer: + { + if (instr.defer.deferCount) { + QObject *target = stack.top(); + QDeclarativeData *data = + QDeclarativeData::get(target, true); + comp->addref(); + data->deferredComponent = comp; + data->deferredIdx = ii; + ii += instr.defer.deferCount; + } + } + break; + + case QDeclarativeInstruction::PopFetchedObject: + { + stack.pop(); + } + break; + + case QDeclarativeInstruction::FetchValueType: + { + QObject *target = stack.top(); + + if (instr.fetchValue.bindingSkipList != 0) { + // Possibly need to clear bindings + QDeclarativeData *targetData = QDeclarativeData::get(target); + if (targetData) { + QDeclarativeAbstractBinding *binding = + QDeclarativePropertyPrivate::binding(target, instr.fetchValue.property, -1); + + if (binding && binding->bindingType() != QDeclarativeAbstractBinding::ValueTypeProxy) { + QDeclarativePropertyPrivate::setBinding(target, instr.fetchValue.property, -1, 0); + binding->destroy(); + } else if (binding) { + QDeclarativeValueTypeProxyBinding *proxy = + static_cast<QDeclarativeValueTypeProxyBinding *>(binding); + proxy->removeBindings(instr.fetchValue.bindingSkipList); + } + } + } + + QDeclarativeValueType *valueHandler = ep->valueTypes[instr.fetchValue.type]; + valueHandler->read(target, instr.fetchValue.property); + stack.push(valueHandler); + } + break; + + case QDeclarativeInstruction::PopValueType: + { + QDeclarativeValueType *valueHandler = + static_cast<QDeclarativeValueType *>(stack.pop()); + QObject *target = stack.top(); + valueHandler->write(target, instr.fetchValue.property, + QDeclarativePropertyPrivate::BypassInterceptor); + } + break; + + default: + qFatal("QDeclarativeCompiledData: Internal error - unknown instruction %d", instr.type); + break; + } + } + + if (isError()) { + if (!stack.isEmpty()) { + delete stack.at(0); // ### What about failures in deferred creation? + } else { + ctxt->destroy(); + } + + QDeclarativeEnginePrivate::clear(bindValues); + QDeclarativeEnginePrivate::clear(parserStatus); + return 0; + } + + if (bindValues.count) + ep->bindValues << bindValues; + else if (bindValues.values) + bindValues.clear(); + + if (parserStatus.count) + ep->parserStatus << parserStatus; + else if (parserStatus.values) + parserStatus.clear(); + + Q_ASSERT(stack.count() == 1); + return stack.top(); +} + +bool QDeclarativeVME::isError() const +{ + return !vmeErrors.isEmpty(); +} + +QList<QDeclarativeError> QDeclarativeVME::errors() const +{ + return vmeErrors; +} + +QObject * +QDeclarativeCompiledData::TypeReference::createInstance(QDeclarativeContextData *ctxt, + const QBitField &bindings, + QList<QDeclarativeError> *errors) const +{ + if (type) { + QObject *rv = 0; + void *memory = 0; + + type->create(&rv, &memory, sizeof(QDeclarativeData)); + QDeclarativeData *ddata = new (memory) QDeclarativeData; + ddata->ownMemory = false; + QObjectPrivate::get(rv)->declarativeData = ddata; + + if (typePropertyCache && !ddata->propertyCache) { + ddata->propertyCache = typePropertyCache; + ddata->propertyCache->addref(); + } + + return rv; + } else { + Q_ASSERT(component); + return QDeclarativeComponentPrivate::begin(ctxt, 0, component, -1, -1, 0, errors, bindings); + } +} + +template<typename T> +QDeclarativeVMEStack<T>::QDeclarativeVMEStack() +: _index(-1) +{ +} + +template<typename T> +bool QDeclarativeVMEStack<T>::isEmpty() const { + return _index == -1; +} + +template<typename T> +const T &QDeclarativeVMEStack<T>::top() const { + return at(_index); +} + +template<typename T> +void QDeclarativeVMEStack<T>::push(const T &o) { + _index++; + + Q_ASSERT(_index <= VLA::size()); + if (_index == VLA::size()) + VLA::append(o); + else + VLA::data()[_index] = o; +} + +template<typename T> +T QDeclarativeVMEStack<T>::pop() { + Q_ASSERT(_index >= 0); + --_index; + return VLA::data()[_index + 1]; +} + +template<typename T> +int QDeclarativeVMEStack<T>::count() const { + return _index + 1; +} + +template<typename T> +const T &QDeclarativeVMEStack<T>::at(int index) const { + return VLA::data()[index]; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h new file mode 100644 index 00000000..a00b4f12 --- /dev/null +++ b/src/declarative/qml/qdeclarativevme_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEVME_P_H +#define QDECLARATIVEVME_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarativeerror.h" +#include "private/qbitfield_p.h" + +#include <QtCore/QString> +#include <QtCore/QStack> +#include <QtCore/QVarLengthArray> + +QT_BEGIN_NAMESPACE + +class QObject; +class QDeclarativeInstruction; +class QDeclarativeCompiledData; +class QDeclarativeCompiledData; +class QDeclarativeContextData; + +class QDeclarativeVMEObjectStack; +class QDeclarativeVME +{ +public: + QDeclarativeVME(); + + QObject *run(QDeclarativeContextData *, QDeclarativeCompiledData *, + int start = -1, int count = -1, + const QBitField & = QBitField()); + void runDeferred(QObject *); + + bool isError() const; + QList<QDeclarativeError> errors() const; + +private: + QObject *run(QDeclarativeVMEObjectStack &, + QDeclarativeContextData *, QDeclarativeCompiledData *, + int start, int count, + const QBitField &); + QList<QDeclarativeError> vmeErrors; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEVME_P_H diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp new file mode 100644 index 00000000..f4cc8dbe --- /dev/null +++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp @@ -0,0 +1,903 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativevmemetaobject_p.h" + +#include "qdeclarative.h" +#include "private/qdeclarativerefcount_p.h" +#include "qdeclarativeexpression.h" +#include "private/qdeclarativeexpression_p.h" +#include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativebinding_p.h" + +Q_DECLARE_METATYPE(QScriptValue); + +QT_BEGIN_NAMESPACE + +class QDeclarativeVMEVariant +{ +public: + inline QDeclarativeVMEVariant(); + inline ~QDeclarativeVMEVariant(); + + inline const void *dataPtr() const; + inline void *dataPtr(); + inline int dataType() const; + + inline QObject *asQObject(); + inline const QVariant &asQVariant(); + inline int asInt(); + inline bool asBool(); + inline double asDouble(); + inline const QString &asQString(); + inline const QUrl &asQUrl(); + inline const QColor &asQColor(); + inline const QTime &asQTime(); + inline const QDate &asQDate(); + inline const QDateTime &asQDateTime(); + inline const QScriptValue &asQScriptValue(); + + inline void setValue(QObject *); + inline void setValue(const QVariant &); + inline void setValue(int); + inline void setValue(bool); + inline void setValue(double); + inline void setValue(const QString &); + inline void setValue(const QUrl &); + inline void setValue(const QColor &); + inline void setValue(const QTime &); + inline void setValue(const QDate &); + inline void setValue(const QDateTime &); + inline void setValue(const QScriptValue &); +private: + int type; + void *data[4]; // Large enough to hold all types + + inline void cleanup(); +}; + +QDeclarativeVMEVariant::QDeclarativeVMEVariant() +: type(QVariant::Invalid) +{ +} + +QDeclarativeVMEVariant::~QDeclarativeVMEVariant() +{ + cleanup(); +} + +void QDeclarativeVMEVariant::cleanup() +{ + if (type == QVariant::Invalid) { + } else if (type == QMetaType::Int || + type == QMetaType::Bool || + type == QMetaType::Double) { + type = QVariant::Invalid; + } else if (type == QMetaType::QObjectStar) { + ((QDeclarativeGuard<QObject>*)dataPtr())->~QDeclarativeGuard<QObject>(); + type = QVariant::Invalid; + } else if (type == QMetaType::QString) { + ((QString *)dataPtr())->~QString(); + type = QVariant::Invalid; + } else if (type == QMetaType::QUrl) { + ((QUrl *)dataPtr())->~QUrl(); + type = QVariant::Invalid; + } else if (type == QMetaType::QColor) { + ((QColor *)dataPtr())->~QColor(); + type = QVariant::Invalid; + } else if (type == QMetaType::QTime) { + ((QTime *)dataPtr())->~QTime(); + type = QVariant::Invalid; + } else if (type == QMetaType::QDate) { + ((QDate *)dataPtr())->~QDate(); + type = QVariant::Invalid; + } else if (type == QMetaType::QDateTime) { + ((QDateTime *)dataPtr())->~QDateTime(); + type = QVariant::Invalid; + } else if (type == qMetaTypeId<QVariant>()) { + ((QVariant *)dataPtr())->~QVariant(); + type = QVariant::Invalid; + } else if (type == qMetaTypeId<QScriptValue>()) { + ((QScriptValue *)dataPtr())->~QScriptValue(); + type = QVariant::Invalid; + } + +} + +int QDeclarativeVMEVariant::dataType() const +{ + return type; +} + +const void *QDeclarativeVMEVariant::dataPtr() const +{ + return &data; +} + +void *QDeclarativeVMEVariant::dataPtr() +{ + return &data; +} + +QObject *QDeclarativeVMEVariant::asQObject() +{ + if (type != QMetaType::QObjectStar) + setValue((QObject *)0); + + return *(QDeclarativeGuard<QObject> *)(dataPtr()); +} + +const QVariant &QDeclarativeVMEVariant::asQVariant() +{ + if (type != QMetaType::QVariant) + setValue(QVariant()); + + return *(QVariant *)(dataPtr()); +} + +int QDeclarativeVMEVariant::asInt() +{ + if (type != QMetaType::Int) + setValue(int(0)); + + return *(int *)(dataPtr()); +} + +bool QDeclarativeVMEVariant::asBool() +{ + if (type != QMetaType::Bool) + setValue(bool(false)); + + return *(bool *)(dataPtr()); +} + +double QDeclarativeVMEVariant::asDouble() +{ + if (type != QMetaType::Double) + setValue(double(0)); + + return *(double *)(dataPtr()); +} + +const QString &QDeclarativeVMEVariant::asQString() +{ + if (type != QMetaType::QString) + setValue(QString()); + + return *(QString *)(dataPtr()); +} + +const QUrl &QDeclarativeVMEVariant::asQUrl() +{ + if (type != QMetaType::QUrl) + setValue(QUrl()); + + return *(QUrl *)(dataPtr()); +} + +const QColor &QDeclarativeVMEVariant::asQColor() +{ + if (type != QMetaType::QColor) + setValue(QColor()); + + return *(QColor *)(dataPtr()); +} + +const QTime &QDeclarativeVMEVariant::asQTime() +{ + if (type != QMetaType::QTime) + setValue(QTime()); + + return *(QTime *)(dataPtr()); +} + +const QDate &QDeclarativeVMEVariant::asQDate() +{ + if (type != QMetaType::QDate) + setValue(QDate()); + + return *(QDate *)(dataPtr()); +} + +const QDateTime &QDeclarativeVMEVariant::asQDateTime() +{ + if (type != QMetaType::QDateTime) + setValue(QDateTime()); + + return *(QDateTime *)(dataPtr()); +} + +const QScriptValue &QDeclarativeVMEVariant::asQScriptValue() +{ + if (type != qMetaTypeId<QScriptValue>()) + setValue(QScriptValue()); + + return *(QScriptValue *)(dataPtr()); +} + +void QDeclarativeVMEVariant::setValue(QObject *v) +{ + if (type != QMetaType::QObjectStar) { + cleanup(); + type = QMetaType::QObjectStar; + new (dataPtr()) QDeclarativeGuard<QObject>(); + } + *(QDeclarativeGuard<QObject>*)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(const QVariant &v) +{ + if (type != qMetaTypeId<QVariant>()) { + cleanup(); + type = qMetaTypeId<QVariant>(); + new (dataPtr()) QVariant(v); + } else { + *(QVariant *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(int v) +{ + if (type != QMetaType::Int) { + cleanup(); + type = QMetaType::Int; + } + *(int *)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(bool v) +{ + if (type != QMetaType::Bool) { + cleanup(); + type = QMetaType::Bool; + } + *(bool *)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(double v) +{ + if (type != QMetaType::Double) { + cleanup(); + type = QMetaType::Double; + } + *(double *)(dataPtr()) = v; +} + +void QDeclarativeVMEVariant::setValue(const QString &v) +{ + if (type != QMetaType::QString) { + cleanup(); + type = QMetaType::QString; + new (dataPtr()) QString(v); + } else { + *(QString *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QUrl &v) +{ + if (type != QMetaType::QUrl) { + cleanup(); + type = QMetaType::QUrl; + new (dataPtr()) QUrl(v); + } else { + *(QUrl *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QColor &v) +{ + if (type != QMetaType::QColor) { + cleanup(); + type = QMetaType::QColor; + new (dataPtr()) QColor(v); + } else { + *(QColor *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QTime &v) +{ + if (type != QMetaType::QTime) { + cleanup(); + type = QMetaType::QTime; + new (dataPtr()) QTime(v); + } else { + *(QTime *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QDate &v) +{ + if (type != QMetaType::QDate) { + cleanup(); + type = QMetaType::QDate; + new (dataPtr()) QDate(v); + } else { + *(QDate *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QDateTime &v) +{ + if (type != QMetaType::QDateTime) { + cleanup(); + type = QMetaType::QDateTime; + new (dataPtr()) QDateTime(v); + } else { + *(QDateTime *)(dataPtr()) = v; + } +} + +void QDeclarativeVMEVariant::setValue(const QScriptValue &v) +{ + if (type != qMetaTypeId<QScriptValue>()) { + cleanup(); + type = qMetaTypeId<QScriptValue>(); + new (dataPtr()) QScriptValue(v); + } else { + *(QScriptValue *)(dataPtr()) = v; + } +} + +QDeclarativeVMEMetaObject::QDeclarativeVMEMetaObject(QObject *obj, + const QMetaObject *other, + const QDeclarativeVMEMetaData *meta, + QDeclarativeCompiledData *cdata) +: object(obj), compiledData(cdata), ctxt(QDeclarativeData::get(obj, true)->outerContext), + metaData(meta), data(0), methods(0), parent(0) +{ + compiledData->addref(); + + *static_cast<QMetaObject *>(this) = *other; + this->d.superdata = obj->metaObject(); + + QObjectPrivate *op = QObjectPrivate::get(obj); + if (op->metaObject) + parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject); + op->metaObject = this; + + propOffset = QAbstractDynamicMetaObject::propertyOffset(); + methodOffset = QAbstractDynamicMetaObject::methodOffset(); + + data = new QDeclarativeVMEVariant[metaData->propertyCount]; + + aConnected.resize(metaData->aliasCount); + int list_type = qMetaTypeId<QDeclarativeListProperty<QObject> >(); + + // ### Optimize + for (int ii = 0; ii < metaData->propertyCount; ++ii) { + int t = (metaData->propertyData() + ii)->propertyType; + if (t == list_type) { + listProperties.append(List(methodOffset + ii)); + data[ii].setValue(listProperties.count() - 1); + } + } +} + +QDeclarativeVMEMetaObject::~QDeclarativeVMEMetaObject() +{ + compiledData->release(); + delete parent; + delete [] data; + delete [] methods; +} + +int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) +{ + int id = _id; + if(c == QMetaObject::WriteProperty) { + int flags = *reinterpret_cast<int*>(a[3]); + if (!(flags & QDeclarativePropertyPrivate::BypassInterceptor) + && !aInterceptors.isEmpty() + && aInterceptors.testBit(id)) { + QPair<int, QDeclarativePropertyValueInterceptor*> pair = interceptors.value(id); + int valueIndex = pair.first; + QDeclarativePropertyValueInterceptor *vi = pair.second; + int type = property(id).userType(); + + if (type != QVariant::Invalid) { + if (valueIndex != -1) { + QDeclarativeEnginePrivate *ep = ctxt?QDeclarativeEnginePrivate::get(ctxt->engine):0; + QDeclarativeValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[type]; + else valueType = QDeclarativeValueTypeFactory::valueType(type); + Q_ASSERT(valueType); + + valueType->setValue(QVariant(type, a[0])); + QMetaProperty valueProp = valueType->metaObject()->property(valueIndex); + vi->write(valueProp.read(valueType)); + + if (!ep) delete valueType; + return -1; + } else { + vi->write(QVariant(type, a[0])); + return -1; + } + } + } + } + if(c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) { + if (id >= propOffset) { + id -= propOffset; + + if (id < metaData->propertyCount) { + int t = (metaData->propertyData() + id)->propertyType; + bool needActivate = false; + + if (t == -1) { + + if (c == QMetaObject::ReadProperty) { + *reinterpret_cast<QVariant *>(a[0]) = readVarPropertyAsVariant(id); + } else if (c == QMetaObject::WriteProperty) { + writeVarProperty(id, *reinterpret_cast<QVariant *>(a[0])); + } + + } else { + + if (c == QMetaObject::ReadProperty) { + switch(t) { + case QVariant::Int: + *reinterpret_cast<int *>(a[0]) = data[id].asInt(); + break; + case QVariant::Bool: + *reinterpret_cast<bool *>(a[0]) = data[id].asBool(); + break; + case QVariant::Double: + *reinterpret_cast<double *>(a[0]) = data[id].asDouble(); + break; + case QVariant::String: + *reinterpret_cast<QString *>(a[0]) = data[id].asQString(); + break; + case QVariant::Url: + *reinterpret_cast<QUrl *>(a[0]) = data[id].asQUrl(); + break; + case QVariant::Color: + *reinterpret_cast<QColor *>(a[0]) = data[id].asQColor(); + break; + case QVariant::Date: + *reinterpret_cast<QDate *>(a[0]) = data[id].asQDate(); + break; + case QVariant::DateTime: + *reinterpret_cast<QDateTime *>(a[0]) = data[id].asQDateTime(); + break; + case QMetaType::QObjectStar: + *reinterpret_cast<QObject **>(a[0]) = data[id].asQObject(); + break; + default: + break; + } + if (t == qMetaTypeId<QDeclarativeListProperty<QObject> >()) { + int listIndex = data[id].asInt(); + const List *list = &listProperties.at(listIndex); + *reinterpret_cast<QDeclarativeListProperty<QObject> *>(a[0]) = + QDeclarativeListProperty<QObject>(object, (void *)list, + list_append, list_count, list_at, + list_clear); + } + + } else if (c == QMetaObject::WriteProperty) { + + switch(t) { + case QVariant::Int: + needActivate = *reinterpret_cast<int *>(a[0]) != data[id].asInt(); + data[id].setValue(*reinterpret_cast<int *>(a[0])); + break; + case QVariant::Bool: + needActivate = *reinterpret_cast<bool *>(a[0]) != data[id].asBool(); + data[id].setValue(*reinterpret_cast<bool *>(a[0])); + break; + case QVariant::Double: + needActivate = *reinterpret_cast<double *>(a[0]) != data[id].asDouble(); + data[id].setValue(*reinterpret_cast<double *>(a[0])); + break; + case QVariant::String: + needActivate = *reinterpret_cast<QString *>(a[0]) != data[id].asQString(); + data[id].setValue(*reinterpret_cast<QString *>(a[0])); + break; + case QVariant::Url: + needActivate = *reinterpret_cast<QUrl *>(a[0]) != data[id].asQUrl(); + data[id].setValue(*reinterpret_cast<QUrl *>(a[0])); + break; + case QVariant::Color: + needActivate = *reinterpret_cast<QColor *>(a[0]) != data[id].asQColor(); + data[id].setValue(*reinterpret_cast<QColor *>(a[0])); + break; + case QVariant::Date: + needActivate = *reinterpret_cast<QDate *>(a[0]) != data[id].asQDate(); + data[id].setValue(*reinterpret_cast<QDate *>(a[0])); + break; + case QVariant::DateTime: + needActivate = *reinterpret_cast<QDateTime *>(a[0]) != data[id].asQDateTime(); + data[id].setValue(*reinterpret_cast<QDateTime *>(a[0])); + break; + case QMetaType::QObjectStar: + needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject(); + data[id].setValue(*reinterpret_cast<QObject **>(a[0])); + break; + default: + break; + } + } + + } + + if (c == QMetaObject::WriteProperty && needActivate) { + activate(object, methodOffset + id, 0); + } + + return -1; + } + + id -= metaData->propertyCount; + + if (id < metaData->aliasCount) { + + QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + id; + + if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty) + *reinterpret_cast<void **>(a[0]) = 0; + + if (!ctxt) return -1; + + QDeclarativeContext *context = ctxt->asQDeclarativeContext(); + QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context); + + QObject *target = ctxtPriv->data->idValues[d->contextIdx].data(); + if (!target) + return -1; + + connectAlias(id); + + if (d->isObjectAlias()) { + *reinterpret_cast<QObject **>(a[0]) = target; + return -1; + } + + // Remove binding (if any) on write + if(c == QMetaObject::WriteProperty) { + int flags = *reinterpret_cast<int*>(a[3]); + if (flags & QDeclarativePropertyPrivate::RemoveBindingOnAliasWrite) { + QDeclarativeData *targetData = QDeclarativeData::get(target); + if (targetData && targetData->hasBindingBit(d->propertyIndex())) { + QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0); + if (binding) binding->destroy(); + } + } + } + + if (d->isValueTypeAlias()) { + // Value type property + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine); + + QDeclarativeValueType *valueType = ep->valueTypes[d->valueType()]; + Q_ASSERT(valueType); + + valueType->read(target, d->propertyIndex()); + int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a); + + if (c == QMetaObject::WriteProperty) + valueType->write(target, d->propertyIndex(), 0x00); + + return rv; + + } else { + return QMetaObject::metacall(target, c, d->propertyIndex(), a); + } + + } + return -1; + + } + + } else if(c == QMetaObject::InvokeMetaMethod) { + + if (id >= methodOffset) { + + id -= methodOffset; + int plainSignals = metaData->signalCount + metaData->propertyCount + + metaData->aliasCount; + if (id < plainSignals) { + QMetaObject::activate(object, _id, a); + return -1; + } + + id -= plainSignals; + + if (id < metaData->methodCount) { + if (!ctxt->engine) + return -1; // We can't run the method + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine); + + QScriptValue function = method(id); + + QScriptValueList args; + QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + id; + if (data->parameterCount) { + for (int ii = 0; ii < data->parameterCount; ++ii) { + args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]); + } + } + QScriptValue rv = function.call(ep->objectClass->newQObject(object), args); + + if (a[0]) *reinterpret_cast<QVariant *>(a[0]) = ep->scriptValueToVariant(rv); + + return -1; + } + return -1; + } + } + + if (parent) + return parent->metaCall(c, _id, a); + else + return object->qt_metacall(c, _id, a); +} + +QScriptValue QDeclarativeVMEMetaObject::method(int index) +{ + if (!methods) + methods = new QScriptValue[metaData->methodCount]; + + if (!methods[index].isValid()) { + QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + index; + + const QChar *body = + (const QChar *)(((const char*)metaData) + data->bodyOffset); + + QString code = QString::fromRawData(body, data->bodyLength); + + // XXX Use QScriptProgram + // XXX We should evaluate all methods in a single big script block to + // improve the call time between dynamic methods defined on the same + // object + methods[index] = QDeclarativeExpressionPrivate::evalInObjectScope(ctxt, object, code, ctxt->url.toString(), + data->lineNumber, 0); + } + + return methods[index]; +} + +QScriptValue QDeclarativeVMEMetaObject::readVarProperty(int id) +{ + if (data[id].dataType() == qMetaTypeId<QScriptValue>()) + return data[id].asQScriptValue(); + else if (data[id].dataType() == QMetaType::QObjectStar) + return QDeclarativeEnginePrivate::get(ctxt->engine)->objectClass->newQObject(data[id].asQObject()); + else + return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueFromVariant(data[id].asQVariant()); +} + +QVariant QDeclarativeVMEMetaObject::readVarPropertyAsVariant(int id) +{ + if (data[id].dataType() == qMetaTypeId<QScriptValue>()) + return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueToVariant(data[id].asQScriptValue()); + else if (data[id].dataType() == QMetaType::QObjectStar) + return QVariant::fromValue(data[id].asQObject()); + else + return data[id].asQVariant(); +} + +void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QScriptValue &value) +{ + data[id].setValue(value); + activate(object, methodOffset + id, 0); +} + +void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QVariant &value) +{ + bool needActivate = false; + if (value.userType() == QMetaType::QObjectStar) { + QObject *o = qvariant_cast<QObject *>(value); + needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o); + data[id].setValue(qvariant_cast<QObject *>(value)); + } else { + needActivate = (data[id].dataType() != qMetaTypeId<QVariant>() || + data[id].asQVariant().userType() != value.userType() || + data[id].asQVariant() != value); + data[id].setValue(value); + } + if (needActivate) + activate(object, methodOffset + id, 0); +} + +void QDeclarativeVMEMetaObject::listChanged(int id) +{ + activate(object, methodOffset + id, 0); +} + +void QDeclarativeVMEMetaObject::list_append(QDeclarativeListProperty<QObject> *prop, QObject *o) +{ + List *list = static_cast<List *>(prop->data); + list->append(o); + QMetaObject::activate(prop->object, list->notifyIndex, 0); +} + +int QDeclarativeVMEMetaObject::list_count(QDeclarativeListProperty<QObject> *prop) +{ + return static_cast<List *>(prop->data)->count(); +} + +QObject *QDeclarativeVMEMetaObject::list_at(QDeclarativeListProperty<QObject> *prop, int index) +{ + return static_cast<List *>(prop->data)->at(index); +} + +void QDeclarativeVMEMetaObject::list_clear(QDeclarativeListProperty<QObject> *prop) +{ + List *list = static_cast<List *>(prop->data); + list->clear(); + QMetaObject::activate(prop->object, list->notifyIndex, 0); +} + +void QDeclarativeVMEMetaObject::registerInterceptor(int index, int valueIndex, QDeclarativePropertyValueInterceptor *interceptor) +{ + if (aInterceptors.isEmpty()) + aInterceptors.resize(propertyCount() + metaData->propertyCount); + aInterceptors.setBit(index); + interceptors.insert(index, qMakePair(valueIndex, interceptor)); +} + +int QDeclarativeVMEMetaObject::vmeMethodLineNumber(int index) +{ + if (index < methodOffset) { + Q_ASSERT(parent); + return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeMethodLineNumber(index); + } + + int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; + Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount)); + + int rawIndex = index - methodOffset - plainSignals; + + QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + rawIndex; + return data->lineNumber; +} + +QScriptValue QDeclarativeVMEMetaObject::vmeMethod(int index) +{ + if (index < methodOffset) { + Q_ASSERT(parent); + return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeMethod(index); + } + int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; + Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount)); + return method(index - methodOffset - plainSignals); +} + +void QDeclarativeVMEMetaObject::setVmeMethod(int index, const QScriptValue &value) +{ + if (index < methodOffset) { + Q_ASSERT(parent); + return static_cast<QDeclarativeVMEMetaObject *>(parent)->setVmeMethod(index, value); + } + int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; + Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount)); + + if (!methods) + methods = new QScriptValue[metaData->methodCount]; + methods[index - methodOffset - plainSignals] = value; +} + +QScriptValue QDeclarativeVMEMetaObject::vmeProperty(int index) +{ + if (index < propOffset) { + Q_ASSERT(parent); + return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeProperty(index); + } + return readVarProperty(index - propOffset); +} + +void QDeclarativeVMEMetaObject::setVMEProperty(int index, const QScriptValue &v) +{ + if (index < propOffset) { + Q_ASSERT(parent); + static_cast<QDeclarativeVMEMetaObject *>(parent)->setVMEProperty(index, v); + } + return writeVarProperty(index - propOffset, v); +} + +bool QDeclarativeVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const +{ + Q_ASSERT(index >= propOffset + metaData->propertyCount); + + *target = 0; + *coreIndex = -1; + *valueTypeIndex = -1; + + if (!ctxt) + return false; + + QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset - metaData->propertyCount); + QDeclarativeContext *context = ctxt->asQDeclarativeContext(); + QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context); + + *target = ctxtPriv->data->idValues[d->contextIdx].data(); + if (!*target) + return false; + + if (d->isObjectAlias()) { + } else if (d->isValueTypeAlias()) { + *coreIndex = d->propertyIndex(); + *valueTypeIndex = d->valueTypeIndex(); + } else { + *coreIndex = d->propertyIndex(); + } + + return true; +} + +void QDeclarativeVMEMetaObject::connectAlias(int aliasId) +{ + if (!aConnected.testBit(aliasId)) { + aConnected.setBit(aliasId); + + QDeclarativeContext *context = ctxt->asQDeclarativeContext(); + QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context); + + QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + aliasId; + + QObject *target = ctxtPriv->data->idValues[d->contextIdx].data(); + if (!target) + return; + + int sigIdx = methodOffset + aliasId + metaData->propertyCount; + QMetaObject::connect(context, d->contextIdx + ctxtPriv->notifyIndex, object, sigIdx); + + if (!d->isObjectAlias()) { + QMetaProperty prop = target->metaObject()->property(d->propertyIndex()); + if (prop.hasNotifySignal()) + QDeclarativePropertyPrivate::connect(target, prop.notifySignalIndex(), object, sigIdx); + } + } +} + +void QDeclarativeVMEMetaObject::connectAliasSignal(int index) +{ + int aliasId = (index - methodOffset) - metaData->propertyCount; + if (aliasId < 0 || aliasId >= metaData->aliasCount) + return; + + connectAlias(aliasId); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativevmemetaobject_p.h b/src/declarative/qml/qdeclarativevmemetaobject_p.h new file mode 100644 index 00000000..3c6e4524 --- /dev/null +++ b/src/declarative/qml/qdeclarativevmemetaobject_p.h @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEVMEMETAOBJECT_P_H +#define QDECLARATIVEVMEMETAOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarative.h" + +#include <QtCore/QMetaObject> +#include <QtCore/QBitArray> +#include <QtCore/QPair> +#include <QtGui/QColor> +#include <QtCore/QDate> +#include <QtCore/qlist.h> +#include <QtCore/qdebug.h> + +#include <private/qobject_p.h> + +#include "private/qdeclarativeguard_p.h" +#include "private/qdeclarativecompiler_p.h" +#include "private/qdeclarativecontext_p.h" + +QT_BEGIN_NAMESPACE + +#define QML_ALIAS_FLAG_PTR 0x00000001 + +struct QDeclarativeVMEMetaData +{ + short propertyCount; + short aliasCount; + short signalCount; + short methodCount; + + struct AliasData { + int contextIdx; + int propertyIdx; + int flags; + + bool isObjectAlias() const { + return propertyIdx == -1; + } + bool isPropertyAlias() const { + return !isObjectAlias() && !(propertyIdx & 0xFF000000); + } + bool isValueTypeAlias() const { + return !isObjectAlias() && (propertyIdx & 0xFF000000); + } + int propertyIndex() const { + return propertyIdx & 0x0000FFFF; + } + int valueTypeIndex() const { + return (propertyIdx & 0x00FF0000) >> 16; + } + int valueType() const { + return ((unsigned int)propertyIdx) >> 24; + } + }; + + struct PropertyData { + int propertyType; + }; + + struct MethodData { + int parameterCount; + int bodyOffset; + int bodyLength; + int lineNumber; + }; + + PropertyData *propertyData() const { + return (PropertyData *)(((const char *)this) + sizeof(QDeclarativeVMEMetaData)); + } + + AliasData *aliasData() const { + return (AliasData *)(propertyData() + propertyCount); + } + + MethodData *methodData() const { + return (MethodData *)(aliasData() + aliasCount); + } +}; + +class QDeclarativeVMEVariant; +class QDeclarativeRefCount; +class QDeclarativeVMEMetaObject : public QAbstractDynamicMetaObject +{ +public: + QDeclarativeVMEMetaObject(QObject *obj, const QMetaObject *other, const QDeclarativeVMEMetaData *data, + QDeclarativeCompiledData *compiledData); + ~QDeclarativeVMEMetaObject(); + + bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const; + void registerInterceptor(int index, int valueIndex, QDeclarativePropertyValueInterceptor *interceptor); + QScriptValue vmeMethod(int index); + int vmeMethodLineNumber(int index); + void setVmeMethod(int index, const QScriptValue &); + QScriptValue vmeProperty(int index); + void setVMEProperty(int index, const QScriptValue &); + + void connectAliasSignal(int index); + +protected: + virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); + +private: + QObject *object; + QDeclarativeCompiledData *compiledData; + QDeclarativeGuardedContextData ctxt; + + const QDeclarativeVMEMetaData *metaData; + int propOffset; + int methodOffset; + + QDeclarativeVMEVariant *data; + + void connectAlias(int aliasId); + QBitArray aConnected; + QBitArray aInterceptors; + QHash<int, QPair<int, QDeclarativePropertyValueInterceptor*> > interceptors; + + QScriptValue *methods; + QScriptValue method(int); + + QScriptValue readVarProperty(int); + QVariant readVarPropertyAsVariant(int); + void writeVarProperty(int, const QScriptValue &); + void writeVarProperty(int, const QVariant &); + + QAbstractDynamicMetaObject *parent; + + void listChanged(int); + class List : public QList<QObject*> + { + public: + List(int lpi) : notifyIndex(lpi) {} + int notifyIndex; + }; + QList<List> listProperties; + + static void list_append(QDeclarativeListProperty<QObject> *, QObject *); + static int list_count(QDeclarativeListProperty<QObject> *); + static QObject *list_at(QDeclarativeListProperty<QObject> *, int); + static void list_clear(QDeclarativeListProperty<QObject> *); +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEVMEMETAOBJECT_P_H diff --git a/src/declarative/qml/qdeclarativewatcher.cpp b/src/declarative/qml/qdeclarativewatcher.cpp new file mode 100644 index 00000000..de5f1489 --- /dev/null +++ b/src/declarative/qml/qdeclarativewatcher.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativewatcher_p.h" + +#include "qdeclarativeexpression.h" +#include "qdeclarativecontext.h" +#include "qdeclarative.h" + +#include <qdeclarativedebugservice_p.h> +#include "private/qdeclarativeproperty_p.h" +#include "private/qdeclarativevaluetype_p.h" + +#include <QtCore/qmetaobject.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + + +class QDeclarativeWatchProxy : public QObject +{ + Q_OBJECT +public: + QDeclarativeWatchProxy(int id, + QObject *object, + int debugId, + const QMetaProperty &prop, + QDeclarativeWatcher *parent = 0); + + QDeclarativeWatchProxy(int id, + QDeclarativeExpression *exp, + int debugId, + QDeclarativeWatcher *parent = 0); + +public slots: + void notifyValueChanged(); + +private: + friend class QDeclarativeWatcher; + int m_id; + QDeclarativeWatcher *m_watch; + QObject *m_object; + int m_debugId; + QMetaProperty m_property; + + QDeclarativeExpression *m_expr; +}; + +QDeclarativeWatchProxy::QDeclarativeWatchProxy(int id, + QDeclarativeExpression *exp, + int debugId, + QDeclarativeWatcher *parent) +: QObject(parent), m_id(id), m_watch(parent), m_object(0), m_debugId(debugId), m_expr(exp) +{ + QObject::connect(m_expr, SIGNAL(valueChanged()), this, SLOT(notifyValueChanged())); +} + +QDeclarativeWatchProxy::QDeclarativeWatchProxy(int id, + QObject *object, + int debugId, + const QMetaProperty &prop, + QDeclarativeWatcher *parent) +: QObject(parent), m_id(id), m_watch(parent), m_object(object), m_debugId(debugId), m_property(prop), m_expr(0) +{ + static int refreshIdx = -1; + if(refreshIdx == -1) + refreshIdx = QDeclarativeWatchProxy::staticMetaObject.indexOfMethod("notifyValueChanged()"); + + if (prop.hasNotifySignal()) + QDeclarativePropertyPrivate::connect(m_object, prop.notifySignalIndex(), this, refreshIdx); +} + +void QDeclarativeWatchProxy::notifyValueChanged() +{ + QVariant v; + if (m_expr) + v = m_expr->evaluate(); + else if (QDeclarativeValueTypeFactory::isValueType(m_property.userType())) + v = m_property.read(m_object); + + emit m_watch->propertyChanged(m_id, m_debugId, m_property, v); +} + + +QDeclarativeWatcher::QDeclarativeWatcher(QObject *parent) + : QObject(parent) +{ +} + +bool QDeclarativeWatcher::addWatch(int id, quint32 debugId) +{ + QObject *object = QDeclarativeDebugService::objectForId(debugId); + if (object) { + int propCount = object->metaObject()->propertyCount(); + for (int ii=0; ii<propCount; ii++) + addPropertyWatch(id, object, debugId, object->metaObject()->property(ii)); + return true; + } + return false; +} + +bool QDeclarativeWatcher::addWatch(int id, quint32 debugId, const QByteArray &property) +{ + QObject *object = QDeclarativeDebugService::objectForId(debugId); + if (object) { + int index = object->metaObject()->indexOfProperty(property.constData()); + if (index >= 0) { + addPropertyWatch(id, object, debugId, object->metaObject()->property(index)); + return true; + } + } + return false; +} + +bool QDeclarativeWatcher::addWatch(int id, quint32 objectId, const QString &expr) +{ + QObject *object = QDeclarativeDebugService::objectForId(objectId); + QDeclarativeContext *context = qmlContext(object); + if (context) { + QDeclarativeExpression *exprObj = new QDeclarativeExpression(context, object, expr); + exprObj->setNotifyOnValueChanged(true); + QDeclarativeWatchProxy *proxy = new QDeclarativeWatchProxy(id, exprObj, objectId, this); + exprObj->setParent(proxy); + m_proxies[id].append(proxy); + proxy->notifyValueChanged(); + return true; + } + return false; +} + +void QDeclarativeWatcher::removeWatch(int id) +{ + if (!m_proxies.contains(id)) + return; + + QList<QPointer<QDeclarativeWatchProxy> > proxies = m_proxies.take(id); + qDeleteAll(proxies); +} + +void QDeclarativeWatcher::addPropertyWatch(int id, QObject *object, quint32 debugId, const QMetaProperty &property) +{ + QDeclarativeWatchProxy *proxy = new QDeclarativeWatchProxy(id, object, debugId, property, this); + m_proxies[id].append(proxy); + + proxy->notifyValueChanged(); +} + +QT_END_NAMESPACE + +#include <qdeclarativewatcher.moc> diff --git a/src/declarative/qml/qdeclarativewatcher_p.h b/src/declarative/qml/qdeclarativewatcher_p.h new file mode 100644 index 00000000..c8b31424 --- /dev/null +++ b/src/declarative/qml/qdeclarativewatcher_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEWATCHER_P_H +#define QDECLARATIVEWATCHER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qlist.h> +#include <QtCore/qpair.h> +#include <QtCore/qhash.h> +#include <QtCore/qset.h> +#include <QtCore/qpointer.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeWatchProxy; +class QDeclarativeExpression; +class QDeclarativeContext; +class QMetaProperty; + +class QDeclarativeWatcher : public QObject +{ + Q_OBJECT +public: + QDeclarativeWatcher(QObject * = 0); + + bool addWatch(int id, quint32 objectId); + bool addWatch(int id, quint32 objectId, const QByteArray &property); + bool addWatch(int id, quint32 objectId, const QString &expr); + + void removeWatch(int id); + +Q_SIGNALS: + void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); + +private: + friend class QDeclarativeWatchProxy; + void addPropertyWatch(int id, QObject *object, quint32 objectId, const QMetaProperty &property); + + QHash<int, QList<QPointer<QDeclarativeWatchProxy> > > m_proxies; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEWATCHER_P_H diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp new file mode 100644 index 00000000..be283eae --- /dev/null +++ b/src/declarative/qml/qdeclarativeworkerscript.cpp @@ -0,0 +1,753 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativeworkerscript_p.h" +#include "private/qdeclarativelistmodel_p.h" +#include "private/qdeclarativelistmodelworkeragent_p.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativeexpression_p.h" + +#include <QtCore/qcoreevent.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdebug.h> +#include <QtScript/qscriptengine.h> +#include <QtCore/qmutex.h> +#include <QtCore/qwaitcondition.h> +#include <QtScript/qscriptvalueiterator.h> +#include <QtCore/qfile.h> +#include <QtCore/qdatetime.h> +#include <QtNetwork/qnetworkaccessmanager.h> +#include <QtDeclarative/qdeclarativeinfo.h> +#include "qdeclarativenetworkaccessmanagerfactory.h" + + +QT_BEGIN_NAMESPACE + +class WorkerDataEvent : public QEvent +{ +public: + enum Type { WorkerData = QEvent::User }; + + WorkerDataEvent(int workerId, const QVariant &data); + virtual ~WorkerDataEvent(); + + int workerId() const; + QVariant data() const; + +private: + int m_id; + QVariant m_data; +}; + +class WorkerLoadEvent : public QEvent +{ +public: + enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 }; + + WorkerLoadEvent(int workerId, const QUrl &url); + + int workerId() const; + QUrl url() const; + +private: + int m_id; + QUrl m_url; +}; + +class WorkerRemoveEvent : public QEvent +{ +public: + enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 }; + + WorkerRemoveEvent(int workerId); + + int workerId() const; + +private: + int m_id; +}; + +class WorkerErrorEvent : public QEvent +{ +public: + enum Type { WorkerError = WorkerRemoveEvent::WorkerRemove + 1 }; + + WorkerErrorEvent(const QDeclarativeError &error); + + QDeclarativeError error() const; + +private: + QDeclarativeError m_error; +}; + +class QDeclarativeWorkerScriptEnginePrivate : public QObject +{ + Q_OBJECT +public: + enum WorkerEventTypes { + WorkerDestroyEvent = QEvent::User + 100 + }; + + QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng); + + struct ScriptEngine : public QDeclarativeScriptEngine + { + ScriptEngine(QDeclarativeWorkerScriptEnginePrivate *parent) : QDeclarativeScriptEngine(0), p(parent), accessManager(0) {} + ~ScriptEngine() { delete accessManager; } + QDeclarativeWorkerScriptEnginePrivate *p; + QNetworkAccessManager *accessManager; + + virtual QNetworkAccessManager *networkAccessManager() { + if (!accessManager) { + if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) { + accessManager = p->qmlengine->networkAccessManagerFactory()->create(this); + } else { + accessManager = new QNetworkAccessManager(this); + } + } + return accessManager; + } + }; + ScriptEngine *workerEngine; + static QDeclarativeWorkerScriptEnginePrivate *get(QScriptEngine *e) { + return static_cast<ScriptEngine *>(e)->p; + } + + QDeclarativeEngine *qmlengine; + + QMutex m_lock; + QWaitCondition m_wait; + + struct WorkerScript { + WorkerScript(); + + int id; + QUrl source; + bool initialized; + QDeclarativeWorkerScript *owner; + QScriptValue object; + + QScriptValue callback; + }; + + QHash<int, WorkerScript *> workers; + QScriptValue getWorker(int); + + int m_nextId; + + static QVariant scriptValueToVariant(const QScriptValue &); + static QScriptValue variantToScriptValue(const QVariant &, QScriptEngine *); + + static QScriptValue onMessage(QScriptContext *ctxt, QScriptEngine *engine); + static QScriptValue sendMessage(QScriptContext *ctxt, QScriptEngine *engine); + +signals: + void stopThread(); + +protected: + virtual bool event(QEvent *); + +private: + void processMessage(int, const QVariant &); + void processLoad(int, const QUrl &); + void reportScriptException(WorkerScript *); +}; + +QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine) +: workerEngine(0), qmlengine(engine), m_nextId(0) +{ +} + +QScriptValue QDeclarativeWorkerScriptEnginePrivate::onMessage(QScriptContext *ctxt, QScriptEngine *engine) +{ + QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine); + + int id = ctxt->thisObject().data().toVariant().toInt(); + + WorkerScript *script = p->workers.value(id); + if (!script) + return engine->undefinedValue(); + + if (ctxt->argumentCount() >= 1) + script->callback = ctxt->argument(0); + + return script->callback; +} + +QScriptValue QDeclarativeWorkerScriptEnginePrivate::sendMessage(QScriptContext *ctxt, QScriptEngine *engine) +{ + if (!ctxt->argumentCount()) + return engine->undefinedValue(); + + QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine); + + int id = ctxt->thisObject().data().toVariant().toInt(); + + WorkerScript *script = p->workers.value(id); + if (!script) + return engine->undefinedValue(); + + QMutexLocker(&p->m_lock); + + if (script->owner) + QCoreApplication::postEvent(script->owner, + new WorkerDataEvent(0, scriptValueToVariant(ctxt->argument(0)))); + + return engine->undefinedValue(); +} + +QScriptValue QDeclarativeWorkerScriptEnginePrivate::getWorker(int id) +{ + QHash<int, WorkerScript *>::ConstIterator iter = workers.find(id); + + if (iter == workers.end()) + return workerEngine->nullValue(); + + WorkerScript *script = *iter; + if (!script->initialized) { + + script->initialized = true; + script->object = workerEngine->newObject(); + + QScriptValue api = workerEngine->newObject(); + api.setData(script->id); + + api.setProperty(QLatin1String("onMessage"), workerEngine->newFunction(onMessage), + QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + api.setProperty(QLatin1String("sendMessage"), workerEngine->newFunction(sendMessage)); + + script->object.setProperty(QLatin1String("WorkerScript"), api); + } + + return script->object; +} + +bool QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event) +{ + if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) { + WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event); + processMessage(workerEvent->workerId(), workerEvent->data()); + return true; + } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) { + WorkerLoadEvent *workerEvent = static_cast<WorkerLoadEvent *>(event); + processLoad(workerEvent->workerId(), workerEvent->url()); + return true; + } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) { + emit stopThread(); + return true; + } else { + return QObject::event(event); + } +} + +void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QVariant &data) +{ + WorkerScript *script = workers.value(id); + if (!script) + return; + + if (script->callback.isFunction()) { + QScriptValue args = workerEngine->newArray(1); + args.setProperty(0, variantToScriptValue(data, workerEngine)); + + script->callback.call(script->object, args); + + if (workerEngine->hasUncaughtException()) { + reportScriptException(script); + workerEngine->clearExceptions(); + } + } +} + +void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) +{ + if (url.isRelative()) + return; + + QString fileName = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url); + + QFile f(fileName); + if (f.open(QIODevice::ReadOnly)) { + QByteArray data = f.readAll(); + QString sourceCode = QString::fromUtf8(data); + + QScriptValue activation = getWorker(id); + + QScriptContext *ctxt = QScriptDeclarativeClass::pushCleanContext(workerEngine); + QScriptValue urlContext = workerEngine->newObject(); + urlContext.setData(QScriptValue(workerEngine, url.toString())); + ctxt->pushScope(urlContext); + ctxt->pushScope(activation); + ctxt->setActivationObject(activation); + QDeclarativeScriptParser::extractPragmas(sourceCode); + + workerEngine->baseUrl = url; + workerEngine->evaluate(sourceCode); + + WorkerScript *script = workers.value(id); + if (script) { + script->source = url; + if (workerEngine->hasUncaughtException()) { + reportScriptException(script); + workerEngine->clearExceptions(); + } + } + + workerEngine->popContext(); + } else { + qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString(); + } +} + +void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script) +{ + if (!script || !workerEngine->hasUncaughtException()) + return; + + QDeclarativeError error; + QDeclarativeExpressionPrivate::exceptionToError(workerEngine, error); + error.setUrl(script->source); + + QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(workerEngine); + + QMutexLocker(&p->m_lock); + if (script->owner) + QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error)); +} + +QVariant QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value) +{ + if (value.isBool()) { + return QVariant(value.toBool()); + } else if (value.isString()) { + return QVariant(value.toString()); + } else if (value.isNumber()) { + return QVariant((qreal)value.toNumber()); + } else if (value.isDate()) { + return QVariant(value.toDateTime()); +#ifndef QT_NO_REGEXP + } else if (value.isRegExp()) { + return QVariant(value.toRegExp()); +#endif + } else if (value.isArray()) { + QVariantList list; + + quint32 length = (quint32)value.property(QLatin1String("length")).toNumber(); + + for (quint32 ii = 0; ii < length; ++ii) { + QVariant v = scriptValueToVariant(value.property(ii)); + list << v; + } + + return QVariant(list); + } else if (value.isQObject()) { + QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(value.toQObject()); + if (lm) { + QDeclarativeListModelWorkerAgent *agent = lm->agent(); + if (agent) { + QDeclarativeListModelWorkerAgent::VariantRef v(agent); + return QVariant::fromValue(v); + } else { + return QVariant(); + } + } else { + // No other QObject's are allowed to be sent + return QVariant(); + } + } else if (value.isObject()) { + QVariantHash hash; + + QScriptValueIterator iter(value); + + while (iter.hasNext()) { + iter.next(); + hash.insert(iter.name(), scriptValueToVariant(iter.value())); + } + + return QVariant(hash); + } + + return QVariant(); + +} + +QScriptValue QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine) +{ + if (value.userType() == QVariant::Bool) { + return QScriptValue(value.toBool()); + } else if (value.userType() == QVariant::String) { + return QScriptValue(value.toString()); + } else if (value.userType() == QMetaType::QReal) { + return QScriptValue(value.toReal()); + } else if (value.userType() == QVariant::DateTime) { + return engine->newDate(value.toDateTime()); +#ifndef QT_NO_REGEXP + } else if (value.userType() == QVariant::RegExp) { + return engine->newRegExp(value.toRegExp()); +#endif + } else if (value.userType() == qMetaTypeId<QDeclarativeListModelWorkerAgent::VariantRef>()) { + QDeclarativeListModelWorkerAgent::VariantRef vr = qvariant_cast<QDeclarativeListModelWorkerAgent::VariantRef>(value); + if (vr.a->scriptEngine() == 0) + vr.a->setScriptEngine(engine); + else if (vr.a->scriptEngine() != engine) + return engine->nullValue(); + QScriptValue o = engine->newQObject(vr.a); + o.setData(engine->newVariant(value)); // Keeps the agent ref so that it is cleaned up on gc + return o; + } else if (value.userType() == QMetaType::QVariantList) { + QVariantList list = qvariant_cast<QVariantList>(value); + QScriptValue rv = engine->newArray(list.count()); + + for (quint32 ii = 0; ii < quint32(list.count()); ++ii) + rv.setProperty(ii, variantToScriptValue(list.at(ii), engine)); + + return rv; + } else if (value.userType() == QMetaType::QVariantHash) { + + QVariantHash hash = qvariant_cast<QVariantHash>(value); + + QScriptValue rv = engine->newObject(); + + for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter) + rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine)); + + return rv; + } else { + return engine->nullValue(); + } +} + +WorkerDataEvent::WorkerDataEvent(int workerId, const QVariant &data) +: QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data) +{ +} + +WorkerDataEvent::~WorkerDataEvent() +{ +} + +int WorkerDataEvent::workerId() const +{ + return m_id; +} + +QVariant WorkerDataEvent::data() const +{ + return m_data; +} + +WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url) +: QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url) +{ +} + +int WorkerLoadEvent::workerId() const +{ + return m_id; +} + +QUrl WorkerLoadEvent::url() const +{ + return m_url; +} + +WorkerRemoveEvent::WorkerRemoveEvent(int workerId) +: QEvent((QEvent::Type)WorkerRemove), m_id(workerId) +{ +} + +int WorkerRemoveEvent::workerId() const +{ + return m_id; +} + +WorkerErrorEvent::WorkerErrorEvent(const QDeclarativeError &error) +: QEvent((QEvent::Type)WorkerError), m_error(error) +{ +} + +QDeclarativeError WorkerErrorEvent::error() const +{ + return m_error; +} + +QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent) +: QThread(parent), d(new QDeclarativeWorkerScriptEnginePrivate(parent)) +{ + d->m_lock.lock(); + connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection); + start(QThread::IdlePriority); + d->m_wait.wait(&d->m_lock); + d->moveToThread(this); + d->m_lock.unlock(); +} + +QDeclarativeWorkerScriptEngine::~QDeclarativeWorkerScriptEngine() +{ + d->m_lock.lock(); + qDeleteAll(d->workers); + d->workers.clear(); + QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QDeclarativeWorkerScriptEnginePrivate::WorkerDestroyEvent)); + d->m_lock.unlock(); + + wait(); + d->deleteLater(); +} + +QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript() +: id(-1), initialized(false), owner(0) +{ +} + +int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner) +{ + QDeclarativeWorkerScriptEnginePrivate::WorkerScript *script = new QDeclarativeWorkerScriptEnginePrivate::WorkerScript; + script->id = d->m_nextId++; + script->owner = owner; + + d->m_lock.lock(); + d->workers.insert(script->id, script); + d->m_lock.unlock(); + + return script->id; +} + +void QDeclarativeWorkerScriptEngine::removeWorkerScript(int id) +{ + QCoreApplication::postEvent(d, new WorkerRemoveEvent(id)); +} + +void QDeclarativeWorkerScriptEngine::executeUrl(int id, const QUrl &url) +{ + QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url)); +} + +void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QVariant &data) +{ + QCoreApplication::postEvent(d, new WorkerDataEvent(id, data)); +} + +void QDeclarativeWorkerScriptEngine::run() +{ + d->m_lock.lock(); + + d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::ScriptEngine(d); + + d->m_wait.wakeAll(); + + d->m_lock.unlock(); + + exec(); + + delete d->workerEngine; d->workerEngine = 0; +} + + +/*! + \qmlclass WorkerScript QDeclarativeWorkerScript + \ingroup qml-utility-elements + \brief The WorkerScript element enables the use of threads in QML. + + Use WorkerScript to run operations in a new thread. + This is useful for running operations in the background so + that the main GUI thread is not blocked. + + Messages can be passed between the new thread and the parent thread + using \l sendMessage() and the \l {WorkerScript::onMessage}{onMessage()} handler. + + An example: + + \snippet doc/src/snippets/declarative/workerscript.qml 0 + + The above worker script specifies a JavaScript file, "script.js", that handles + the operations to be performed in the new thread. Here is \c script.js: + + \quotefile doc/src/snippets/declarative/script.js + + When the user clicks anywhere within the rectangle, \c sendMessage() is + called, triggering the \tt WorkerScript.onMessage() handler in + \tt script.js. This in turn sends a reply message that is then received + by the \tt onMessage() handler of \tt myWorker. + + + \section3 Restrictions + + Since the \c WorkerScript.onMessage() function is run in a separate thread, the + JavaScript file is evaluated in a context separate from the main QML engine. This means + that unlike an ordinary JavaScript file that is imported into QML, the \c script.js + in the above example cannot access the properties, methods or other attributes + of the QML item, nor can it access any context properties set on the QML object + through QDeclarativeContext. + + Additionally, there are restrictions on the types of values that can be passed to and + from the worker script. See the sendMessage() documentation for details. + + \sa {declarative/threading/workerscript}{WorkerScript example}, + {declarative/threading/threadedlistmodel}{Threaded ListModel example} +*/ +QDeclarativeWorkerScript::QDeclarativeWorkerScript(QObject *parent) +: QObject(parent), m_engine(0), m_scriptId(-1), m_componentComplete(true) +{ +} + +QDeclarativeWorkerScript::~QDeclarativeWorkerScript() +{ + if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId); +} + +/*! + \qmlproperty url WorkerScript::source + + This holds the url of the JavaScript file that implements the + \tt WorkerScript.onMessage() handler for threaded operations. +*/ +QUrl QDeclarativeWorkerScript::source() const +{ + return m_source; +} + +void QDeclarativeWorkerScript::setSource(const QUrl &source) +{ + if (m_source == source) + return; + + m_source = source; + + if (engine()) + m_engine->executeUrl(m_scriptId, m_source); + + emit sourceChanged(); +} + +/*! + \qmlmethod WorkerScript::sendMessage(jsobject message) + + Sends the given \a message to a worker script handler in another + thread. The other worker script handler can receive this message + through the onMessage() handler. + + The \c message object may only contain values of the following + types: + + \list + \o boolean, number, string + \o JavaScript objects and arrays + \o ListModel objects (any other type of QObject* is not allowed) + \endlist + + All objects and arrays are copied to the \c message. With the exception + of ListModel objects, any modifications by the other thread to an object + passed in \c message will not be reflected in the original object. +*/ +void QDeclarativeWorkerScript::sendMessage(const QScriptValue &message) +{ + if (!engine()) { + qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment"); + return; + } + + m_engine->sendMessage(m_scriptId, QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(message)); +} + +void QDeclarativeWorkerScript::classBegin() +{ + m_componentComplete = false; +} + +QDeclarativeWorkerScriptEngine *QDeclarativeWorkerScript::engine() +{ + if (m_engine) return m_engine; + if (m_componentComplete) { + QDeclarativeEngine *engine = qmlEngine(this); + if (!engine) { + qWarning("QDeclarativeWorkerScript: engine() called without qmlEngine() set"); + return 0; + } + + m_engine = QDeclarativeEnginePrivate::get(engine)->getWorkerScriptEngine(); + m_scriptId = m_engine->registerWorkerScript(this); + + if (m_source.isValid()) + m_engine->executeUrl(m_scriptId, m_source); + + return m_engine; + } + return 0; +} + +void QDeclarativeWorkerScript::componentComplete() +{ + m_componentComplete = true; + engine(); // Get it started now. +} + +/*! + \qmlsignal WorkerScript::onMessage(jsobject msg) + + This handler is called when a message \a msg is received from a worker + script in another thread through a call to sendMessage(). +*/ + +bool QDeclarativeWorkerScript::event(QEvent *event) +{ + if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) { + QDeclarativeEngine *engine = qmlEngine(this); + if (engine) { + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event); + QScriptValue value = + QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(workerEvent->data(), scriptEngine); + emit message(value); + } + return true; + } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) { + WorkerErrorEvent *workerEvent = static_cast<WorkerErrorEvent *>(event); + QDeclarativeEnginePrivate::warning(qmlEngine(this), workerEvent->error()); + return true; + } else { + return QObject::event(event); + } +} + +QT_END_NAMESPACE + +#include <qdeclarativeworkerscript.moc> + diff --git a/src/declarative/qml/qdeclarativeworkerscript_p.h b/src/declarative/qml/qdeclarativeworkerscript_p.h new file mode 100644 index 00000000..80482764 --- /dev/null +++ b/src/declarative/qml/qdeclarativeworkerscript_p.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEWORKERSCRIPT_P_H +#define QDECLARATIVEWORKERSCRIPT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdeclarative.h" +#include "qdeclarativeparserstatus.h" + +#include <QtCore/qthread.h> +#include <QtScript/qscriptvalue.h> +#include <QtCore/qurl.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeWorkerScript; +class QDeclarativeWorkerScriptEnginePrivate; +class QDeclarativeWorkerScriptEngine : public QThread +{ +Q_OBJECT +public: + QDeclarativeWorkerScriptEngine(QDeclarativeEngine *parent = 0); + virtual ~QDeclarativeWorkerScriptEngine(); + + int registerWorkerScript(QDeclarativeWorkerScript *); + void removeWorkerScript(int); + void executeUrl(int, const QUrl &); + void sendMessage(int, const QVariant &); + +protected: + virtual void run(); + +private: + QDeclarativeWorkerScriptEnginePrivate *d; +}; + +class Q_AUTOTEST_EXPORT QDeclarativeWorkerScript : public QObject, public QDeclarativeParserStatus +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + + Q_INTERFACES(QDeclarativeParserStatus) +public: + QDeclarativeWorkerScript(QObject *parent = 0); + virtual ~QDeclarativeWorkerScript(); + + QUrl source() const; + void setSource(const QUrl &); + +public slots: + void sendMessage(const QScriptValue &); + +signals: + void sourceChanged(); + void message(const QScriptValue &messageObject); + +protected: + virtual void classBegin(); + virtual void componentComplete(); + virtual bool event(QEvent *); + +private: + QDeclarativeWorkerScriptEngine *engine(); + QDeclarativeWorkerScriptEngine *m_engine; + int m_scriptId; + QUrl m_source; + bool m_componentComplete; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeWorkerScript) + +QT_END_HEADER + +#endif // QDECLARATIVEWORKERSCRIPT_P_H diff --git a/src/declarative/qml/qdeclarativexmlhttprequest.cpp b/src/declarative/qml/qdeclarativexmlhttprequest.cpp new file mode 100644 index 00000000..3348a7d2 --- /dev/null +++ b/src/declarative/qml/qdeclarativexmlhttprequest.cpp @@ -0,0 +1,1740 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativexmlhttprequest_p.h" + +#include "qdeclarativeengine.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativerefcount_p.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativeexpression_p.h" +#include "qdeclarativeglobal_p.h" + +#include <QtCore/qobject.h> +#include <QtScript/qscriptvalue.h> +#include <QtScript/qscriptcontext.h> +#include <QtScript/qscriptengine.h> +#include <QtNetwork/qnetworkreply.h> +#include <QtCore/qtextcodec.h> +#include <QtCore/qxmlstream.h> +#include <QtCore/qstack.h> +#include <QtCore/qdebug.h> + +#include <QtCore/QStringBuilder> + +#ifndef QT_NO_XMLSTREAMREADER + +// From DOM-Level-3-Core spec +// http://www.w3.org/TR/DOM-Level-3-Core/core.html +#define INDEX_SIZE_ERR 1 +#define DOMSTRING_SIZE_ERR 2 +#define HIERARCHY_REQUEST_ERR 3 +#define WRONG_DOCUMENT_ERR 4 +#define INVALID_CHARACTER_ERR 5 +#define NO_DATA_ALLOWED_ERR 6 +#define NO_MODIFICATION_ALLOWED_ERR 7 +#define NOT_FOUND_ERR 8 +#define NOT_SUPPORTED_ERR 9 +#define INUSE_ATTRIBUTE_ERR 10 +#define INVALID_STATE_ERR 11 +#define SYNTAX_ERR 12 +#define INVALID_MODIFICATION_ERR 13 +#define NAMESPACE_ERR 14 +#define INVALID_ACCESS_ERR 15 +#define VALIDATION_ERR 16 +#define TYPE_MISMATCH_ERR 17 + +#define THROW_DOM(error, desc) \ +{ \ + QScriptValue errorValue = context->throwError(QLatin1String(desc)); \ + errorValue.setProperty(QLatin1String("code"), error); \ + return errorValue; \ +} + +#define THROW_SYNTAX(desc) \ + return context->throwError(QScriptContext::SyntaxError, QLatin1String(desc)); +#define THROW_REFERENCE(desc) \ + return context->throwError(QScriptContext::ReferenceError, QLatin1String(desc)); + +#define D(arg) (arg)->release() +#define A(arg) (arg)->addref() + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP); + +class DocumentImpl; +class NodeImpl +{ +public: + NodeImpl() : type(Element), document(0), parent(0) {} + virtual ~NodeImpl() { + for (int ii = 0; ii < children.count(); ++ii) + delete children.at(ii); + for (int ii = 0; ii < attributes.count(); ++ii) + delete attributes.at(ii); + } + + // These numbers are copied from the Node IDL definition + enum Type { + Attr = 2, + CDATA = 4, + Comment = 8, + Document = 9, + DocumentFragment = 11, + DocumentType = 10, + Element = 1, + Entity = 6, + EntityReference = 5, + Notation = 12, + ProcessingInstruction = 7, + Text = 3 + }; + Type type; + + QString namespaceUri; + QString name; + + QString data; + + void addref(); + void release(); + + DocumentImpl *document; + NodeImpl *parent; + + QList<NodeImpl *> children; + QList<NodeImpl *> attributes; +}; + +class DocumentImpl : public QDeclarativeRefCount, public NodeImpl +{ +public: + DocumentImpl() : root(0) { type = Document; } + virtual ~DocumentImpl() { + if (root) delete root; + } + + QString version; + QString encoding; + bool isStandalone; + + NodeImpl *root; + + void addref() { QDeclarativeRefCount::addref(); } + void release() { QDeclarativeRefCount::release(); } +}; + +class NamedNodeMap +{ +public: + // JS API + static QScriptValue length(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); + static QScriptValue create(QScriptEngine *, NodeImpl *, QList<NodeImpl *> *); + + NamedNodeMap(); + NamedNodeMap(const NamedNodeMap &); + ~NamedNodeMap(); + bool isNull(); + + NodeImpl *d; + QList<NodeImpl *> *list; +private: + NamedNodeMap &operator=(const NamedNodeMap &); +}; + +class NamedNodeMapClass : public QScriptClass +{ +public: + NamedNodeMapClass(QScriptEngine *engine) : QScriptClass(engine) {} + + virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id); + virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id); +}; + +class NodeList +{ +public: + // JS API + static QScriptValue length(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); + static QScriptValue create(QScriptEngine *, NodeImpl *); + + NodeList(); + NodeList(const NodeList &); + ~NodeList(); + bool isNull(); + + NodeImpl *d; +private: + NodeList &operator=(const NodeList &); +}; + +class NodeListClass : public QScriptClass +{ +public: + NodeListClass(QScriptEngine *engine) : QScriptClass(engine) {} + virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id); + virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id); +}; + +class Node +{ +public: + // JS API + static QScriptValue nodeName(QScriptContext *context, QScriptEngine *engine); + static QScriptValue nodeValue(QScriptContext *context, QScriptEngine *engine); + static QScriptValue nodeType(QScriptContext *context, QScriptEngine *engine); + + static QScriptValue parentNode(QScriptContext *context, QScriptEngine *engine); + static QScriptValue childNodes(QScriptContext *context, QScriptEngine *engine); + static QScriptValue firstChild(QScriptContext *context, QScriptEngine *engine); + static QScriptValue lastChild(QScriptContext *context, QScriptEngine *engine); + static QScriptValue previousSibling(QScriptContext *context, QScriptEngine *engine); + static QScriptValue nextSibling(QScriptContext *context, QScriptEngine *engine); + static QScriptValue attributes(QScriptContext *context, QScriptEngine *engine); + + //static QScriptValue ownerDocument(QScriptContext *context, QScriptEngine *engine); + //static QScriptValue namespaceURI(QScriptContext *context, QScriptEngine *engine); + //static QScriptValue prefix(QScriptContext *context, QScriptEngine *engine); + //static QScriptValue localName(QScriptContext *context, QScriptEngine *engine); + //static QScriptValue baseURI(QScriptContext *context, QScriptEngine *engine); + //static QScriptValue textContent(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); + static QScriptValue create(QScriptEngine *, NodeImpl *); + + Node(); + Node(const Node &o); + ~Node(); + bool isNull() const; + + NodeImpl *d; + +private: + Node &operator=(const Node &); +}; + +class Element : public Node +{ +public: + // C++ API + static QScriptValue prototype(QScriptEngine *); +}; + +class Attr : public Node +{ +public: + // JS API + static QScriptValue name(QScriptContext *context, QScriptEngine *engine); + static QScriptValue specified(QScriptContext *context, QScriptEngine *engine); + static QScriptValue value(QScriptContext *context, QScriptEngine *engine); + static QScriptValue ownerElement(QScriptContext *context, QScriptEngine *engine); + static QScriptValue schemaTypeInfo(QScriptContext *context, QScriptEngine *engine); + static QScriptValue isId(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); +}; + +class CharacterData : public Node +{ +public: + // JS API + static QScriptValue length(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); +}; + +class Text : public CharacterData +{ +public: + // JS API + static QScriptValue isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine); + static QScriptValue wholeText(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); +}; + +class CDATA : public Text +{ +public: + // C++ API + static QScriptValue prototype(QScriptEngine *); +}; + +class Document : public Node +{ +public: + // JS API + static QScriptValue xmlVersion(QScriptContext *context, QScriptEngine *engine); + static QScriptValue xmlEncoding(QScriptContext *context, QScriptEngine *engine); + static QScriptValue xmlStandalone(QScriptContext *context, QScriptEngine *engine); + static QScriptValue documentElement(QScriptContext *context, QScriptEngine *engine); + + // C++ API + static QScriptValue prototype(QScriptEngine *); + static QScriptValue load(QScriptEngine *engine, const QByteArray &data); +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(Node) +Q_DECLARE_METATYPE(NodeList) +Q_DECLARE_METATYPE(NamedNodeMap) + +QT_BEGIN_NAMESPACE + +void NodeImpl::addref() +{ + A(document); +} + +void NodeImpl::release() +{ + D(document); +} + +QScriptValue Node::nodeName(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + switch (node.d->type) { + case NodeImpl::Document: + return QScriptValue(QLatin1String("#document")); + case NodeImpl::CDATA: + return QScriptValue(QLatin1String("#cdata-section")); + case NodeImpl::Text: + return QScriptValue(QLatin1String("#text")); + default: + return QScriptValue(node.d->name); + } +} + +QScriptValue Node::nodeValue(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (node.d->type == NodeImpl::Document || + node.d->type == NodeImpl::DocumentFragment || + node.d->type == NodeImpl::DocumentType || + node.d->type == NodeImpl::Element || + node.d->type == NodeImpl::Entity || + node.d->type == NodeImpl::EntityReference || + node.d->type == NodeImpl::Notation) + return engine->nullValue(); + + return QScriptValue(node.d->data); +} + +QScriptValue Node::nodeType(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + return QScriptValue(node.d->type); +} + +QScriptValue Node::parentNode(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (node.d->parent) return Node::create(engine, node.d->parent); + else return engine->nullValue(); +} + +QScriptValue Node::childNodes(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return NodeList::create(engine, node.d); +} + +QScriptValue Node::firstChild(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (node.d->children.isEmpty()) return engine->nullValue(); + else return Node::create(engine, node.d->children.first()); +} + +QScriptValue Node::lastChild(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (node.d->children.isEmpty()) return engine->nullValue(); + else return Node::create(engine, node.d->children.last()); +} + +QScriptValue Node::previousSibling(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (!node.d->parent) return engine->nullValue(); + + for (int ii = 0; ii < node.d->parent->children.count(); ++ii) { + if (node.d->parent->children.at(ii) == node.d) { + if (ii == 0) return engine->nullValue(); + else return Node::create(engine, node.d->parent->children.at(ii - 1)); + } + } + + return engine->nullValue(); +} + +QScriptValue Node::nextSibling(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (!node.d->parent) return engine->nullValue(); + + for (int ii = 0; ii < node.d->parent->children.count(); ++ii) { + if (node.d->parent->children.at(ii) == node.d) { + if ((ii + 1) == node.d->parent->children.count()) return engine->nullValue(); + else return Node::create(engine, node.d->parent->children.at(ii + 1)); + } + } + + return engine->nullValue(); +} + +QScriptValue Node::attributes(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + if (node.d->type != NodeImpl::Element) + return engine->nullValue(); + else + return NamedNodeMap::create(engine, node.d, &node.d->attributes); +} + +QScriptValue Node::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + + proto.setProperty(QLatin1String("nodeName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("nodeValue"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + proto.setProperty(QLatin1String("nodeType"), engine->newFunction(nodeType), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("parentNode"), engine->newFunction(parentNode), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("childNodes"), engine->newFunction(childNodes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("firstChild"), engine->newFunction(firstChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("lastChild"), engine->newFunction(lastChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("previousSibling"), engine->newFunction(previousSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("nextSibling"), engine->newFunction(nextSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("attributes"), engine->newFunction(attributes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue Node::create(QScriptEngine *engine, NodeImpl *data) +{ + QScriptValue instance = engine->newObject(); + + switch (data->type) { + case NodeImpl::Attr: + instance.setPrototype(Attr::prototype(engine)); + break; + case NodeImpl::Comment: + case NodeImpl::Document: + case NodeImpl::DocumentFragment: + case NodeImpl::DocumentType: + case NodeImpl::Entity: + case NodeImpl::EntityReference: + case NodeImpl::Notation: + case NodeImpl::ProcessingInstruction: + return QScriptValue(); + case NodeImpl::CDATA: + instance.setPrototype(CDATA::prototype(engine)); + break; + case NodeImpl::Text: + instance.setPrototype(Text::prototype(engine)); + break; + case NodeImpl::Element: + instance.setPrototype(Element::prototype(engine)); + break; + } + + Node node; + node.d = data; + if (data) A(data); + + return engine->newVariant(instance, QVariant::fromValue(node)); +} + +QScriptValue Element::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(Node::prototype(engine)); + + proto.setProperty(QLatin1String("tagName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue Attr::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(Node::prototype(engine)); + + proto.setProperty(QLatin1String("name"), engine->newFunction(name), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("value"), engine->newFunction(value), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("ownerElement"), engine->newFunction(ownerElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue Attr::name(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return QScriptValue(node.d->name); +} + +QScriptValue Attr::value(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return QScriptValue(node.d->data); +} + +QScriptValue Attr::ownerElement(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return Node::create(engine, node.d->parent); +} + +QScriptValue CharacterData::length(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return QScriptValue(node.d->data.length()); +} + +QScriptValue CharacterData::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(Node::prototype(engine)); + + proto.setProperty(QLatin1String("data"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue Text::isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return node.d->data.trimmed().isEmpty(); +} + +QScriptValue Text::wholeText(QScriptContext *context, QScriptEngine *engine) +{ + Node node = qscriptvalue_cast<Node>(context->thisObject()); + if (node.isNull()) return engine->undefinedValue(); + + return node.d->data; +} + +QScriptValue Text::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(CharacterData::prototype(engine)); + + proto.setProperty(QLatin1String("isElementContentWhitespace"), engine->newFunction(isElementContentWhitespace), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + proto.setProperty(QLatin1String("wholeText"), engine->newFunction(wholeText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue CDATA::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(Text::prototype(engine)); + return proto; +} + +QScriptValue Document::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + proto.setPrototype(Node::prototype(engine)); + + proto.setProperty(QLatin1String("xmlVersion"), engine->newFunction(xmlVersion), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + proto.setProperty(QLatin1String("xmlEncoding"), engine->newFunction(xmlEncoding), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + proto.setProperty(QLatin1String("xmlStandalone"), engine->newFunction(xmlStandalone), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + proto.setProperty(QLatin1String("documentElement"), engine->newFunction(documentElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue Document::load(QScriptEngine *engine, const QByteArray &data) +{ + Q_ASSERT(engine); + + DocumentImpl *document = 0; + QStack<NodeImpl *> nodeStack; + + QXmlStreamReader reader(data); + + while (!reader.atEnd()) { + switch (reader.readNext()) { + case QXmlStreamReader::NoToken: + break; + case QXmlStreamReader::Invalid: + break; + case QXmlStreamReader::StartDocument: + Q_ASSERT(!document); + document = new DocumentImpl; + document->document = document; + document->version = reader.documentVersion().toString(); + document->encoding = reader.documentEncoding().toString(); + document->isStandalone = reader.isStandaloneDocument(); + break; + case QXmlStreamReader::EndDocument: + break; + case QXmlStreamReader::StartElement: + { + Q_ASSERT(document); + NodeImpl *node = new NodeImpl; + node->document = document; + node->namespaceUri = reader.namespaceUri().toString(); + node->name = reader.name().toString(); + if (nodeStack.isEmpty()) { + document->root = node; + } else { + node->parent = nodeStack.top(); + node->parent->children.append(node); + } + nodeStack.append(node); + + foreach (const QXmlStreamAttribute &a, reader.attributes()) { + NodeImpl *attr = new NodeImpl; + attr->document = document; + attr->type = NodeImpl::Attr; + attr->namespaceUri = a.namespaceUri().toString(); + attr->name = a.name().toString(); + attr->data = a.value().toString(); + attr->parent = node; + node->attributes.append(attr); + } + } + break; + case QXmlStreamReader::EndElement: + nodeStack.pop(); + break; + case QXmlStreamReader::Characters: + { + NodeImpl *node = new NodeImpl; + node->document = document; + node->type = reader.isCDATA()?NodeImpl::CDATA:NodeImpl::Text; + node->parent = nodeStack.top(); + node->parent->children.append(node); + node->data = reader.text().toString(); + } + break; + case QXmlStreamReader::Comment: + break; + case QXmlStreamReader::DTD: + break; + case QXmlStreamReader::EntityReference: + break; + case QXmlStreamReader::ProcessingInstruction: + break; + } + } + + if (!document || reader.hasError()) { + if (document) D(document); + return engine->nullValue(); + } + + QScriptValue instance = engine->newObject(); + instance.setPrototype(Document::prototype(engine)); + Node documentNode; + documentNode.d = document; + return engine->newVariant(instance, QVariant::fromValue(documentNode)); +} + +Node::Node() +: d(0) +{ +} + +Node::Node(const Node &o) +: d(o.d) +{ + if (d) A(d); +} + +Node::~Node() +{ + if (d) D(d); +} + +bool Node::isNull() const +{ + return d == 0; +} + +QScriptValue NamedNodeMap::length(QScriptContext *context, QScriptEngine *engine) +{ + NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(context->thisObject().data()); + if (map.isNull()) return engine->undefinedValue(); + + return QScriptValue(map.list->count()); +} + +QScriptValue NamedNodeMap::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + + proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue NamedNodeMap::create(QScriptEngine *engine, NodeImpl *data, QList<NodeImpl *> *list) +{ + QScriptValue instance = engine->newObject(); + instance.setPrototype(NamedNodeMap::prototype(engine)); + + NamedNodeMap map; + map.d = data; + map.list = list; + if (data) A(data); + + instance.setData(engine->newVariant(QVariant::fromValue(map))); + + if (!QDeclarativeScriptEngine::get(engine)->namedNodeMapClass) + QDeclarativeScriptEngine::get(engine)->namedNodeMapClass= new NamedNodeMapClass(engine); + + instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->namedNodeMapClass); + + return instance; +} + +NamedNodeMap::NamedNodeMap() +: d(0), list(0) +{ +} + +NamedNodeMap::NamedNodeMap(const NamedNodeMap &o) +: d(o.d), list(o.list) +{ + if (d) A(d); +} + +NamedNodeMap::~NamedNodeMap() +{ + if (d) D(d); +} + +bool NamedNodeMap::isNull() +{ + return d == 0; +} + +QScriptValue NodeList::length(QScriptContext *context, QScriptEngine *engine) +{ + NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data()); + if (list.isNull()) return engine->undefinedValue(); + + return QScriptValue(list.d->children.count()); +} + +QScriptValue NodeList::prototype(QScriptEngine *engine) +{ + QScriptValue proto = engine->newObject(); + + proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + + return proto; +} + +QScriptValue NodeList::create(QScriptEngine *engine, NodeImpl *data) +{ + QScriptValue instance = engine->newObject(); + instance.setPrototype(NodeList::prototype(engine)); + + NodeList list; + list.d = data; + if (data) A(data); + + instance.setData(engine->newVariant(QVariant::fromValue(list))); + + if (!QDeclarativeScriptEngine::get(engine)->nodeListClass) + QDeclarativeScriptEngine::get(engine)->nodeListClass= new NodeListClass(engine); + + instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->nodeListClass); + + return instance; +} + +NodeList::NodeList() +: d(0) +{ +} + +NodeList::NodeList(const NodeList &o) +: d(o.d) +{ + if (d) A(d); +} + +NodeList::~NodeList() +{ + if (d) D(d); +} + +bool NodeList::isNull() +{ + return d == 0; +} + +NamedNodeMapClass::QueryFlags NamedNodeMapClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id) +{ + if (!(flags & HandlesReadAccess)) + return 0; + + NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data()); + Q_ASSERT(!map.isNull()); + + bool ok = false; + QString nameString = name.toString(); + uint index = nameString.toUInt(&ok); + if (ok) { + if ((uint)map.list->count() <= index) + return 0; + + *id = index; + return HandlesReadAccess; + } else { + for (int ii = 0; ii < map.list->count(); ++ii) { + if (map.list->at(ii) && map.list->at(ii)->name == nameString) { + *id = ii; + return HandlesReadAccess; + } + } + } + + return 0; +} + +QScriptValue NamedNodeMapClass::property(const QScriptValue &object, const QScriptString &, uint id) +{ + NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data()); + return Node::create(engine(), map.list->at(id)); +} + +NodeListClass::QueryFlags NodeListClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id) +{ + if (!(flags & HandlesReadAccess)) + return 0; + + bool ok = false; + uint index = name.toString().toUInt(&ok); + if (!ok) + return 0; + + NodeList list = qscriptvalue_cast<NodeList>(object.data()); + if (list.isNull() || (uint)list.d->children.count() <= index) + return 0; // ### I think we're meant to raise an exception + + *id = index; + return HandlesReadAccess; +} + +QScriptValue NodeListClass::property(const QScriptValue &object, const QScriptString &, uint id) +{ + NodeList list = qscriptvalue_cast<NodeList>(object.data()); + return Node::create(engine(), list.d->children.at(id)); +} + +QScriptValue Document::documentElement(QScriptContext *context, QScriptEngine *engine) +{ + Node document = qscriptvalue_cast<Node>(context->thisObject()); + if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); + + return Node::create(engine, static_cast<DocumentImpl *>(document.d)->root); +} + +QScriptValue Document::xmlStandalone(QScriptContext *context, QScriptEngine *engine) +{ + Node document = qscriptvalue_cast<Node>(context->thisObject()); + if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); + + return QScriptValue(static_cast<DocumentImpl *>(document.d)->isStandalone); +} + +QScriptValue Document::xmlVersion(QScriptContext *context, QScriptEngine *engine) +{ + Node document = qscriptvalue_cast<Node>(context->thisObject()); + if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); + + return QScriptValue(static_cast<DocumentImpl *>(document.d)->version); +} + +QScriptValue Document::xmlEncoding(QScriptContext *context, QScriptEngine *engine) +{ + Node document = qscriptvalue_cast<Node>(context->thisObject()); + if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue(); + + return QScriptValue(static_cast<DocumentImpl *>(document.d)->encoding); +} + +class QDeclarativeXMLHttpRequest : public QObject +{ +Q_OBJECT +public: + enum State { Unsent = 0, + Opened = 1, HeadersReceived = 2, + Loading = 3, Done = 4 }; + + QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager); + virtual ~QDeclarativeXMLHttpRequest(); + + bool sendFlag() const; + bool errorFlag() const; + quint32 readyState() const; + int replyStatus() const; + QString replyStatusText() const; + + QScriptValue open(QScriptValue *me, const QString &, const QUrl &); + + void addHeader(const QString &, const QString &); + QString header(const QString &name); + QString headers(); + QScriptValue send(QScriptValue *me, const QByteArray &); + QScriptValue abort(QScriptValue *me); + + QString responseBody(); + const QByteArray & rawResponseBody() const; + bool receivedXml() const; +private slots: + void downloadProgress(qint64); + void error(QNetworkReply::NetworkError); + void finished(); + +private: + void requestFromUrl(const QUrl &url); + + State m_state; + bool m_errorFlag; + bool m_sendFlag; + QString m_method; + QUrl m_url; + QByteArray m_responseEntityBody; + QByteArray m_data; + int m_redirectCount; + + typedef QPair<QByteArray, QByteArray> HeaderPair; + typedef QList<HeaderPair> HeadersList; + HeadersList m_headersList; + void fillHeadersList(); + + bool m_gotXml; + QByteArray m_mime; + QByteArray m_charset; + QTextCodec *m_textCodec; +#ifndef QT_NO_TEXTCODEC + QTextCodec* findTextCodec() const; +#endif + void readEncoding(); + + QScriptValue m_me; // Set to the data object while a send() is ongoing (to access the callback) + + QScriptValue dispatchCallback(QScriptValue *me); + void printError(const QScriptValue&); + + int m_status; + QString m_statusText; + QNetworkRequest m_request; + QDeclarativeGuard<QNetworkReply> m_network; + void destroyNetwork(); + + QNetworkAccessManager *m_nam; + QNetworkAccessManager *networkAccessManager() { return m_nam; } +}; + +QDeclarativeXMLHttpRequest::QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager) +: m_state(Unsent), m_errorFlag(false), m_sendFlag(false), + m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager) +{ +} + +QDeclarativeXMLHttpRequest::~QDeclarativeXMLHttpRequest() +{ + destroyNetwork(); +} + +bool QDeclarativeXMLHttpRequest::sendFlag() const +{ + return m_sendFlag; +} + +bool QDeclarativeXMLHttpRequest::errorFlag() const +{ + return m_errorFlag; +} + +quint32 QDeclarativeXMLHttpRequest::readyState() const +{ + return m_state; +} + +int QDeclarativeXMLHttpRequest::replyStatus() const +{ + return m_status; +} + +QString QDeclarativeXMLHttpRequest::replyStatusText() const +{ + return m_statusText; +} + +QScriptValue QDeclarativeXMLHttpRequest::open(QScriptValue *me, const QString &method, const QUrl &url) +{ + destroyNetwork(); + m_sendFlag = false; + m_errorFlag = false; + m_responseEntityBody = QByteArray(); + m_method = method; + m_url = url; + m_state = Opened; + return dispatchCallback(me); +} + +void QDeclarativeXMLHttpRequest::addHeader(const QString &name, const QString &value) +{ + QByteArray utfname = name.toUtf8(); + + if (m_request.hasRawHeader(utfname)) { + m_request.setRawHeader(utfname, m_request.rawHeader(utfname) + ',' + value.toUtf8()); + } else { + m_request.setRawHeader(utfname, value.toUtf8()); + } +} + +QString QDeclarativeXMLHttpRequest::header(const QString &name) +{ + QByteArray utfname = name.toLower().toUtf8(); + + foreach (const HeaderPair &header, m_headersList) { + if (header.first == utfname) + return QString::fromUtf8(header.second); + } + return QString(); +} + +QString QDeclarativeXMLHttpRequest::headers() +{ + QString ret; + + foreach (const HeaderPair &header, m_headersList) { + if (ret.length()) + ret.append(QLatin1String("\r\n")); + ret = ret % QString::fromUtf8(header.first) % QLatin1String(": ") + % QString::fromUtf8(header.second); + } + return ret; +} + +void QDeclarativeXMLHttpRequest::fillHeadersList() +{ + QList<QByteArray> headerList = m_network->rawHeaderList(); + + m_headersList.clear(); + foreach (const QByteArray &header, headerList) { + HeaderPair pair (header.toLower(), m_network->rawHeader(header)); + if (pair.first == "set-cookie" || + pair.first == "set-cookie2") + continue; + + m_headersList << pair; + } +} + +void QDeclarativeXMLHttpRequest::requestFromUrl(const QUrl &url) +{ + QNetworkRequest request = m_request; + request.setUrl(url); + if(m_method == QLatin1String("POST") || + m_method == QLatin1String("PUT")) { + QVariant var = request.header(QNetworkRequest::ContentTypeHeader); + if (var.isValid()) { + QString str = var.toString(); + int charsetIdx = str.indexOf(QLatin1String("charset=")); + if (charsetIdx == -1) { + // No charset - append + if (!str.isEmpty()) str.append(QLatin1Char(';')); + str.append(QLatin1String("charset=UTF-8")); + } else { + charsetIdx += 8; + int n = 0; + int semiColon = str.indexOf(QLatin1Char(';'), charsetIdx); + if (semiColon == -1) { + n = str.length() - charsetIdx; + } else { + n = semiColon - charsetIdx; + } + + str.replace(charsetIdx, n, QLatin1String("UTF-8")); + } + request.setHeader(QNetworkRequest::ContentTypeHeader, str); + } else { + request.setHeader(QNetworkRequest::ContentTypeHeader, + QLatin1String("text/plain;charset=UTF-8")); + } + } + + if (xhrDump()) { + qWarning().nospace() << "XMLHttpRequest: " << qPrintable(m_method) << " " << qPrintable(url.toString()); + if (!m_data.isEmpty()) { + qWarning().nospace() << " " + << qPrintable(QString::fromUtf8(m_data)); + } + } + + if (m_method == QLatin1String("GET")) + m_network = networkAccessManager()->get(request); + else if (m_method == QLatin1String("HEAD")) + m_network = networkAccessManager()->head(request); + else if(m_method == QLatin1String("POST")) + m_network = networkAccessManager()->post(request, m_data); + else if(m_method == QLatin1String("PUT")) + m_network = networkAccessManager()->put(request, m_data); + + QObject::connect(m_network, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(downloadProgress(qint64))); + QObject::connect(m_network, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(error(QNetworkReply::NetworkError))); + QObject::connect(m_network, SIGNAL(finished()), + this, SLOT(finished())); +} + +QScriptValue QDeclarativeXMLHttpRequest::send(QScriptValue *me, const QByteArray &data) +{ + m_errorFlag = false; + m_sendFlag = true; + m_redirectCount = 0; + m_data = data; + m_me = *me; + + requestFromUrl(m_url); + + return QScriptValue(); +} + +QScriptValue QDeclarativeXMLHttpRequest::abort(QScriptValue *me) +{ + destroyNetwork(); + m_responseEntityBody = QByteArray(); + m_errorFlag = true; + m_request = QNetworkRequest(); + + if (!(m_state == Unsent || + (m_state == Opened && !m_sendFlag) || + m_state == Done)) { + + m_state = Done; + m_sendFlag = false; + QScriptValue cbv = dispatchCallback(me); + if (cbv.isError()) return cbv; + } + + m_state = Unsent; + return QScriptValue(); +} + +void QDeclarativeXMLHttpRequest::downloadProgress(qint64 bytes) +{ + Q_UNUSED(bytes) + m_status = + m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + m_statusText = + QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray()); + + // ### We assume if this is called the headers are now available + if (m_state < HeadersReceived) { + m_state = HeadersReceived; + fillHeadersList (); + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + } + + bool wasEmpty = m_responseEntityBody.isEmpty(); + m_responseEntityBody.append(m_network->readAll()); + if (wasEmpty && !m_responseEntityBody.isEmpty()) { + m_state = Loading; + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + } +} + +void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error) +{ + Q_UNUSED(error) + m_status = + m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + m_statusText = + QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray()); + + m_responseEntityBody = QByteArray(); + + m_request = QNetworkRequest(); + m_data.clear(); + destroyNetwork(); + + if (error == QNetworkReply::ContentAccessDenied || + error == QNetworkReply::ContentOperationNotPermittedError || + error == QNetworkReply::ContentNotFoundError || + error == QNetworkReply::AuthenticationRequiredError || + error == QNetworkReply::ContentReSendError) { + m_state = Loading; + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + } else { + m_errorFlag = true; + } + + m_state = Done; + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); +} + +#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15 +void QDeclarativeXMLHttpRequest::finished() +{ + m_redirectCount++; + if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) { + QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute); + if (redirect.isValid()) { + QUrl url = m_network->url().resolved(redirect.toUrl()); + destroyNetwork(); + requestFromUrl(url); + return; + } + } + + m_status = + m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + m_statusText = + QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray()); + + if (m_state < HeadersReceived) { + m_state = HeadersReceived; + fillHeadersList (); + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + } + m_responseEntityBody.append(m_network->readAll()); + readEncoding(); + + if (xhrDump()) { + qWarning().nospace() << "XMLHttpRequest: RESPONSE " << qPrintable(m_url.toString()); + if (!m_responseEntityBody.isEmpty()) { + qWarning().nospace() << " " + << qPrintable(QString::fromUtf8(m_responseEntityBody)); + } + } + + + m_data.clear(); + destroyNetwork(); + if (m_state < Loading) { + m_state = Loading; + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + } + m_state = Done; + QScriptValue cbv = dispatchCallback(&m_me); + if (cbv.isError()) printError(cbv); + + m_me = QScriptValue(); +} + + +void QDeclarativeXMLHttpRequest::readEncoding() +{ + foreach (const HeaderPair &header, m_headersList) { + if (header.first == "content-type") { + int separatorIdx = header.second.indexOf(';'); + if (separatorIdx == -1) { + m_mime == header.second; + } else { + m_mime = header.second.mid(0, separatorIdx); + int charsetIdx = header.second.indexOf("charset="); + if (charsetIdx != -1) { + charsetIdx += 8; + separatorIdx = header.second.indexOf(';', charsetIdx); + m_charset = header.second.mid(charsetIdx, separatorIdx >= 0 ? separatorIdx : header.second.length()); + } + } + break; + } + } + + if (m_mime.isEmpty() || m_mime == "text/xml" || m_mime == "application/xml" || m_mime.endsWith("+xml")) + m_gotXml = true; +} + +bool QDeclarativeXMLHttpRequest::receivedXml() const +{ + return m_gotXml; +} + + +#ifndef QT_NO_TEXTCODEC +QTextCodec* QDeclarativeXMLHttpRequest::findTextCodec() const +{ + QTextCodec *codec = 0; + + if (!m_charset.isEmpty()) + codec = QTextCodec::codecForName(m_charset); + + if (!codec && m_gotXml) { + QXmlStreamReader reader(m_responseEntityBody); + reader.readNext(); + codec = QTextCodec::codecForName(reader.documentEncoding().toString().toUtf8()); + } + + if (!codec && m_mime == "text/html") + codec = QTextCodec::codecForHtml(m_responseEntityBody, 0); + + if (!codec) + codec = QTextCodec::codecForUtfText(m_responseEntityBody, 0); + + if (!codec) + codec = QTextCodec::codecForName("UTF-8"); + return codec; +} +#endif + + +QString QDeclarativeXMLHttpRequest::responseBody() +{ +#ifndef QT_NO_TEXTCODEC + if (!m_textCodec) + m_textCodec = findTextCodec(); + if (m_textCodec) + return m_textCodec->toUnicode(m_responseEntityBody); +#endif + + return QString::fromUtf8(m_responseEntityBody); +} + +const QByteArray &QDeclarativeXMLHttpRequest::rawResponseBody() const +{ + return m_responseEntityBody; +} + +QScriptValue QDeclarativeXMLHttpRequest::dispatchCallback(QScriptValue *me) +{ + QScriptValue v = me->property(QLatin1String("callback")); + return v.call(); +} + +void QDeclarativeXMLHttpRequest::printError(const QScriptValue& sv) +{ + QDeclarativeError error; + QDeclarativeExpressionPrivate::exceptionToError(sv.engine(), error); + QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate::get(sv.engine()), error); +} + +void QDeclarativeXMLHttpRequest::destroyNetwork() +{ + if (m_network) { + m_network->disconnect(); + m_network->deleteLater(); + m_network = 0; + } +} + +// XMLHttpRequest methods +static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngine *engine) +{ + QScriptValue dataObject = context->thisObject().data(); + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (context->argumentCount() < 2 || context->argumentCount() > 5) + THROW_DOM(SYNTAX_ERR, "Incorrect argument count"); + + // Argument 0 - Method + QString method = context->argument(0).toString().toUpper(); + if (method != QLatin1String("GET") && + method != QLatin1String("PUT") && + method != QLatin1String("HEAD") && + method != QLatin1String("POST")) + THROW_DOM(SYNTAX_ERR, "Unsupported HTTP method type"); + + + // Argument 1 - URL + QUrl url = QUrl::fromEncoded(context->argument(1).toString().toUtf8()); + + if (url.isRelative()) { + url = QDeclarativeScriptEngine::get(engine)->resolvedUrl(context,url); + } + + // Argument 2 - async (optional) + if (context->argumentCount() > 2 && !context->argument(2).toBoolean()) + THROW_DOM(NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported"); + + + // Argument 3/4 - user/pass (optional) + QString username, password; + if (context->argumentCount() > 3) + username = context->argument(3).toString(); + if (context->argumentCount() > 4) + password = context->argument(4).toString(); + + + // Clear the fragment (if any) + url.setFragment(QString()); + // Set username/password + if (!username.isNull()) url.setUserName(username); + if (!password.isNull()) url.setPassword(password); + + return request->open(&dataObject, method, url); +} + +static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, QScriptEngine *engine) +{ + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (context->argumentCount() != 2) + THROW_DOM(SYNTAX_ERR, "Incorrect argument count"); + + + if (request->readyState() != QDeclarativeXMLHttpRequest::Opened || + request->sendFlag()) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + + QString name = context->argument(0).toString(); + QString value = context->argument(1).toString(); + + // ### Check that name and value are well formed + + QString nameUpper = name.toUpper(); + if (nameUpper == QLatin1String("ACCEPT-CHARSET") || + nameUpper == QLatin1String("ACCEPT-ENCODING") || + nameUpper == QLatin1String("CONNECTION") || + nameUpper == QLatin1String("CONTENT-LENGTH") || + nameUpper == QLatin1String("COOKIE") || + nameUpper == QLatin1String("COOKIE2") || + nameUpper == QLatin1String("CONTENT-TRANSFER-ENCODING") || + nameUpper == QLatin1String("DATE") || + nameUpper == QLatin1String("EXPECT") || + nameUpper == QLatin1String("HOST") || + nameUpper == QLatin1String("KEEP-ALIVE") || + nameUpper == QLatin1String("REFERER") || + nameUpper == QLatin1String("TE") || + nameUpper == QLatin1String("TRAILER") || + nameUpper == QLatin1String("TRANSFER-ENCODING") || + nameUpper == QLatin1String("UPGRADE") || + nameUpper == QLatin1String("USER-AGENT") || + nameUpper == QLatin1String("VIA") || + nameUpper.startsWith(QLatin1String("PROXY-")) || + nameUpper.startsWith(QLatin1String("SEC-"))) + return engine->undefinedValue(); + + request->addHeader(nameUpper, value); + + return engine->undefinedValue(); +} + +static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngine *) +{ + QScriptValue dataObject = context->thisObject().data(); + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (request->readyState() != QDeclarativeXMLHttpRequest::Opened) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + if (request->sendFlag()) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + QByteArray data; + if (context->argumentCount() > 0) + data = context->argument(0).toString().toUtf8(); + + return request->send(&dataObject, data); +} + +static QScriptValue qmlxmlhttprequest_abort(QScriptContext *context, QScriptEngine *) +{ + QScriptValue dataObject = context->thisObject().data(); + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + return request->abort(&dataObject); +} + +static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (context->argumentCount() != 1) + THROW_DOM(SYNTAX_ERR, "Incorrect argument count"); + + if (request->readyState() != QDeclarativeXMLHttpRequest::Loading && + request->readyState() != QDeclarativeXMLHttpRequest::Done && + request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + QString headerName = context->argument(0).toString(); + + return QScriptValue(request->header(headerName)); +} + +static QScriptValue qmlxmlhttprequest_getAllResponseHeaders(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (context->argumentCount() != 0) + THROW_DOM(SYNTAX_ERR, "Incorrect argument count"); + + if (request->readyState() != QDeclarativeXMLHttpRequest::Loading && + request->readyState() != QDeclarativeXMLHttpRequest::Done && + request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + return QScriptValue(request->headers()); +} + +// XMLHttpRequest properties +static QScriptValue qmlxmlhttprequest_readyState(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + return QScriptValue(request->readyState()); +} + +static QScriptValue qmlxmlhttprequest_status(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent || + request->readyState() == QDeclarativeXMLHttpRequest::Opened) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + if (request->errorFlag()) + return QScriptValue(0); + else + return QScriptValue(request->replyStatus()); +} + +static QScriptValue qmlxmlhttprequest_statusText(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent || + request->readyState() == QDeclarativeXMLHttpRequest::Opened) + THROW_DOM(INVALID_STATE_ERR, "Invalid state"); + + if (request->errorFlag()) + return QScriptValue(0); + else + return QScriptValue(request->replyStatusText()); +} + +static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine) + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (request->readyState() != QDeclarativeXMLHttpRequest::Loading && + request->readyState() != QDeclarativeXMLHttpRequest::Done) + return QScriptValue(QString()); + else + return QScriptValue(request->responseBody()); +} + +static QScriptValue qmlxmlhttprequest_responseXML(QScriptContext *context, QScriptEngine *engine) +{ + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (!request->receivedXml() || + (request->readyState() != QDeclarativeXMLHttpRequest::Loading && + request->readyState() != QDeclarativeXMLHttpRequest::Done)) + return engine->nullValue(); + else + return Document::load(engine, request->rawResponseBody()); +} + +static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context, QScriptEngine *engine) +{ + Q_UNUSED(engine); + QScriptValue dataObject = context->thisObject().data(); + QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject()); + if (!request) + THROW_REFERENCE("Not an XMLHttpRequest object"); + + if (context->argumentCount()) { + QScriptValue v = context->argument(0); + dataObject.setProperty(QLatin1String("callback"), v); + return v; + } else { + return dataObject.property(QLatin1String("callback")); + } +} + +// Constructor +static QScriptValue qmlxmlhttprequest_new(QScriptContext *context, QScriptEngine *engine) +{ + if (context->isCalledAsConstructor()) { + context->thisObject().setData(engine->newQObject(new QDeclarativeXMLHttpRequest(QDeclarativeScriptEngine::get(engine)->networkAccessManager()), QScriptEngine::ScriptOwnership)); + } + return engine->undefinedValue(); +} + +void qt_add_qmlxmlhttprequest(QScriptEngine *engine) +{ + QScriptValue prototype = engine->newObject(); + + // Methods + prototype.setProperty(QLatin1String("open"), engine->newFunction(qmlxmlhttprequest_open, 2)); + prototype.setProperty(QLatin1String("setRequestHeader"), engine->newFunction(qmlxmlhttprequest_setRequestHeader, 2)); + prototype.setProperty(QLatin1String("send"), engine->newFunction(qmlxmlhttprequest_send)); + prototype.setProperty(QLatin1String("abort"), engine->newFunction(qmlxmlhttprequest_abort)); + prototype.setProperty(QLatin1String("getResponseHeader"), engine->newFunction(qmlxmlhttprequest_getResponseHeader, 1)); + prototype.setProperty(QLatin1String("getAllResponseHeaders"), engine->newFunction(qmlxmlhttprequest_getAllResponseHeaders)); + + // Read-only properties + prototype.setProperty(QLatin1String("readyState"), engine->newFunction(qmlxmlhttprequest_readyState), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("status"), engine->newFunction(qmlxmlhttprequest_status), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("statusText"), engine->newFunction(qmlxmlhttprequest_statusText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("responseText"), engine->newFunction(qmlxmlhttprequest_responseText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("responseXML"), engine->newFunction(qmlxmlhttprequest_responseXML), QScriptValue::ReadOnly | QScriptValue::PropertyGetter); + prototype.setProperty(QLatin1String("onreadystatechange"), engine->newFunction(qmlxmlhttprequest_onreadystatechange), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); + + // State values + prototype.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + prototype.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + + // Constructor + QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new, prototype); + constructor.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + constructor.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + constructor.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + constructor.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + constructor.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + engine->globalObject().setProperty(QLatin1String("XMLHttpRequest"), constructor); + + // DOM Exception + QScriptValue domExceptionPrototype = engine->newObject(); + domExceptionPrototype.setProperty(QLatin1String("INDEX_SIZE_ERR"), INDEX_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("DOMSTRING_SIZE_ERR"), DOMSTRING_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("HIERARCHY_REQUEST_ERR"), HIERARCHY_REQUEST_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("WRONG_DOCUMENT_ERR"), WRONG_DOCUMENT_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("INVALID_CHARACTER_ERR"), INVALID_CHARACTER_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("NO_DATA_ALLOWED_ERR"), NO_DATA_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("NO_MODIFICATION_ALLOWED_ERR"), NO_MODIFICATION_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("NOT_FOUND_ERR"), NOT_FOUND_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("NOT_SUPPORTED_ERR"), NOT_SUPPORTED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("INUSE_ATTRIBUTE_ERR"), INUSE_ATTRIBUTE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("INVALID_STATE_ERR"), INVALID_STATE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("SYNTAX_ERR"), SYNTAX_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("INVALID_MODIFICATION_ERR"), INVALID_MODIFICATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("NAMESPACE_ERR"), NAMESPACE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("INVALID_ACCESS_ERR"), INVALID_ACCESS_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("VALIDATION_ERR"), VALIDATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + domExceptionPrototype.setProperty(QLatin1String("TYPE_MISMATCH_ERR"), TYPE_MISMATCH_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); + + engine->globalObject().setProperty(QLatin1String("DOMException"), domExceptionPrototype); +} + +QT_END_NAMESPACE + +#endif // QT_NO_XMLSTREAMREADER + +#include <qdeclarativexmlhttprequest.moc> diff --git a/src/declarative/qml/qdeclarativexmlhttprequest_p.h b/src/declarative/qml/qdeclarativexmlhttprequest_p.h new file mode 100644 index 00000000..c7d3ebb6 --- /dev/null +++ b/src/declarative/qml/qdeclarativexmlhttprequest_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEXMLHTTPREQUEST_P_H +#define QDECLARATIVEXMLHTTPREQUEST_P_H + +#include <QtScript/qscriptengine.h> +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +#ifndef QT_NO_XMLSTREAMREADER + +QT_BEGIN_NAMESPACE + +class QScriptEngine; +void qt_add_qmlxmlhttprequest(QScriptEngine *engine); + +QT_END_NAMESPACE + +#endif // QT_NO_XMLSTREAMREADER + +#endif // QDECLARATIVEXMLHTTPREQUEST_P_H + diff --git a/src/declarative/qml/qmetaobjectbuilder.cpp b/src/declarative/qml/qmetaobjectbuilder.cpp new file mode 100644 index 00000000..0648914f --- /dev/null +++ b/src/declarative/qml/qmetaobjectbuilder.cpp @@ -0,0 +1,2601 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qmetaobjectbuilder_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QMetaObjectBuilder + \internal + \brief The QMetaObjectBuilder class supports building QMetaObject objects at runtime. + +*/ + +/*! + \enum QMetaObjectBuilder::AddMember + This enum defines which members of QMetaObject should be copied by QMetaObjectBuilder::addMetaObject() + + \value ClassName Add the class name. + \value SuperClass Add the super class. + \value Methods Add methods that aren't signals or slots. + \value Signals Add signals. + \value Slots Add slots. + \value Constructors Add constructors. + \value Properties Add properties. + \value Enumerators Add enumerators. + \value ClassInfos Add items of class information. + \value RelatedMetaObjects Add related meta objects. + \value StaticMetacall Add the static metacall function. + \value PublicMethods Add public methods (ignored for signals). + \value ProtectedMethods Add protected methods (ignored for signals). + \value PrivateMethods All private methods (ignored for signals). + \value AllMembers Add all members. + \value AllPrimaryMembers Add everything except the class name, super class, and static metacall function. +*/ + +// copied from moc's generator.cpp +uint qvariant_nameToType(const char* name) +{ + if (!name) + return 0; + + if (strcmp(name, "QVariant") == 0) + return 0xffffffff; + if (strcmp(name, "QCString") == 0) + return QMetaType::QByteArray; + if (strcmp(name, "Q_LLONG") == 0) + return QMetaType::LongLong; + if (strcmp(name, "Q_ULLONG") == 0) + return QMetaType::ULongLong; + if (strcmp(name, "QIconSet") == 0) + return QMetaType::QIcon; + + uint tp = QMetaType::type(name); + return tp < QMetaType::User ? tp : 0; +} + +/* + Returns true if the type is a QVariant types. +*/ +bool isVariantType(const char* type) +{ + return qvariant_nameToType(type) != 0; +} + +// copied from qmetaobject_p.h +// do not touch without touching the moc as well +enum PropertyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resettable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, +// Override = 0x00000200, + Constant = 0x00000400, + Final = 0x00000800, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000, + User = 0x00100000, + ResolveUser = 0x00200000, + Notify = 0x00400000, + Revisioned = 0x00800000 +}; + +enum MethodFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + AccessMask = 0x03, //mask + + MethodMethod = 0x00, + MethodSignal = 0x04, + MethodSlot = 0x08, + MethodConstructor = 0x0c, + MethodTypeMask = 0x0c, + + MethodCompatibility = 0x10, + MethodCloned = 0x20, + MethodScriptable = 0x40, + MethodRevisioned = 0x80 +}; + +struct QMetaObjectPrivate +{ + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + int propertyCount, propertyData; + int enumeratorCount, enumeratorData; + int constructorCount, constructorData; + int flags; +}; + +static inline const QMetaObjectPrivate *priv(const uint* data) +{ return reinterpret_cast<const QMetaObjectPrivate*>(data); } +// end of copied lines from qmetaobject.cpp + +class QMetaMethodBuilderPrivate +{ +public: + QMetaMethodBuilderPrivate + (QMetaMethod::MethodType _methodType, + const QByteArray& _signature, + const QByteArray& _returnType = QByteArray(), + QMetaMethod::Access _access = QMetaMethod::Public) + : signature(QMetaObject::normalizedSignature(_signature.constData())), + returnType(QMetaObject::normalizedType(_returnType)), + attributes(((int)_access) | (((int)_methodType) << 2)) + { + } + + QByteArray signature; + QByteArray returnType; + QList<QByteArray> parameterNames; + QByteArray tag; + int attributes; + + QMetaMethod::MethodType methodType() const + { + return (QMetaMethod::MethodType)((attributes & MethodTypeMask) >> 2); + } + + QMetaMethod::Access access() const + { + return (QMetaMethod::Access)(attributes & AccessMask); + } + + void setAccess(QMetaMethod::Access value) + { + attributes = ((attributes & ~AccessMask) | (int)value); + } +}; + +class QMetaPropertyBuilderPrivate +{ +public: + QMetaPropertyBuilderPrivate + (const QByteArray& _name, const QByteArray& _type, int notifierIdx=-1) + : name(_name), + type(QMetaObject::normalizedType(_type.constData())), + flags(Readable | Writable | Scriptable), notifySignal(-1) + { + if (notifierIdx >= 0) { + flags |= Notify; + notifySignal = notifierIdx; + } + } + + QByteArray name; + QByteArray type; + int flags; + int notifySignal; + + bool flag(int f) const + { + return ((flags & f) != 0); + } + + void setFlag(int f, bool value) + { + if (value) + flags |= f; + else + flags &= ~f; + } +}; + +class QMetaEnumBuilderPrivate +{ +public: + QMetaEnumBuilderPrivate(const QByteArray& _name) + : name(_name), isFlag(false) + { + } + + QByteArray name; + bool isFlag; + QList<QByteArray> keys; + QList<int> values; +}; + +class QMetaObjectBuilderPrivate +{ +public: + QMetaObjectBuilderPrivate() + : flags(0) + { + superClass = &QObject::staticMetaObject; + staticMetacallFunction = 0; + } + + QByteArray className; + const QMetaObject *superClass; + QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction; + QList<QMetaMethodBuilderPrivate> methods; + QList<QMetaMethodBuilderPrivate> constructors; + QList<QMetaPropertyBuilderPrivate> properties; + QList<QByteArray> classInfoNames; + QList<QByteArray> classInfoValues; + QList<QMetaEnumBuilderPrivate> enumerators; +#ifdef Q_NO_DATA_RELOCATION + QList<QMetaObjectAccessor> relatedMetaObjects; +#else + QList<const QMetaObject *> relatedMetaObjects; +#endif + int flags; +}; + +/*! + Constructs a new QMetaObjectBuilder. +*/ +QMetaObjectBuilder::QMetaObjectBuilder() +{ + d = new QMetaObjectBuilderPrivate(); +} + +/*! + Constructs a new QMetaObjectBuilder which is a copy of the + meta object information in \a prototype. Note: the super class + contents for \a prototype are not copied, only the immediate + class that is defined by \a prototype. + + The \a members parameter indicates which members of \a prototype + should be added. The default is AllMembers. + + \sa addMetaObject() +*/ +QMetaObjectBuilder::QMetaObjectBuilder + (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members) +{ + d = new QMetaObjectBuilderPrivate(); + addMetaObject(prototype, members); +} + +/*! + Destroys this meta object builder. +*/ +QMetaObjectBuilder::~QMetaObjectBuilder() +{ + delete d; +} + +/*! + Returns the name of the class being constructed by this + meta object builder. The default value is an empty QByteArray. + + \sa setClassName(), superClass() +*/ +QByteArray QMetaObjectBuilder::className() const +{ + return d->className; +} + +/*! + Sets the \a name of the class being constructed by this + meta object builder. + + \sa className(), setSuperClass() +*/ +void QMetaObjectBuilder::setClassName(const QByteArray& name) +{ + d->className = name; +} + +/*! + Returns the superclass meta object of the class being constructed + by this meta object builder. The default value is the meta object + for QObject. + + \sa setSuperClass(), className() +*/ +const QMetaObject *QMetaObjectBuilder::superClass() const +{ + return d->superClass; +} + +/*! + Sets the superclass meta object of the class being constructed + by this meta object builder to \a meta. The \a meta parameter + must not be null. + + \sa superClass(), setClassName() +*/ +void QMetaObjectBuilder::setSuperClass(const QMetaObject *meta) +{ + Q_ASSERT(meta); + d->superClass = meta; +} + +/*! + Returns the flags of the class being constructed by this meta object + builder. + + \sa setFlags() +*/ +QMetaObjectBuilder::MetaObjectFlags QMetaObjectBuilder::flags() const +{ + return (QMetaObjectBuilder::MetaObjectFlags)d->flags; +} + +/*! + Sets the \a flags of the class being constructed by this meta object + builder. + + \sa flags() +*/ +void QMetaObjectBuilder::setFlags(MetaObjectFlags flags) +{ + d->flags = flags; +} + +/*! + Returns the number of methods in this class, excluding the number + of methods in the base class. These include signals and slots + as well as normal member functions. + + \sa addMethod(), method(), removeMethod(), indexOfMethod() +*/ +int QMetaObjectBuilder::methodCount() const +{ + return d->methods.size(); +} + +/*! + Returns the number of constructors in this class. + + \sa addConstructor(), constructor(), removeConstructor(), indexOfConstructor() +*/ +int QMetaObjectBuilder::constructorCount() const +{ + return d->constructors.size(); +} + +/*! + Returns the number of properties in this class, excluding the number + of properties in the base class. + + \sa addProperty(), property(), removeProperty(), indexOfProperty() +*/ +int QMetaObjectBuilder::propertyCount() const +{ + return d->properties.size(); +} + +/*! + Returns the number of enumerators in this class, excluding the + number of enumerators in the base class. + + \sa addEnumerator(), enumerator(), removeEnumerator() + \sa indexOfEnumerator() +*/ +int QMetaObjectBuilder::enumeratorCount() const +{ + return d->enumerators.size(); +} + +/*! + Returns the number of items of class information in this class, + exclusing the number of items of class information in the base class. + + \sa addClassInfo(), classInfoName(), classInfoValue(), removeClassInfo() + \sa indexOfClassInfo() +*/ +int QMetaObjectBuilder::classInfoCount() const +{ + return d->classInfoNames.size(); +} + +/*! + Returns the number of related meta objects that are associated + with this class. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa addRelatedMetaObject(), relatedMetaObject() + \sa removeRelatedMetaObject() +*/ +int QMetaObjectBuilder::relatedMetaObjectCount() const +{ + return d->relatedMetaObjects.size(); +} + +/*! + Adds a new public method to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the method. The \a signature will be normalized before it is + added to the class. + + \sa method(), methodCount(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QByteArray& signature) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Method, signature)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new public method to this class with the specified + \a signature and \a returnType. Returns an object that can be + used to adjust the other attributes of the method. The \a signature + and \a returnType will be normalized before they are added to + the class. If \a returnType is empty, then it indicates that + the method has \c{void} as its return type. + + \sa method(), methodCount(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addMethod + (const QByteArray& signature, const QByteArray& returnType) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate + (QMetaMethod::Method, signature, returnType)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new public method to this class that has the same information as + \a prototype. This is used to clone the methods of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the method. + + This function will detect if \a prototype is an ordinary method, + signal, slot, or constructor and act accordingly. + + \sa method(), methodCount(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QMetaMethod& prototype) +{ + QMetaMethodBuilder method; + if (prototype.methodType() == QMetaMethod::Method) + method = addMethod(prototype.signature()); + else if (prototype.methodType() == QMetaMethod::Signal) + method = addSignal(prototype.signature()); + else if (prototype.methodType() == QMetaMethod::Slot) + method = addSlot(prototype.signature()); + else if (prototype.methodType() == QMetaMethod::Constructor) + method = addConstructor(prototype.signature()); + method.setReturnType(prototype.typeName()); + method.setParameterNames(prototype.parameterNames()); + method.setTag(prototype.tag()); + method.setAccess(prototype.access()); + method.setAttributes(prototype.attributes()); + return method; +} + +/*! + Adds a new public slot to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the slot. The \a signature will be normalized before it is + added to the class. + + \sa addMethod(), addSignal(), indexOfSlot() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addSlot(const QByteArray& signature) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Slot, signature)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new signal to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the signal. The \a signature will be normalized before it is + added to the class. + + \sa addMethod(), addSlot(), indexOfSignal() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addSignal(const QByteArray& signature) +{ + int index = d->methods.size(); + d->methods.append(QMetaMethodBuilderPrivate + (QMetaMethod::Signal, signature, QByteArray(), QMetaMethod::Protected)); + return QMetaMethodBuilder(this, index); +} + +/*! + Adds a new constructor to this class with the specified \a signature. + Returns an object that can be used to adjust the other attributes + of the constructor. The \a signature will be normalized before it is + added to the class. + + \sa constructor(), constructorCount(), removeConstructor() + \sa indexOfConstructor() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QByteArray& signature) +{ + int index = d->constructors.size(); + d->constructors.append(QMetaMethodBuilderPrivate(QMetaMethod::Constructor, signature)); + return QMetaMethodBuilder(this, -(index + 1)); +} + +/*! + Adds a new constructor to this class that has the same information as + \a prototype. This is used to clone the constructors of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the constructor. + + This function requires that \a prototype be a constructor. + + \sa constructor(), constructorCount(), removeConstructor() + \sa indexOfConstructor() +*/ +QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QMetaMethod& prototype) +{ + Q_ASSERT(prototype.methodType() == QMetaMethod::Constructor); + QMetaMethodBuilder ctor = addConstructor(prototype.signature()); + ctor.setReturnType(prototype.typeName()); + ctor.setParameterNames(prototype.parameterNames()); + ctor.setTag(prototype.tag()); + ctor.setAccess(prototype.access()); + ctor.setAttributes(prototype.attributes()); + return ctor; +} + +/*! + Adds a new readable/writable property to this class with the + specified \a name and \a type. Returns an object that can be used + to adjust the other attributes of the property. The \a type will + be normalized before it is added to the class. \a notifierId will + be registered as the property's \e notify signal. + + \sa property(), propertyCount(), removeProperty(), indexOfProperty() +*/ +QMetaPropertyBuilder QMetaObjectBuilder::addProperty + (const QByteArray& name, const QByteArray& type, int notifierId) +{ + int index = d->properties.size(); + d->properties.append(QMetaPropertyBuilderPrivate(name, type, notifierId)); + return QMetaPropertyBuilder(this, index); +} + +/*! + Adds a new property to this class that has the same information as + \a prototype. This is used to clone the properties of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the property. + + \sa property(), propertyCount(), removeProperty(), indexOfProperty() +*/ +QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& prototype) +{ + QMetaPropertyBuilder property = addProperty(prototype.name(), prototype.typeName()); + property.setReadable(prototype.isReadable()); + property.setWritable(prototype.isWritable()); + property.setResettable(prototype.isResettable()); + property.setDesignable(prototype.isDesignable()); + property.setScriptable(prototype.isScriptable()); + property.setStored(prototype.isStored()); + property.setEditable(prototype.isEditable()); + property.setUser(prototype.isUser()); + property.setStdCppSet(prototype.hasStdCppSet()); + property.setEnumOrFlag(prototype.isEnumType()); + property.setConstant(prototype.isConstant()); + property.setFinal(prototype.isFinal()); + if (prototype.hasNotifySignal()) { + // Find an existing method for the notify signal, or add a new one. + QMetaMethod method = prototype.notifySignal(); + int index = indexOfMethod(method.signature()); + if (index == -1) + index = addMethod(method).index(); + d->properties[property._index].notifySignal = index; + d->properties[property._index].setFlag(Notify, true); + } + return property; +} + +/*! + Adds a new enumerator to this class with the specified + \a name. Returns an object that can be used to adjust + the other attributes of the enumerator. + + \sa enumerator(), enumeratorCount(), removeEnumerator(), + \sa indexOfEnumerator() +*/ +QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QByteArray& name) +{ + int index = d->enumerators.size(); + d->enumerators.append(QMetaEnumBuilderPrivate(name)); + return QMetaEnumBuilder(this, index); +} + +/*! + Adds a new enumerator to this class that has the same information as + \a prototype. This is used to clone the enumerators of an existing + QMetaObject. Returns an object that can be used to adjust the + attributes of the enumerator. + + \sa enumerator(), enumeratorCount(), removeEnumerator(), + \sa indexOfEnumerator() +*/ +QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum& prototype) +{ + QMetaEnumBuilder en = addEnumerator(prototype.name()); + en.setIsFlag(prototype.isFlag()); + int count = prototype.keyCount(); + for (int index = 0; index < count; ++index) + en.addKey(prototype.key(index), prototype.value(index)); + return en; +} + +/*! + Adds \a name and \a value as an item of class information to this class. + Returns the index of the new item of class information. + + \sa classInfoCount(), classInfoName(), classInfoValue(), removeClassInfo() + \sa indexOfClassInfo() +*/ +int QMetaObjectBuilder::addClassInfo(const QByteArray& name, const QByteArray& value) +{ + int index = d->classInfoNames.size(); + d->classInfoNames += name; + d->classInfoValues += value; + return index; +} + +/*! + Adds \a meta to this class as a related meta object. Returns + the index of the new related meta object entry. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa relatedMetaObjectCount(), relatedMetaObject() + \sa removeRelatedMetaObject() +*/ +#ifdef Q_NO_DATA_RELOCATION +int QMetaObjectBuilder::addRelatedMetaObject(const QMetaObjectAccessor &meta) +#else +int QMetaObjectBuilder::addRelatedMetaObject(const QMetaObject *meta) +#endif +{ + Q_ASSERT(meta); + int index = d->relatedMetaObjects.size(); + d->relatedMetaObjects.append(meta); + return index; +} + +/*! + Adds the contents of \a prototype to this meta object builder. + This function is useful for cloning the contents of an existing QMetaObject. + + The \a members parameter indicates which members of \a prototype + should be added. The default is AllMembers. +*/ +void QMetaObjectBuilder::addMetaObject + (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members) +{ + Q_ASSERT(prototype); + int index; + + if ((members & ClassName) != 0) + d->className = prototype->className(); + + if ((members & SuperClass) != 0) + d->superClass = prototype->superClass(); + + if ((members & (Methods | Signals | Slots)) != 0) { + for (index = prototype->methodOffset(); index < prototype->methodCount(); ++index) { + QMetaMethod method = prototype->method(index); + if (method.methodType() != QMetaMethod::Signal) { + if (method.access() == QMetaMethod::Public && (members & PublicMethods) == 0) + continue; + if (method.access() == QMetaMethod::Private && (members & PrivateMethods) == 0) + continue; + if (method.access() == QMetaMethod::Protected && (members & ProtectedMethods) == 0) + continue; + } + if (method.methodType() == QMetaMethod::Method && (members & Methods) != 0) { + addMethod(method); + } else if (method.methodType() == QMetaMethod::Signal && + (members & Signals) != 0) { + addMethod(method); + } else if (method.methodType() == QMetaMethod::Slot && + (members & Slots) != 0) { + addMethod(method); + } + } + } + + if ((members & Constructors) != 0) { + for (index = 0; index < prototype->constructorCount(); ++index) + addConstructor(prototype->constructor(index)); + } + + if ((members & Properties) != 0) { + for (index = prototype->propertyOffset(); index < prototype->propertyCount(); ++index) + addProperty(prototype->property(index)); + } + + if ((members & Enumerators) != 0) { + for (index = prototype->enumeratorOffset(); index < prototype->enumeratorCount(); ++index) + addEnumerator(prototype->enumerator(index)); + } + + if ((members & ClassInfos) != 0) { + for (index = prototype->classInfoOffset(); index < prototype->classInfoCount(); ++index) { + QMetaClassInfo ci = prototype->classInfo(index); + addClassInfo(ci.name(), ci.value()); + } + } + + if ((members & RelatedMetaObjects) != 0) { +#ifdef Q_NO_DATA_RELOCATION + const QMetaObjectAccessor *objects = 0; +#else + const QMetaObject **objects; + if (priv(prototype->d.data)->revision < 2) { + objects = (const QMetaObject **)(prototype->d.extradata); + } else +#endif + { + const QMetaObjectExtraData *extra = (const QMetaObjectExtraData *)(prototype->d.extradata); + if (extra) + objects = extra->objects; + else + objects = 0; + } + if (objects) { + while (*objects != 0) { + addRelatedMetaObject(*objects); + ++objects; + } + } + } + + if ((members & StaticMetacall) != 0) { + if (priv(prototype->d.data)->revision >= 6) { + const QMetaObjectExtraData *extra = + (const QMetaObjectExtraData *)(prototype->d.extradata); + if (extra && extra->static_metacall) + setStaticMetacallFunction(extra->static_metacall); + } + } +} + +/*! + Returns the method at \a index in this class. + + \sa methodCount(), addMethod(), removeMethod(), indexOfMethod() +*/ +QMetaMethodBuilder QMetaObjectBuilder::method(int index) const +{ + if (index >= 0 && index < d->methods.size()) + return QMetaMethodBuilder(this, index); + else + return QMetaMethodBuilder(); +} + +/*! + Returns the constructor at \a index in this class. + + \sa methodCount(), addMethod(), removeMethod(), indexOfConstructor() +*/ +QMetaMethodBuilder QMetaObjectBuilder::constructor(int index) const +{ + if (index >= 0 && index < d->constructors.size()) + return QMetaMethodBuilder(this, -(index + 1)); + else + return QMetaMethodBuilder(); +} + +/*! + Returns the property at \a index in this class. + + \sa methodCount(), addMethod(), removeMethod(), indexOfProperty() +*/ +QMetaPropertyBuilder QMetaObjectBuilder::property(int index) const +{ + if (index >= 0 && index < d->properties.size()) + return QMetaPropertyBuilder(this, index); + else + return QMetaPropertyBuilder(); +} + +/*! + Returns the enumerator at \a index in this class. + + \sa enumeratorCount(), addEnumerator(), removeEnumerator() + \sa indexOfEnumerator() +*/ +QMetaEnumBuilder QMetaObjectBuilder::enumerator(int index) const +{ + if (index >= 0 && index < d->enumerators.size()) + return QMetaEnumBuilder(this, index); + else + return QMetaEnumBuilder(); +} + +/*! + Returns the related meta object at \a index in this class. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa relatedMetaObjectCount(), addRelatedMetaObject() + \sa removeRelatedMetaObject() +*/ +const QMetaObject *QMetaObjectBuilder::relatedMetaObject(int index) const +{ + if (index >= 0 && index < d->relatedMetaObjects.size()) +#ifdef Q_NO_DATA_RELOCATION + return &((*(d->relatedMetaObjects[index]))()); +#else + return d->relatedMetaObjects[index]; +#endif + else + return 0; +} + +/*! + Returns the name of the item of class information at \a index + in this class. + + \sa classInfoCount(), addClassInfo(), classInfoValue(), removeClassInfo() + \sa indexOfClassInfo() +*/ +QByteArray QMetaObjectBuilder::classInfoName(int index) const +{ + if (index >= 0 && index < d->classInfoNames.size()) + return d->classInfoNames[index]; + else + return QByteArray(); +} + +/*! + Returns the value of the item of class information at \a index + in this class. + + \sa classInfoCount(), addClassInfo(), classInfoName(), removeClassInfo() + \sa indexOfClassInfo() +*/ +QByteArray QMetaObjectBuilder::classInfoValue(int index) const +{ + if (index >= 0 && index < d->classInfoValues.size()) + return d->classInfoValues[index]; + else + return QByteArray(); +} + +/*! + Removes the method at \a index from this class. The indices of + all following methods will be adjusted downwards by 1. If the + method is registered as a notify signal on a property, then the + notify signal will be removed from the property. + + \sa methodCount(), addMethod(), method(), indexOfMethod() +*/ +void QMetaObjectBuilder::removeMethod(int index) +{ + if (index >= 0 && index < d->methods.size()) { + d->methods.removeAt(index); + for (int prop = 0; prop < d->properties.size(); ++prop) { + // Adjust the indices of property notify signal references. + if (d->properties[prop].notifySignal == index) { + d->properties[prop].notifySignal = -1; + d->properties[prop].setFlag(Notify, false); + } else if (d->properties[prop].notifySignal > index) + (d->properties[prop].notifySignal)--; + } + } +} + +/*! + Removes the constructor at \a index from this class. The indices of + all following constructors will be adjusted downwards by 1. + + \sa constructorCount(), addConstructor(), constructor() + \sa indexOfConstructor() +*/ +void QMetaObjectBuilder::removeConstructor(int index) +{ + if (index >= 0 && index < d->constructors.size()) + d->constructors.removeAt(index); +} + +/*! + Removes the property at \a index from this class. The indices of + all following properties will be adjusted downwards by 1. + + \sa propertyCount(), addProperty(), property(), indexOfProperty() +*/ +void QMetaObjectBuilder::removeProperty(int index) +{ + if (index >= 0 && index < d->properties.size()) + d->properties.removeAt(index); +} + +/*! + Removes the enumerator at \a index from this class. The indices of + all following enumerators will be adjusted downwards by 1. + + \sa enumertorCount(), addEnumerator(), enumerator() + \sa indexOfEnumerator() +*/ +void QMetaObjectBuilder::removeEnumerator(int index) +{ + if (index >= 0 && index < d->enumerators.size()) + d->enumerators.removeAt(index); +} + +/*! + Removes the item of class information at \a index from this class. + The indices of all following items will be adjusted downwards by 1. + + \sa classInfoCount(), addClassInfo(), classInfoName(), classInfoValue() + \sa indexOfClassInfo() +*/ +void QMetaObjectBuilder::removeClassInfo(int index) +{ + if (index >= 0 && index < d->classInfoNames.size()) { + d->classInfoNames.removeAt(index); + d->classInfoValues.removeAt(index); + } +} + +/*! + Removes the related meta object at \a index from this class. + The indices of all following related meta objects will be adjusted + downwards by 1. + + Related meta objects are used when resolving the enumerated type + associated with a property, where the enumerated type is in a + different class from the property. + + \sa relatedMetaObjectCount(), addRelatedMetaObject() + \sa relatedMetaObject() +*/ +void QMetaObjectBuilder::removeRelatedMetaObject(int index) +{ + if (index >= 0 && index < d->relatedMetaObjects.size()) + d->relatedMetaObjects.removeAt(index); +} + +/*! + Finds a method with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa method(), methodCount(), addMethod(), removeMethod() +*/ +int QMetaObjectBuilder::indexOfMethod(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->methods.size(); ++index) { + if (sig == d->methods[index].signature) + return index; + } + return -1; +} + +/*! + Finds a signal with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa indexOfMethod(), indexOfSlot() +*/ +int QMetaObjectBuilder::indexOfSignal(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->methods.size(); ++index) { + if (sig == d->methods[index].signature && + d->methods[index].methodType() == QMetaMethod::Signal) + return index; + } + return -1; +} + +/*! + Finds a slot with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa indexOfMethod(), indexOfSignal() +*/ +int QMetaObjectBuilder::indexOfSlot(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->methods.size(); ++index) { + if (sig == d->methods[index].signature && + d->methods[index].methodType() == QMetaMethod::Slot) + return index; + } + return -1; +} + +/*! + Finds a constructor with the specified \a signature and returns its index; + otherwise returns -1. The \a signature will be normalized by this method. + + \sa constructor(), constructorCount(), addConstructor(), removeConstructor() +*/ +int QMetaObjectBuilder::indexOfConstructor(const QByteArray& signature) +{ + QByteArray sig = QMetaObject::normalizedSignature(signature); + for (int index = 0; index < d->constructors.size(); ++index) { + if (sig == d->constructors[index].signature) + return index; + } + return -1; +} + +/*! + Finds a property with the specified \a name and returns its index; + otherwise returns -1. + + \sa property(), propertyCount(), addProperty(), removeProperty() +*/ +int QMetaObjectBuilder::indexOfProperty(const QByteArray& name) +{ + for (int index = 0; index < d->properties.size(); ++index) { + if (name == d->properties[index].name) + return index; + } + return -1; +} + +/*! + Finds an enumerator with the specified \a name and returns its index; + otherwise returns -1. + + \sa enumertor(), enumeratorCount(), addEnumerator(), removeEnumerator() +*/ +int QMetaObjectBuilder::indexOfEnumerator(const QByteArray& name) +{ + for (int index = 0; index < d->enumerators.size(); ++index) { + if (name == d->enumerators[index].name) + return index; + } + return -1; +} + +/*! + Finds an item of class information with the specified \a name and + returns its index; otherwise returns -1. + + \sa classInfoName(), classInfoValue(), classInfoCount(), addClassInfo() + \sa removeClassInfo() +*/ +int QMetaObjectBuilder::indexOfClassInfo(const QByteArray& name) +{ + for (int index = 0; index < d->classInfoNames.size(); ++index) { + if (name == d->classInfoNames[index]) + return index; + } + return -1; +} + +// Align on a specific type boundary. +#define ALIGN(size,type) \ + (size) = ((size) + sizeof(type) - 1) & ~(sizeof(type) - 1) + +// Build a string into a QMetaObject representation. Returns the +// position in the string table where the string was placed. +static int buildString + (char *buf, char *str, int *offset, const QByteArray& value, int empty) +{ + if (value.size() == 0 && empty >= 0) + return empty; + if (buf) { + memcpy(str + *offset, value.constData(), value.size()); + str[*offset + value.size()] = '\0'; + } + int posn = *offset; + *offset += value.size() + 1; + return posn; +} + +// Build the parameter array string for a method. +static QByteArray buildParameterNames + (const QByteArray& signature, const QList<QByteArray>& parameterNames) +{ + // If the parameter name list is specified, then concatenate them. + if (!parameterNames.isEmpty()) { + QByteArray names; + bool first = true; + foreach (const QByteArray &name, parameterNames) { + if (first) + first = false; + else + names += (char)','; + names += name; + } + return names; + } + + // Count commas in the signature, excluding those inside template arguments. + int index = signature.indexOf('('); + if (index < 0) + return QByteArray(); + ++index; + if (index >= signature.size()) + return QByteArray(); + if (signature[index] == ')') + return QByteArray(); + int count = 1; + int brackets = 0; + while (index < signature.size() && signature[index] != ',') { + char ch = signature[index++]; + if (ch == '<') + ++brackets; + else if (ch == '>') + --brackets; + else if (ch == ',' && brackets <= 0) + ++count; + } + return QByteArray(count - 1, ','); +} + +// Build a QMetaObject in "buf" based on the information in "d". +// If "buf" is null, then return the number of bytes needed to +// build the QMetaObject. Returns -1 if the metaobject if +// relocatable is set, but the metaobject contains extradata. +static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, + bool relocatable) +{ + int size = 0; + int dataIndex; + int enumIndex; + int index; + bool hasNotifySignals = false; + + if (relocatable && + (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction)) + return -1; + + // Create the main QMetaObject structure at the start of the buffer. + QMetaObject *meta = reinterpret_cast<QMetaObject *>(buf); + size += sizeof(QMetaObject); + ALIGN(size, int); + if (buf) { + if (!relocatable) meta->d.superdata = d->superClass; + meta->d.extradata = 0; + } + + // Populate the QMetaObjectPrivate structure. + QMetaObjectPrivate *pmeta + = reinterpret_cast<QMetaObjectPrivate *>(buf + size); + int pmetaSize = size; + dataIndex = 13; // Number of fields in the QMetaObjectPrivate. + for (index = 0; index < d->properties.size(); ++index) { + if (d->properties[index].notifySignal != -1) { + hasNotifySignals = true; + break; + } + } + if (buf) { + pmeta->revision = 3; + pmeta->flags = d->flags; + pmeta->className = 0; // Class name is always the first string. + + pmeta->classInfoCount = d->classInfoNames.size(); + pmeta->classInfoData = dataIndex; + dataIndex += 2 * d->classInfoNames.size(); + + pmeta->methodCount = d->methods.size(); + pmeta->methodData = dataIndex; + dataIndex += 5 * d->methods.size(); + + pmeta->propertyCount = d->properties.size(); + pmeta->propertyData = dataIndex; + dataIndex += 3 * d->properties.size(); + if (hasNotifySignals) + dataIndex += d->properties.size(); + + pmeta->enumeratorCount = d->enumerators.size(); + pmeta->enumeratorData = dataIndex; + dataIndex += 4 * d->enumerators.size(); + + pmeta->constructorCount = d->constructors.size(); + pmeta->constructorData = dataIndex; + dataIndex += 5 * d->constructors.size(); + } else { + dataIndex += 2 * d->classInfoNames.size(); + dataIndex += 5 * d->methods.size(); + dataIndex += 3 * d->properties.size(); + if (hasNotifySignals) + dataIndex += d->properties.size(); + dataIndex += 4 * d->enumerators.size(); + dataIndex += 5 * d->constructors.size(); + } + + // Allocate space for the enumerator key names and values. + enumIndex = dataIndex; + for (index = 0; index < d->enumerators.size(); ++index) { + QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + dataIndex += 2 * enumerator->keys.size(); + } + + // Zero terminator at the end of the data offset table. + ++dataIndex; + + // Find the start of the data and string tables. + int *data = reinterpret_cast<int *>(pmeta); + size += dataIndex * sizeof(int); + char *str = reinterpret_cast<char *>(buf + size); + if (buf) { + if (relocatable) { + meta->d.stringdata = reinterpret_cast<const char *>((quintptr)size); + meta->d.data = reinterpret_cast<uint *>((quintptr)pmetaSize); + } else { + meta->d.stringdata = str; + meta->d.data = reinterpret_cast<uint *>(data); + } + } + + // Reset the current data position to just past the QMetaObjectPrivate. + dataIndex = 13; + + // Add the class name to the string table. + int offset = 0; + buildString(buf, str, &offset, d->className, -1); + + // Add a common empty string, which is used to indicate "void" + // method returns, empty tag strings, etc. + int empty = buildString(buf, str, &offset, QByteArray(), -1); + + // Output the class infos, + for (index = 0; index < d->classInfoNames.size(); ++index) { + int name = buildString(buf, str, &offset, d->classInfoNames[index], empty); + int value = buildString(buf, str, &offset, d->classInfoValues[index], empty); + if (buf) { + data[dataIndex] = name; + data[dataIndex + 1] = value; + } + dataIndex += 2; + } + + // Output the methods in the class. + for (index = 0; index < d->methods.size(); ++index) { + QMetaMethodBuilderPrivate *method = &(d->methods[index]); + int sig = buildString(buf, str, &offset, method->signature, empty); + int params; + QByteArray names = buildParameterNames + (method->signature, method->parameterNames); + params = buildString(buf, str, &offset, names, empty); + int ret = buildString(buf, str, &offset, method->returnType, empty); + int tag = buildString(buf, str, &offset, method->tag, empty); + int attrs = method->attributes; + if (buf) { + data[dataIndex] = sig; + data[dataIndex + 1] = params; + data[dataIndex + 2] = ret; + data[dataIndex + 3] = tag; + data[dataIndex + 4] = attrs; + } + dataIndex += 5; + } + + // Output the properties in the class. + for (index = 0; index < d->properties.size(); ++index) { + QMetaPropertyBuilderPrivate *prop = &(d->properties[index]); + int name = buildString(buf, str, &offset, prop->name, empty); + int type = buildString(buf, str, &offset, prop->type, empty); + int flags = prop->flags; + + if (!isVariantType(prop->type)) { + flags |= EnumOrFlag; + } else { + flags |= qvariant_nameToType(prop->type) << 24; + } + + if (buf) { + data[dataIndex] = name; + data[dataIndex + 1] = type; + data[dataIndex + 2] = flags; + } + dataIndex += 3; + } + if (hasNotifySignals) { + for (index = 0; index < d->properties.size(); ++index) { + QMetaPropertyBuilderPrivate *prop = &(d->properties[index]); + if (buf) { + if (prop->notifySignal != -1) + data[dataIndex] = prop->notifySignal; + else + data[dataIndex] = 0; + } + ++dataIndex; + } + } + + // Output the enumerators in the class. + for (index = 0; index < d->enumerators.size(); ++index) { + QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + int name = buildString(buf, str, &offset, enumerator->name, empty); + int isFlag = (int)(enumerator->isFlag); + int count = enumerator->keys.size(); + int enumOffset = enumIndex; + if (buf) { + data[dataIndex] = name; + data[dataIndex + 1] = isFlag; + data[dataIndex + 2] = count; + data[dataIndex + 3] = enumOffset; + } + for (int key = 0; key < count; ++key) { + int keyIndex = buildString(buf, str, &offset, enumerator->keys[key], empty); + if (buf) { + data[enumOffset++] = keyIndex; + data[enumOffset++] = enumerator->values[key]; + } + } + dataIndex += 4; + enumIndex += 2 * count; + } + + // Output the constructors in the class. + for (index = 0; index < d->constructors.size(); ++index) { + QMetaMethodBuilderPrivate *method = &(d->constructors[index]); + int sig = buildString(buf, str, &offset, method->signature, empty); + int params; + QByteArray names = buildParameterNames + (method->signature, method->parameterNames); + params = buildString(buf, str, &offset, names, empty); + int ret = buildString(buf, str, &offset, method->returnType, empty); + int tag = buildString(buf, str, &offset, method->tag, empty); + int attrs = method->attributes; + if (buf) { + data[dataIndex] = sig; + data[dataIndex + 1] = params; + data[dataIndex + 2] = ret; + data[dataIndex + 3] = tag; + data[dataIndex + 4] = attrs; + } + dataIndex += 5; + } + + // One more empty string to act as a terminator. + buildString(buf, str, &offset, QByteArray(), -1); + size += offset; + + // Output the zero terminator in the data array. + if (buf) + data[enumIndex] = 0; + + // Create the extradata block if we need one. + if (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction) { + ALIGN(size, QMetaObject **); + ALIGN(size, QMetaObjectBuilder::StaticMetacallFunction); + QMetaObjectExtraData *extra = + reinterpret_cast<QMetaObjectExtraData *>(buf + size); + size += sizeof(QMetaObjectExtraData); + ALIGN(size, QMetaObject *); +#ifdef Q_NO_DATA_RELOCATION + QMetaObjectAccessor *objects = + reinterpret_cast<QMetaObjectAccessor *>(buf + size); +#else + const QMetaObject **objects = + reinterpret_cast<const QMetaObject **>(buf + size); +#endif + if (buf) { + if (d->relatedMetaObjects.size() > 0) { + extra->objects = objects; + for (index = 0; index < d->relatedMetaObjects.size(); ++index) + objects[index] = d->relatedMetaObjects[index]; + objects[index] = 0; + } else { + extra->objects = 0; + } + extra->static_metacall = d->staticMetacallFunction; + meta->d.extradata = reinterpret_cast<void *>(extra); + } + if (d->relatedMetaObjects.size() > 0) + size += sizeof(QMetaObject *) * (d->relatedMetaObjects.size() + 1); + } + + // Align the final size and return it. + ALIGN(size, void *); + return size; +} + +/*! + Converts this meta object builder into a concrete QMetaObject. + The return value should be deallocated using qFree() once it + is no longer needed. + + The returned meta object is a snapshot of the state of the + QMetaObjectBuilder. Any further modifications to the QMetaObjectBuilder + will not be reflected in previous meta objects returned by + this method. +*/ +QMetaObject *QMetaObjectBuilder::toMetaObject() const +{ + int size = buildMetaObject(d, 0, false); + char *buf = reinterpret_cast<char *>(qMalloc(size)); + memset(buf, 0, size); + buildMetaObject(d, buf, false); + return reinterpret_cast<QMetaObject *>(buf); +} + +/* + \internal + + Converts this meta object builder into relocatable data. This data can + be stored, copied and later passed to fromRelocatableData() to create a + concrete QMetaObject. + + The data is specific to the architecture on which it was created, but is not + specific to the process that created it. Not all meta object builder's can + be converted to data in this way. If \a ok is provided, it will be set to + true if the conversion succeeds, and false otherwise. If a + staticMetacallFunction() or any relatedMetaObject()'s are specified the + conversion to relocatable data will fail. +*/ +QByteArray QMetaObjectBuilder::toRelocatableData(bool *ok) const +{ + int size = buildMetaObject(d, 0, true); + if (size == -1) { + if (ok) *ok = false; + return QByteArray(); + } + + QByteArray data; + data.resize(size); + char *buf = data.data(); + memset(buf, 0, size); + buildMetaObject(d, buf, true); + if (ok) *ok = true; + return data; +} + +/* + \internal + + Sets the \a data returned from toRelocatableData() onto a concrete + QMetaObject instance, \a output. As the meta object's super class is not + saved in the relocatable data, it must be passed as \a superClass. +*/ +void QMetaObjectBuilder::fromRelocatableData(QMetaObject *output, + const QMetaObject *superclass, + const QByteArray &data) +{ + if (!output) + return; + + const char *buf = data.constData(); + const QMetaObject *dataMo = reinterpret_cast<const QMetaObject *>(buf); + + quintptr stringdataOffset = (quintptr)dataMo->d.stringdata; + quintptr dataOffset = (quintptr)dataMo->d.data; + + output->d.superdata = superclass; + output->d.stringdata = buf + stringdataOffset; + output->d.data = reinterpret_cast<const uint *>(buf + dataOffset); +} + +/*! + \typedef QMetaObjectBuilder::StaticMetacallFunction + + Typedef for static metacall functions. The three parameters are + the call type value, the constructor index, and the + array of parameters. +*/ + +/*! + Returns the static metacall function to use to construct objects + of this class. The default value is null. + + \sa setStaticMetacallFunction() +*/ +QMetaObjectBuilder::StaticMetacallFunction QMetaObjectBuilder::staticMetacallFunction() const +{ + return d->staticMetacallFunction; +} + +/*! + Sets the static metacall function to use to construct objects + of this class to \a value. The default value is null. + + \sa staticMetacallFunction() +*/ +void QMetaObjectBuilder::setStaticMetacallFunction + (QMetaObjectBuilder::StaticMetacallFunction value) +{ + d->staticMetacallFunction = value; +} + +#ifndef QT_NO_DATASTREAM + +/*! + Serializes the contents of the meta object builder onto \a stream. + + \sa deserialize() +*/ +void QMetaObjectBuilder::serialize(QDataStream& stream) const +{ + int index; + + // Write the class and super class names. + stream << d->className; + if (d->superClass) + stream << QByteArray(d->superClass->className()); + else + stream << QByteArray(); + + // Write the counts for each type of class member. + stream << d->classInfoNames.size(); + stream << d->methods.size(); + stream << d->properties.size(); + stream << d->enumerators.size(); + stream << d->constructors.size(); + stream << d->relatedMetaObjects.size(); + + // Write the items of class information. + for (index = 0; index < d->classInfoNames.size(); ++index) { + stream << d->classInfoNames[index]; + stream << d->classInfoValues[index]; + } + + // Write the methods. + for (index = 0; index < d->methods.size(); ++index) { + const QMetaMethodBuilderPrivate *method = &(d->methods[index]); + stream << method->signature; + stream << method->returnType; + stream << method->parameterNames; + stream << method->tag; + stream << method->attributes; + } + + // Write the properties. + for (index = 0; index < d->properties.size(); ++index) { + const QMetaPropertyBuilderPrivate *property = &(d->properties[index]); + stream << property->name; + stream << property->type; + stream << property->flags; + stream << property->notifySignal; + } + + // Write the enumerators. + for (index = 0; index < d->enumerators.size(); ++index) { + const QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + stream << enumerator->name; + stream << enumerator->isFlag; + stream << enumerator->keys; + stream << enumerator->values; + } + + // Write the constructors. + for (index = 0; index < d->constructors.size(); ++index) { + const QMetaMethodBuilderPrivate *method = &(d->constructors[index]); + stream << method->signature; + stream << method->returnType; + stream << method->parameterNames; + stream << method->tag; + stream << method->attributes; + } + + // Write the related meta objects. +#ifdef Q_NO_DATA_RELOCATION + //### What do we do here? +#else + for (index = 0; index < d->relatedMetaObjects.size(); ++index) { + const QMetaObject *meta = d->relatedMetaObjects[index]; + stream << QByteArray(meta->className()); + } +#endif + + // Add an extra empty QByteArray for additional data in future versions. + // This should help maintain backwards compatibility, allowing older + // versions to read newer data. + stream << QByteArray(); +} + +// Resolve a class name using the name reference map. +static const QMetaObject *resolveClassName + (const QMap<QByteArray, const QMetaObject *>& references, + const QByteArray& name) +{ + if (name == QByteArray("QObject")) + return &QObject::staticMetaObject; + else + return references.value(name, 0); +} + +/*! + Deserializes a meta object builder from \a stream into + this meta object builder. + + The \a references parameter specifies a mapping from class names + to QMetaObject instances for resolving the super class name and + related meta objects in the object that is deserialized. + The meta object for QObject is implicitly added to \a references + and does not need to be supplied. + + The QDataStream::status() value on \a stream will be set to + QDataStream::ReadCorruptData if the input data is corrupt. + The status will be set to QDataStream::ReadPastEnd if the + input was exhausted before the full meta object was read. + + \sa serialize() +*/ +void QMetaObjectBuilder::deserialize + (QDataStream& stream, + const QMap<QByteArray, const QMetaObject *>& references) +{ + QByteArray name; + const QMetaObject *cl; + int index; + + // Clear all members in the builder to their default states. + d->className.clear(); + d->superClass = &QObject::staticMetaObject; + d->classInfoNames.clear(); + d->classInfoValues.clear(); + d->methods.clear(); + d->properties.clear(); + d->enumerators.clear(); + d->constructors.clear(); + d->relatedMetaObjects.clear(); + d->staticMetacallFunction = 0; + + // Read the class and super class names. + stream >> d->className; + stream >> name; + if (name.isEmpty()) { + d->superClass = 0; + } else if ((cl = resolveClassName(references, name)) != 0) { + d->superClass = cl; + } else { + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + + // Read the counts for each type of class member. + int classInfoCount, methodCount, propertyCount; + int enumeratorCount, constructorCount, relatedMetaObjectCount; + stream >> classInfoCount; + stream >> methodCount; + stream >> propertyCount; + stream >> enumeratorCount; + stream >> constructorCount; + stream >> relatedMetaObjectCount; + if (classInfoCount < 0 || methodCount < 0 || + propertyCount < 0 || enumeratorCount < 0 || + constructorCount < 0 || relatedMetaObjectCount < 0) { + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + + // Read the items of class information. + for (index = 0; index < classInfoCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + QByteArray value; + stream >> name; + stream >> value; + addClassInfo(name, value); + } + + // Read the member methods. + for (index = 0; index < methodCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + addMethod(name); + QMetaMethodBuilderPrivate *method = &(d->methods[index]); + stream >> method->returnType; + stream >> method->parameterNames; + stream >> method->tag; + stream >> method->attributes; + if (method->methodType() == QMetaMethod::Constructor) { + // Cannot add a constructor in this set of methods. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the properties. + for (index = 0; index < propertyCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + QByteArray type; + stream >> name; + stream >> type; + addProperty(name, type); + QMetaPropertyBuilderPrivate *property = &(d->properties[index]); + stream >> property->flags; + stream >> property->notifySignal; + if (property->notifySignal < -1 || + property->notifySignal >= d->methods.size()) { + // Notify signal method index is out of range. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + if (property->notifySignal >= 0 && + d->methods[property->notifySignal].methodType() != QMetaMethod::Signal) { + // Notify signal method index does not refer to a signal. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the enumerators. + for (index = 0; index < enumeratorCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + addEnumerator(name); + QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]); + stream >> enumerator->isFlag; + stream >> enumerator->keys; + stream >> enumerator->values; + if (enumerator->keys.size() != enumerator->values.size()) { + // Mismatch between number of keys and number of values. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the constructor methods. + for (index = 0; index < constructorCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + addConstructor(name); + QMetaMethodBuilderPrivate *method = &(d->constructors[index]); + stream >> method->returnType; + stream >> method->parameterNames; + stream >> method->tag; + stream >> method->attributes; + if (method->methodType() != QMetaMethod::Constructor) { + // The type must be Constructor. + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + } + + // Read the related meta objects. +#ifdef Q_NO_DATA_RELOCATION + //### What do we do here +#else + for (index = 0; index < relatedMetaObjectCount; ++index) { + if (stream.status() != QDataStream::Ok) + return; + stream >> name; + cl = resolveClassName(references, name); + if (!cl) { + stream.setStatus(QDataStream::ReadCorruptData); + return; + } + addRelatedMetaObject(cl); + } +#endif + + // Read the extra data block, which is reserved for future use. + stream >> name; +} + +#endif // !QT_NO_DATASTREAM + +/*! + \class QMetaMethodBuilder + \internal + \brief The QMetaMethodBuilder class enables modifications to a method definition on a meta object builder. +*/ + +QMetaMethodBuilderPrivate *QMetaMethodBuilder::d_func() const +{ + // Positive indices indicate methods, negative indices indicate constructors. + if (_mobj && _index >= 0 && _index < _mobj->d->methods.size()) + return &(_mobj->d->methods[_index]); + else if (_mobj && -_index >= 1 && -_index <= _mobj->d->constructors.size()) + return &(_mobj->d->constructors[(-_index) - 1]); + else + return 0; +} + +/*! + \fn QMetaMethodBuilder::QMetaMethodBuilder() + \internal +*/ + +/*! + Returns the index of this method within its QMetaObjectBuilder. +*/ +int QMetaMethodBuilder::index() const +{ + if (_index >= 0) + return _index; // Method, signal, or slot + else + return (-_index) - 1; // Constructor +} + +/*! + Returns the type of this method (signal, slot, method, or constructor). +*/ +QMetaMethod::MethodType QMetaMethodBuilder::methodType() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->methodType(); + else + return QMetaMethod::Method; +} + +/*! + Returns the signature of this method. + + \sa parameterNames(), returnType() +*/ +QByteArray QMetaMethodBuilder::signature() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->signature; + else + return QByteArray(); +} + +/*! + Returns the return type for this method; empty if the method's + return type is \c{void}. + + \sa setReturnType(), signature() +*/ +QByteArray QMetaMethodBuilder::returnType() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->returnType; + else + return QByteArray(); +} + +/*! + Sets the return type for this method to \a value. If \a value + is empty, then the method's return type is \c{void}. The \a value + will be normalized before it is added to the method. + + \sa returnType(), signature() +*/ +void QMetaMethodBuilder::setReturnType(const QByteArray& value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->returnType = QMetaObject::normalizedType(value); +} + +/*! + Returns the list of parameter names for this method. + + \sa setParameterNames() +*/ +QList<QByteArray> QMetaMethodBuilder::parameterNames() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->parameterNames; + else + return QList<QByteArray>(); +} + +/*! + Sets the list of parameter names for this method to \a value. + + \sa parameterNames() +*/ +void QMetaMethodBuilder::setParameterNames(const QList<QByteArray>& value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->parameterNames = value; +} + +/*! + Returns the tag associated with this method. + + \sa setTag() +*/ +QByteArray QMetaMethodBuilder::tag() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->tag; + else + return QByteArray(); +} + +/*! + Sets the tag associated with this method to \a value. + + \sa setTag() +*/ +void QMetaMethodBuilder::setTag(const QByteArray& value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->tag = value; +} + +/*! + Returns the access specification of this method (private, protected, + or public). The default value is QMetaMethod::Public for methods, + slots, and constructors. The default value is QMetaMethod::Protected + for signals. + + \sa setAccess() +*/ +QMetaMethod::Access QMetaMethodBuilder::access() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return d->access(); + else + return QMetaMethod::Public; +} + +/*! + Sets the access specification of this method (private, protected, + or public) to \a value. If the method is a signal, this function + will be ignored. + + \sa access() +*/ +void QMetaMethodBuilder::setAccess(QMetaMethod::Access value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d && d->methodType() != QMetaMethod::Signal) + d->setAccess(value); +} + +/*! + Returns the additional attributes for this method. + + \sa setAttributes() +*/ +int QMetaMethodBuilder::attributes() const +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + return (d->attributes >> 4); + else + return 0; +} + +/*! + Sets the additional attributes for this method to \a value. + + \sa attributes() +*/ +void QMetaMethodBuilder::setAttributes(int value) +{ + QMetaMethodBuilderPrivate *d = d_func(); + if (d) + d->attributes = ((d->attributes & 0x0f) | (value << 4)); +} + +/*! + \class QMetaPropertyBuilder + \internal + \brief The QMetaPropertyBuilder class enables modifications to a property definition on a meta object builder. +*/ + +QMetaPropertyBuilderPrivate *QMetaPropertyBuilder::d_func() const +{ + if (_mobj && _index >= 0 && _index < _mobj->d->properties.size()) + return &(_mobj->d->properties[_index]); + else + return 0; +} + +/*! + \fn QMetaPropertyBuilder::QMetaPropertyBuilder() + \internal +*/ + +/*! + \fn int QMetaPropertyBuilder::index() const + + Returns the index of this property within its QMetaObjectBuilder. +*/ + +/*! + Returns the name associated with this property. + + \sa type() +*/ +QByteArray QMetaPropertyBuilder::name() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->name; + else + return QByteArray(); +} + +/*! + Returns the type associated with this property. + + \sa name() +*/ +QByteArray QMetaPropertyBuilder::type() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->type; + else + return QByteArray(); +} + +/*! + Returns true if this property has a notify signal; false otherwise. + + \sa notifySignal(), setNotifySignal(), removeNotifySignal() +*/ +bool QMetaPropertyBuilder::hasNotifySignal() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Notify); + else + return false; +} + +/*! + Returns the notify signal associated with this property. + + \sa hasNotifySignal(), setNotifySignal(), removeNotifySignal() +*/ +QMetaMethodBuilder QMetaPropertyBuilder::notifySignal() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d && d->notifySignal >= 0) + return QMetaMethodBuilder(_mobj, d->notifySignal); + else + return QMetaMethodBuilder(); +} + +/*! + Sets the notify signal associated with this property to \a value. + + \sa hasNotifySignal(), notifySignal(), removeNotifySignal() +*/ +void QMetaPropertyBuilder::setNotifySignal(const QMetaMethodBuilder& value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) { + if (value._mobj) { + d->notifySignal = value._index; + d->setFlag(Notify, true); + } else { + d->notifySignal = -1; + d->setFlag(Notify, false); + } + } +} + +/*! + Removes the notify signal from this property. + + \sa hasNotifySignal(), notifySignal(), setNotifySignal() +*/ +void QMetaPropertyBuilder::removeNotifySignal() +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) { + d->notifySignal = -1; + d->setFlag(Notify, false); + } +} + +/*! + Returns true if this property is readable; otherwise returns false. + The default value is true. + + \sa setReadable(), isWritable() +*/ +bool QMetaPropertyBuilder::isReadable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Readable); + else + return false; +} + +/*! + Returns true if this property is writable; otherwise returns false. + The default value is true. + + \sa setWritable(), isReadable() +*/ +bool QMetaPropertyBuilder::isWritable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Writable); + else + return false; +} + +/*! + Returns true if this property can be reset to a default value; otherwise + returns false. The default value is false. + + \sa setResettable() +*/ +bool QMetaPropertyBuilder::isResettable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Resettable); + else + return false; +} + +/*! + Returns true if this property is designable; otherwise returns false. + This default value is false. + + \sa setDesignable(), isScriptable(), isStored() +*/ +bool QMetaPropertyBuilder::isDesignable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Designable); + else + return false; +} + +/*! + Returns true if the property is scriptable; otherwise returns false. + This default value is true. + + \sa setScriptable(), isDesignable(), isStored() +*/ +bool QMetaPropertyBuilder::isScriptable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Scriptable); + else + return false; +} + +/*! + Returns true if the property is stored; otherwise returns false. + This default value is false. + + \sa setStored(), isDesignable(), isScriptable() +*/ +bool QMetaPropertyBuilder::isStored() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Stored); + else + return false; +} + +/*! + Returns true if the property is editable; otherwise returns false. + This default value is false. + + \sa setEditable(), isDesignable(), isScriptable(), isStored() +*/ +bool QMetaPropertyBuilder::isEditable() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Editable); + else + return false; +} + +/*! + Returns true if this property is designated as the \c USER + property, i.e., the one that the user can edit or that is + significant in some other way. Otherwise it returns + false. This default value is false. + + \sa setUser(), isDesignable(), isScriptable() +*/ +bool QMetaPropertyBuilder::isUser() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(User); + else + return false; +} + +/*! + Returns true if the property has a C++ setter function that + follows Qt's standard "name" / "setName" pattern. Designer and uic + query hasStdCppSet() in order to avoid expensive + QObject::setProperty() calls. All properties in Qt [should] follow + this pattern. The default value is false. + + \sa setStdCppSet() +*/ +bool QMetaPropertyBuilder::hasStdCppSet() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(StdCppSet); + else + return false; +} + +/*! + Returns true if the property is an enumerator or flag type; + otherwise returns false. This default value is false. + + \sa setEnumOrFlag() +*/ +bool QMetaPropertyBuilder::isEnumOrFlag() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(EnumOrFlag); + else + return false; +} + +/*! + Returns true if the property is constant; otherwise returns false. + The default value is false. +*/ +bool QMetaPropertyBuilder::isConstant() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Constant); + else + return false; +} + +/*! + Returns true if the property is final; otherwise returns false. + The default value is false. +*/ +bool QMetaPropertyBuilder::isFinal() const +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + return d->flag(Final); + else + return false; +} + +/*! + Sets this property to readable if \a value is true. + + \sa isReadable(), setWritable() +*/ +void QMetaPropertyBuilder::setReadable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Readable, value); +} + +/*! + Sets this property to writable if \a value is true. + + \sa isWritable(), setReadable() +*/ +void QMetaPropertyBuilder::setWritable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Writable, value); +} + +/*! + Sets this property to resettable if \a value is true. + + \sa isResettable() +*/ +void QMetaPropertyBuilder::setResettable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Resettable, value); +} + +/*! + Sets this property to designable if \a value is true. + + \sa isDesignable(), setScriptable(), setStored() +*/ +void QMetaPropertyBuilder::setDesignable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Designable, value); +} + +/*! + Sets this property to scriptable if \a value is true. + + \sa isScriptable(), setDesignable(), setStored() +*/ +void QMetaPropertyBuilder::setScriptable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Scriptable, value); +} + +/*! + Sets this property to storable if \a value is true. + + \sa isStored(), setDesignable(), setScriptable() +*/ +void QMetaPropertyBuilder::setStored(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Stored, value); +} + +/*! + Sets this property to editable if \a value is true. + + \sa isEditable(), setDesignable(), setScriptable(), setStored() +*/ +void QMetaPropertyBuilder::setEditable(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Editable, value); +} + +/*! + Sets the \c USER flag on this property to \a value. + + \sa isUser(), setDesignable(), setScriptable() +*/ +void QMetaPropertyBuilder::setUser(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(User, value); +} + +/*! + Sets the C++ setter flag on this property to \a value, which is + true if the property has a C++ setter function that follows Qt's + standard "name" / "setName" pattern. + + \sa hasStdCppSet() +*/ +void QMetaPropertyBuilder::setStdCppSet(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(StdCppSet, value); +} + +/*! + Sets this property to be of an enumerator or flag type if + \a value is true. + + \sa isEnumOrFlag() +*/ +void QMetaPropertyBuilder::setEnumOrFlag(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(EnumOrFlag, value); +} + +/*! + Sets the \c CONSTANT flag on this property to \a value. + + \sa isConstant() +*/ +void QMetaPropertyBuilder::setConstant(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Constant, value); +} + +/*! + Sets the \c FINAL flag on this property to \a value. + + \sa isFinal() +*/ +void QMetaPropertyBuilder::setFinal(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Final, value); +} + + +/*! + \class QMetaEnumBuilder + \internal + \brief The QMetaEnumBuilder class enables modifications to an enumerator definition on a meta object builder. +*/ + +QMetaEnumBuilderPrivate *QMetaEnumBuilder::d_func() const +{ + if (_mobj && _index >= 0 && _index < _mobj->d->enumerators.size()) + return &(_mobj->d->enumerators[_index]); + else + return 0; +} + +/*! + \fn QMetaEnumBuilder::QMetaEnumBuilder() + \internal +*/ + +/*! + \fn int QMetaEnumBuilder::index() const + + Returns the index of this enumerator within its QMetaObjectBuilder. +*/ + +/*! + Returns the name of the enumerator (without the scope). +*/ +QByteArray QMetaEnumBuilder::name() const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + return d->name; + else + return QByteArray(); +} + +/*! + Returns true if this enumerator is used as a flag; otherwise returns + false. + + \sa setIsFlag() +*/ +bool QMetaEnumBuilder::isFlag() const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + return d->isFlag; + else + return false; +} + +/*! + Sets this enumerator to be used as a flag if \a value is true. + + \sa isFlag() +*/ +void QMetaEnumBuilder::setIsFlag(bool value) +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + d->isFlag = value; +} + +/*! + Returns the number of keys. + + \sa key(), addKey() +*/ +int QMetaEnumBuilder::keyCount() const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + return d->keys.size(); + else + return 0; +} + +/*! + Returns the key with the given \a index, or an empty QByteArray + if no such key exists. + + \sa keyCount(), addKey(), value() +*/ +QByteArray QMetaEnumBuilder::key(int index) const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d && index >= 0 && index < d->keys.size()) + return d->keys[index]; + else + return QByteArray(); +} + +/*! + Returns the value with the given \a index; or returns -1 if there + is no such value. + + \sa keyCount(), addKey(), key() +*/ +int QMetaEnumBuilder::value(int index) const +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d && index >= 0 && index < d->keys.size()) + return d->values[index]; + else + return -1; +} + +/*! + Adds a new key called \a name to this enumerator, associated + with \a value. Returns the index of the new key. + + \sa keyCount(), key(), value(), removeKey() +*/ +int QMetaEnumBuilder::addKey(const QByteArray& name, int value) +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) { + int index = d->keys.size(); + d->keys += name; + d->values += value; + return index; + } else { + return -1; + } +} + +/*! + Removes the key at \a index from this enumerator. + + \sa addKey() +*/ +void QMetaEnumBuilder::removeKey(int index) +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d && index >= 0 && index < d->keys.size()) { + d->keys.removeAt(index); + d->values.removeAt(index); + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmetaobjectbuilder_p.h b/src/declarative/qml/qmetaobjectbuilder_p.h new file mode 100644 index 00000000..612d00fa --- /dev/null +++ b/src/declarative/qml/qmetaobjectbuilder_p.h @@ -0,0 +1,325 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMETAOBJECTBUILDER_H +#define QMETAOBJECTBUILDER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of moc. This header file may change from version to version without notice, +// or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qdatastream.h> +#include <QtCore/qmap.h> + +#include <private/qdeclarativeglobal_p.h> + +QT_BEGIN_NAMESPACE + +class QMetaObjectBuilderPrivate; +class QMetaMethodBuilder; +class QMetaMethodBuilderPrivate; +class QMetaPropertyBuilder; +class QMetaPropertyBuilderPrivate; +class QMetaEnumBuilder; +class QMetaEnumBuilderPrivate; + +class Q_DECLARATIVE_PRIVATE_EXPORT QMetaObjectBuilder +{ +public: + enum AddMember + { + ClassName = 0x00000001, + SuperClass = 0x00000002, + Methods = 0x00000004, + Signals = 0x00000008, + Slots = 0x00000010, + Constructors = 0x00000020, + Properties = 0x00000040, + Enumerators = 0x00000080, + ClassInfos = 0x00000100, + RelatedMetaObjects = 0x00000200, + StaticMetacall = 0x00000400, + PublicMethods = 0x00000800, + ProtectedMethods = 0x00001000, + PrivateMethods = 0x00002000, + AllMembers = 0x7FFFFFFF, + AllPrimaryMembers = 0x7FFFFBFC + }; + Q_DECLARE_FLAGS(AddMembers, AddMember) + + enum MetaObjectFlag { + DynamicMetaObject = 0x01 + }; + Q_DECLARE_FLAGS(MetaObjectFlags, MetaObjectFlag) + + QMetaObjectBuilder(); + explicit QMetaObjectBuilder(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers); + virtual ~QMetaObjectBuilder(); + + QByteArray className() const; + void setClassName(const QByteArray& name); + + const QMetaObject *superClass() const; + void setSuperClass(const QMetaObject *meta); + + MetaObjectFlags flags() const; + void setFlags(MetaObjectFlags); + + int methodCount() const; + int constructorCount() const; + int propertyCount() const; + int enumeratorCount() const; + int classInfoCount() const; + int relatedMetaObjectCount() const; + + QMetaMethodBuilder addMethod(const QByteArray& signature); + QMetaMethodBuilder addMethod(const QByteArray& signature, const QByteArray& returnType); + QMetaMethodBuilder addMethod(const QMetaMethod& prototype); + + QMetaMethodBuilder addSlot(const QByteArray& signature); + QMetaMethodBuilder addSignal(const QByteArray& signature); + + QMetaMethodBuilder addConstructor(const QByteArray& signature); + QMetaMethodBuilder addConstructor(const QMetaMethod& prototype); + + QMetaPropertyBuilder addProperty(const QByteArray& name, const QByteArray& type, int notifierId=-1); + QMetaPropertyBuilder addProperty(const QMetaProperty& prototype); + + QMetaEnumBuilder addEnumerator(const QByteArray& name); + QMetaEnumBuilder addEnumerator(const QMetaEnum& prototype); + + int addClassInfo(const QByteArray& name, const QByteArray& value); + +#ifdef Q_NO_DATA_RELOCATION + int addRelatedMetaObject(const QMetaObjectAccessor &meta); +#else + int addRelatedMetaObject(const QMetaObject *meta); +#endif + + void addMetaObject(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers); + + QMetaMethodBuilder method(int index) const; + QMetaMethodBuilder constructor(int index) const; + QMetaPropertyBuilder property(int index) const; + QMetaEnumBuilder enumerator(int index) const; + const QMetaObject *relatedMetaObject(int index) const; + + QByteArray classInfoName(int index) const; + QByteArray classInfoValue(int index) const; + + void removeMethod(int index); + void removeConstructor(int index); + void removeProperty(int index); + void removeEnumerator(int index); + void removeClassInfo(int index); + void removeRelatedMetaObject(int index); + + int indexOfMethod(const QByteArray& signature); + int indexOfSignal(const QByteArray& signature); + int indexOfSlot(const QByteArray& signature); + int indexOfConstructor(const QByteArray& signature); + int indexOfProperty(const QByteArray& name); + int indexOfEnumerator(const QByteArray& name); + int indexOfClassInfo(const QByteArray& name); + + typedef QMetaObjectExtraData::StaticMetacallFunction StaticMetacallFunction; + + QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction() const; + void setStaticMetacallFunction(QMetaObjectBuilder::StaticMetacallFunction value); + + QMetaObject *toMetaObject() const; + QByteArray toRelocatableData(bool * = 0) const; + static void fromRelocatableData(QMetaObject *, const QMetaObject *, const QByteArray &); + +#ifndef QT_NO_DATASTREAM + void serialize(QDataStream& stream) const; + void deserialize + (QDataStream& stream, + const QMap<QByteArray, const QMetaObject *>& references); +#endif + +private: + Q_DISABLE_COPY(QMetaObjectBuilder) + + QMetaObjectBuilderPrivate *d; + + friend class QMetaMethodBuilder; + friend class QMetaPropertyBuilder; + friend class QMetaEnumBuilder; +}; + +class Q_DECLARATIVE_PRIVATE_EXPORT QMetaMethodBuilder +{ +public: + QMetaMethodBuilder() : _mobj(0), _index(0) {} + + int index() const; + + QMetaMethod::MethodType methodType() const; + QByteArray signature() const; + + QByteArray returnType() const; + void setReturnType(const QByteArray& value); + + QList<QByteArray> parameterNames() const; + void setParameterNames(const QList<QByteArray>& value); + + QByteArray tag() const; + void setTag(const QByteArray& value); + + QMetaMethod::Access access() const; + void setAccess(QMetaMethod::Access value); + + int attributes() const; + void setAttributes(int value); + +private: + const QMetaObjectBuilder *_mobj; + int _index; + + friend class QMetaObjectBuilder; + friend class QMetaPropertyBuilder; + + QMetaMethodBuilder(const QMetaObjectBuilder *mobj, int index) + : _mobj(mobj), _index(index) {} + + QMetaMethodBuilderPrivate *d_func() const; +}; + +class Q_DECLARATIVE_PRIVATE_EXPORT QMetaPropertyBuilder +{ +public: + QMetaPropertyBuilder() : _mobj(0), _index(0) {} + + int index() const { return _index; } + + QByteArray name() const; + QByteArray type() const; + + bool hasNotifySignal() const; + QMetaMethodBuilder notifySignal() const; + void setNotifySignal(const QMetaMethodBuilder& value); + void removeNotifySignal(); + + bool isReadable() const; + bool isWritable() const; + bool isResettable() const; + bool isDesignable() const; + bool isScriptable() const; + bool isStored() const; + bool isEditable() const; + bool isUser() const; + bool hasStdCppSet() const; + bool isEnumOrFlag() const; + bool isConstant() const; + bool isFinal() const; + + void setReadable(bool value); + void setWritable(bool value); + void setResettable(bool value); + void setDesignable(bool value); + void setScriptable(bool value); + void setStored(bool value); + void setEditable(bool value); + void setUser(bool value); + void setStdCppSet(bool value); + void setEnumOrFlag(bool value); + void setConstant(bool value); + void setFinal(bool value); + +private: + const QMetaObjectBuilder *_mobj; + int _index; + + friend class QMetaObjectBuilder; + + QMetaPropertyBuilder(const QMetaObjectBuilder *mobj, int index) + : _mobj(mobj), _index(index) {} + + QMetaPropertyBuilderPrivate *d_func() const; +}; + +class Q_DECLARATIVE_PRIVATE_EXPORT QMetaEnumBuilder +{ +public: + QMetaEnumBuilder() : _mobj(0), _index(0) {} + + int index() const { return _index; } + + QByteArray name() const; + + bool isFlag() const; + void setIsFlag(bool value); + + int keyCount() const; + QByteArray key(int index) const; + int value(int index) const; + + int addKey(const QByteArray& name, int value); + void removeKey(int index); + +private: + const QMetaObjectBuilder *_mobj; + int _index; + + friend class QMetaObjectBuilder; + + QMetaEnumBuilder(const QMetaObjectBuilder *mobj, int index) + : _mobj(mobj), _index(index) {} + + QMetaEnumBuilderPrivate *d_func() const; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::AddMembers) +Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::MetaObjectFlags) + +QT_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri new file mode 100644 index 00000000..5d171bfe --- /dev/null +++ b/src/declarative/qml/qml.pri @@ -0,0 +1,139 @@ +INCLUDEPATH += $$PWD +SOURCES += \ + $$PWD/qdeclarativeparser.cpp \ + $$PWD/qdeclarativeinstruction.cpp \ + $$PWD/qdeclarativevmemetaobject.cpp \ + $$PWD/qdeclarativeengine.cpp \ + $$PWD/qdeclarativeexpression.cpp \ + $$PWD/qdeclarativebinding.cpp \ + $$PWD/qdeclarativeproperty.cpp \ + $$PWD/qdeclarativecomponent.cpp \ + $$PWD/qdeclarativecontext.cpp \ + $$PWD/qdeclarativeinclude.cpp \ + $$PWD/qdeclarativecustomparser.cpp \ + $$PWD/qdeclarativepropertyvaluesource.cpp \ + $$PWD/qdeclarativepropertyvalueinterceptor.cpp \ + $$PWD/qdeclarativeproxymetaobject.cpp \ + $$PWD/qdeclarativevme.cpp \ + $$PWD/qdeclarativecompiler.cpp \ + $$PWD/qdeclarativecompileddata.cpp \ + $$PWD/qdeclarativeboundsignal.cpp \ + $$PWD/qdeclarativedom.cpp \ + $$PWD/qdeclarativerefcount.cpp \ + $$PWD/qdeclarativemetatype.cpp \ + $$PWD/qdeclarativestringconverters.cpp \ + $$PWD/qdeclarativeparserstatus.cpp \ + $$PWD/qdeclarativetypeloader.cpp \ + $$PWD/qdeclarativeinfo.cpp \ + $$PWD/qdeclarativeerror.cpp \ + $$PWD/qdeclarativescriptparser.cpp \ + $$PWD/qdeclarativerewrite.cpp \ + $$PWD/qdeclarativevaluetype.cpp \ + $$PWD/qdeclarativecompiledbindings.cpp \ + $$PWD/qdeclarativefastproperties.cpp \ + $$PWD/qdeclarativexmlhttprequest.cpp \ + $$PWD/qdeclarativesqldatabase.cpp \ + $$PWD/qmetaobjectbuilder.cpp \ + $$PWD/qdeclarativewatcher.cpp \ + $$PWD/qdeclarativecleanup.cpp \ + $$PWD/qdeclarativepropertycache.cpp \ + $$PWD/qdeclarativenotifier.cpp \ + $$PWD/qdeclarativeintegercache.cpp \ + $$PWD/qdeclarativetypenotavailable.cpp \ + $$PWD/qdeclarativetypenamecache.cpp \ + $$PWD/qdeclarativescriptstring.cpp \ + $$PWD/qdeclarativeobjectscriptclass.cpp \ + $$PWD/qdeclarativecontextscriptclass.cpp \ + $$PWD/qdeclarativeglobalscriptclass.cpp \ + $$PWD/qdeclarativevaluetypescriptclass.cpp \ + $$PWD/qdeclarativetypenamescriptclass.cpp \ + $$PWD/qdeclarativelistscriptclass.cpp \ + $$PWD/qdeclarativeworkerscript.cpp \ + $$PWD/qdeclarativeimageprovider.cpp \ + $$PWD/qdeclarativenetworkaccessmanagerfactory.cpp \ + $$PWD/qdeclarativedirparser.cpp \ + $$PWD/qdeclarativeextensionplugin.cpp \ + $$PWD/qdeclarativeimport.cpp \ + $$PWD/qdeclarativelist.cpp \ + $$PWD/qperformancetimer.cpp + +HEADERS += \ + $$PWD/qdeclarativeparser_p.h \ + $$PWD/qdeclarativeglobal_p.h \ + $$PWD/qdeclarativeinstruction_p.h \ + $$PWD/qdeclarativevmemetaobject_p.h \ + $$PWD/qdeclarative.h \ + $$PWD/qdeclarativebinding_p.h \ + $$PWD/qdeclarativebinding_p_p.h \ + $$PWD/qdeclarativeproperty.h \ + $$PWD/qdeclarativecomponent.h \ + $$PWD/qdeclarativecomponent_p.h \ + $$PWD/qdeclarativecustomparser_p.h \ + $$PWD/qdeclarativecustomparser_p_p.h \ + $$PWD/qdeclarativepropertyvaluesource.h \ + $$PWD/qdeclarativepropertyvalueinterceptor.h \ + $$PWD/qdeclarativeboundsignal_p.h \ + $$PWD/qdeclarativeparserstatus.h \ + $$PWD/qdeclarativeproxymetaobject_p.h \ + $$PWD/qdeclarativevme_p.h \ + $$PWD/qdeclarativecompiler_p.h \ + $$PWD/qdeclarativeengine_p.h \ + $$PWD/qdeclarativeexpression_p.h \ + $$PWD/qdeclarativeprivate.h \ + $$PWD/qdeclarativedom_p.h \ + $$PWD/qdeclarativedom_p_p.h \ + $$PWD/qdeclarativerefcount_p.h \ + $$PWD/qdeclarativemetatype_p.h \ + $$PWD/qdeclarativeengine.h \ + $$PWD/qdeclarativecontext.h \ + $$PWD/qdeclarativeexpression.h \ + $$PWD/qdeclarativestringconverters_p.h \ + $$PWD/qdeclarativeinfo.h \ + $$PWD/qdeclarativeproperty_p.h \ + $$PWD/qdeclarativecontext_p.h \ + $$PWD/qdeclarativeinclude_p.h \ + $$PWD/qdeclarativetypeloader_p.h \ + $$PWD/qdeclarativelist.h \ + $$PWD/qdeclarativelist_p.h \ + $$PWD/qdeclarativedata_p.h \ + $$PWD/qdeclarativeerror.h \ + $$PWD/qdeclarativescriptparser_p.h \ + $$PWD/qdeclarativerewrite_p.h \ + $$PWD/qpodvector_p.h \ + $$PWD/qbitfield_p.h \ + $$PWD/qdeclarativevaluetype_p.h \ + $$PWD/qdeclarativecompiledbindings_p.h \ + $$PWD/qdeclarativefastproperties_p.h \ + $$PWD/qdeclarativexmlhttprequest_p.h \ + $$PWD/qdeclarativesqldatabase_p.h \ + $$PWD/qmetaobjectbuilder_p.h \ + $$PWD/qdeclarativewatcher_p.h \ + $$PWD/qdeclarativecleanup_p.h \ + $$PWD/qdeclarativepropertycache_p.h \ + $$PWD/qdeclarativenotifier_p.h \ + $$PWD/qdeclarativeintegercache_p.h \ + $$PWD/qdeclarativetypenotavailable_p.h \ + $$PWD/qdeclarativetypenamecache_p.h \ + $$PWD/qdeclarativescriptstring.h \ + $$PWD/qdeclarativeobjectscriptclass_p.h \ + $$PWD/qdeclarativecontextscriptclass_p.h \ + $$PWD/qdeclarativeglobalscriptclass_p.h \ + $$PWD/qdeclarativevaluetypescriptclass_p.h \ + $$PWD/qdeclarativetypenamescriptclass_p.h \ + $$PWD/qdeclarativelistscriptclass_p.h \ + $$PWD/qdeclarativeworkerscript_p.h \ + $$PWD/qdeclarativeguard_p.h \ + $$PWD/qdeclarativeimageprovider.h \ + $$PWD/qdeclarativenetworkaccessmanagerfactory.h \ + $$PWD/qdeclarativedirparser_p.h \ + $$PWD/qdeclarativeextensioninterface.h \ + $$PWD/qdeclarativeimport_p.h \ + $$PWD/qdeclarativeextensionplugin.h \ + $$PWD/qperformancetimer_p.h + +QT += sql +include(parser/parser.pri) +include(rewriter/rewriter.pri) + +# mirrors logic in corelib/kernel/kernel.pri +unix:!symbian: contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri) diff --git a/src/declarative/qml/qperformancetimer.cpp b/src/declarative/qml/qperformancetimer.cpp new file mode 100644 index 00000000..b67bee4b --- /dev/null +++ b/src/declarative/qml/qperformancetimer.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qperformancetimer_p.h" + +#if defined(Q_OS_MAC) +#include <sys/time.h> +#include <unistd.h> +#include <mach/mach_time.h> +#elif defined(Q_OS_SYMBIAN) +#include <e32std.h> +#include <sys/time.h> +#include <hal.h> +#include <hal_data.h> +#elif defined(Q_OS_UNIX) +#include <sys/time.h> +#include <time.h> +#include <unistd.h> +#elif defined(Q_OS_WIN) +#include <windows.h> +#endif + +// mac/unix code heavily copied from QElapsedTimer + +QT_BEGIN_NAMESPACE + +////////////////////////////// Mac ////////////////////////////// +#if defined(Q_OS_MAC) + +static mach_timebase_info_data_t info = {0,0}; +static qint64 absoluteToNSecs(qint64 cpuTime) +{ + if (info.denom == 0) + mach_timebase_info(&info); + qint64 nsecs = cpuTime * info.numer / info.denom; + return nsecs; +} + +void QPerformanceTimer::start() +{ + t1 = mach_absolute_time(); +} + +qint64 QPerformanceTimer::elapsed() const +{ + uint64_t cpu_time = mach_absolute_time(); + return absoluteToNSecs(cpu_time - t1); +} + +////////////////////////////// Symbian ////////////////////////////// +#elif defined(Q_OS_SYMBIAN) + +static qint64 getTimeFromTick(quint64 elapsed) +{ + static TInt freq = 0; + if (!freq) + HAL::Get(HALData::EFastCounterFrequency, freq); + + return (elapsed * 1000000000) / freq; +} + +void QPerformanceTimer::start() +{ + t1 = User::FastCounter(); +} + +qint64 QPerformanceTimer::elapsed() const +{ + return getTimeFromTick(User::FastCounter() - t1); +} + + +////////////////////////////// Unix ////////////////////////////// +#elif defined(Q_OS_UNIX) + +#if defined(QT_NO_CLOCK_MONOTONIC) || defined(QT_BOOTSTRAPPED) +// turn off the monotonic clock +# ifdef _POSIX_MONOTONIC_CLOCK +# undef _POSIX_MONOTONIC_CLOCK +# endif +# define _POSIX_MONOTONIC_CLOCK -1 +#endif + +#if (_POSIX_MONOTONIC_CLOCK-0 != 0) +static const bool monotonicClockChecked = true; +static const bool monotonicClockAvailable = _POSIX_MONOTONIC_CLOCK > 0; +#else +static int monotonicClockChecked = false; +static int monotonicClockAvailable = false; +#endif + +#ifdef Q_CC_GNU +# define is_likely(x) __builtin_expect((x), 1) +#else +# define is_likely(x) (x) +#endif +#define load_acquire(x) ((volatile const int&)(x)) +#define store_release(x,v) ((volatile int&)(x) = (v)) + +static void unixCheckClockType() +{ +#if (_POSIX_MONOTONIC_CLOCK-0 == 0) + if (is_likely(load_acquire(monotonicClockChecked))) + return; + +# if defined(_SC_MONOTONIC_CLOCK) + // detect if the system support monotonic timers + long x = sysconf(_SC_MONOTONIC_CLOCK); + store_release(monotonicClockAvailable, x >= 200112L); +# endif + + store_release(monotonicClockChecked, true); +#endif +} + +static inline void do_gettime(qint64 *sec, qint64 *frac) +{ +#if (_POSIX_MONOTONIC_CLOCK-0 >= 0) + unixCheckClockType(); + if (is_likely(monotonicClockAvailable)) { + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + *sec = ts.tv_sec; + *frac = ts.tv_nsec; + return; + } +#endif + *sec = 0; + *frac = 0; +} + +void QPerformanceTimer::start() +{ + do_gettime(&t1, &t2); +} + +qint64 QPerformanceTimer::elapsed() const +{ + qint64 sec, frac; + do_gettime(&sec, &frac); + sec = sec - t1; + frac = frac - t2; + + return sec * Q_INT64_C(1000000000) + frac; +} + +////////////////////////////// Windows ////////////////////////////// +#elif defined(Q_OS_WIN) + +static qint64 getTimeFromTick(quint64 elapsed) +{ + static LARGE_INTEGER freq; + if (!freq.QuadPart) + QueryPerformanceFrequency(&freq); + return 1000000000 * elapsed / freq.QuadPart; +} + +void QPerformanceTimer::start() +{ + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + t1 = li.QuadPart; +} + +qint64 QPerformanceTimer::elapsed() const +{ + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + return getTimeFromTick(li.QuadPart - t1); +} + +////////////////////////////// Default ////////////////////////////// +#else + +// default implementation (no hi-perf timer) does nothing +void QPerformanceTimer::start() +{ +} + +qint64 QPerformanceTimer::elapsed() const +{ + return 0; +} + +#endif + +QT_END_NAMESPACE + + diff --git a/src/declarative/qml/qperformancetimer_p.h b/src/declarative/qml/qperformancetimer_p.h new file mode 100644 index 00000000..b637cd70 --- /dev/null +++ b/src/declarative/qml/qperformancetimer_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPERFORMANCETIMER_P_H +#define QPERFORMANCETIMER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of moc. This header file may change from version to version without notice, +// or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_AUTOTEST_EXPORT QPerformanceTimer +{ +public: + void start(); + qint64 elapsed() const; + +private: + qint64 t1; + qint64 t2; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QPERFORMANCETIMER_P_H diff --git a/src/declarative/qml/qpodvector_p.h b/src/declarative/qml/qpodvector_p.h new file mode 100644 index 00000000..ee48e524 --- /dev/null +++ b/src/declarative/qml/qpodvector_p.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPODVECTOR_P_H +#define QPODVECTOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QDebug> + +QT_BEGIN_NAMESPACE + +template<class T, int Increment=1024> +class QPODVector +{ +public: + QPODVector() + : m_count(0), m_capacity(0), m_data(0) {} + ~QPODVector() { if (m_data) ::free(m_data); } + + const T &at(int idx) const { + return m_data[idx]; + } + + T &operator[](int idx) { + return m_data[idx]; + } + + void clear() { + m_count = 0; + } + + void prepend(const T &v) { + insert(0, v); + } + + void append(const T &v) { + insert(m_count, v); + } + + void insert(int idx, const T &v) { + if (m_count == m_capacity) { + m_capacity += Increment; + m_data = (T *)q_check_ptr(realloc(m_data, m_capacity * sizeof(T))); + } + int moveCount = m_count - idx; + if (moveCount) + ::memmove(m_data + idx + 1, m_data + idx, moveCount * sizeof(T)); + m_count++; + m_data[idx] = v; + } + + void reserve(int count) { + if (count >= m_capacity) { + m_capacity = (count + (Increment-1)) & (0xFFFFFFFF - Increment + 1); + m_data = (T *)q_check_ptr(realloc(m_data, m_capacity * sizeof(T))); + } + } + + void insertBlank(int idx, int count) { + int newSize = m_count + count; + reserve(newSize); + int moveCount = m_count - idx; + if (moveCount) + ::memmove(m_data + idx + count, m_data + idx, + moveCount * sizeof(T)); + m_count = newSize; + } + + void remove(int idx, int count = 1) { + int moveCount = m_count - (idx + count); + if (moveCount) + ::memmove(m_data + idx, m_data + idx + count, + moveCount * sizeof(T)); + m_count -= count; + } + + void removeOne(const T &v) { + int idx = 0; + while (idx < m_count) { + if (m_data[idx] == v) { + remove(idx); + return; + } + ++idx; + } + } + + int find(const T &v) { + for (int idx = 0; idx < m_count; ++idx) + if (m_data[idx] == v) + return idx; + return -1; + } + + bool contains(const T &v) { + return find(v) != -1; + } + + int count() const { + return m_count; + } + + void copyAndClear(QPODVector<T,Increment> &other) { + if (other.m_data) ::free(other.m_data); + other.m_count = m_count; + other.m_capacity = m_capacity; + other.m_data = m_data; + m_count = 0; + m_capacity = 0; + m_data = 0; + } + + QPODVector<T,Increment> &operator<<(const T &v) { append(v); return *this; } +private: + QPODVector(const QPODVector &); + QPODVector &operator=(const QPODVector &); + int m_count; + int m_capacity; + T *m_data; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/rewriter/rewriter.pri b/src/declarative/qml/rewriter/rewriter.pri new file mode 100644 index 00000000..a9fa1b57 --- /dev/null +++ b/src/declarative/qml/rewriter/rewriter.pri @@ -0,0 +1,4 @@ +INCLUDEPATH += $$PWD + +HEADERS += $$PWD/textwriter_p.h +SOURCES += $$PWD/textwriter.cpp diff --git a/src/declarative/qml/rewriter/textwriter.cpp b/src/declarative/qml/rewriter/textwriter.cpp new file mode 100644 index 00000000..6d07d3f9 --- /dev/null +++ b/src/declarative/qml/rewriter/textwriter.cpp @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/textwriter_p.h" + +QT_QML_BEGIN_NAMESPACE + +using namespace QDeclarativeJS; + +TextWriter::TextWriter() + :string(0), cursor(0) +{ +} + +static bool overlaps(int posA, int lengthA, int posB, int lengthB) { + return (posA < posB + lengthB && posA + lengthA > posB + lengthB) + || (posA < posB && posA + lengthA > posB); +} + +bool TextWriter::hasOverlap(int pos, int length) +{ + { + QListIterator<Replace> i(replaceList); + while (i.hasNext()) { + const Replace &cmd = i.next(); + if (overlaps(pos, length, cmd.pos, cmd.length)) + return true; + } + } + { + QListIterator<Move> i(moveList); + while (i.hasNext()) { + const Move &cmd = i.next(); + if (overlaps(pos, length, cmd.pos, cmd.length)) + return true; + } + return false; + } +} + +bool TextWriter::hasMoveInto(int pos, int length) +{ + QListIterator<Move> i(moveList); + while (i.hasNext()) { + const Move &cmd = i.next(); + if (cmd.to >= pos && cmd.to < pos + length) + return true; + } + return false; +} + +void TextWriter::replace(int pos, int length, const QString &replacement) +{ + Q_ASSERT(!hasOverlap(pos, length)); + Q_ASSERT(!hasMoveInto(pos, length)); + + Replace cmd; + cmd.pos = pos; + cmd.length = length; + cmd.replacement = replacement; + replaceList += cmd; +} + +void TextWriter::move(int pos, int length, int to) +{ + Q_ASSERT(!hasOverlap(pos, length)); + + Move cmd; + cmd.pos = pos; + cmd.length = length; + cmd.to = to; + moveList += cmd; +} + +void TextWriter::doReplace(const Replace &replace) +{ + int diff = replace.replacement.size() - replace.length; + { + QMutableListIterator<Replace> i(replaceList); + while (i.hasNext()) { + Replace &c = i.next(); + if (replace.pos < c.pos) + c.pos += diff; + else if (replace.pos + replace.length < c.pos + c.length) + c.length += diff; + } + } + { + QMutableListIterator<Move> i(moveList); + while (i.hasNext()) { + Move &c = i.next(); + if (replace.pos < c.pos) + c.pos += diff; + else if (replace.pos + replace.length < c.pos + c.length) + c.length += diff; + + if (replace.pos < c.to) + c.to += diff; + } + } + + if (string) { + string->replace(replace.pos, replace.length, replace.replacement); + } else if (cursor) { + cursor->setPosition(replace.pos); + cursor->setPosition(replace.pos + replace.length, QTextCursor::KeepAnchor); + cursor->insertText(replace.replacement); + } +} + +void TextWriter::doMove(const Move &move) +{ + QString text; + if (string) { + text = string->mid(move.pos, move.length); + } else if (cursor) { + cursor->setPosition(move.pos); + cursor->setPosition(move.pos + move.length, QTextCursor::KeepAnchor); + text = cursor->selectedText(); + } + + Replace cut; + cut.pos = move.pos; + cut.length = move.length; + Replace paste; + paste.pos = move.to; + paste.length = 0; + paste.replacement = text; + + replaceList.append(cut); + replaceList.append(paste); + + Replace cmd; + while (!replaceList.isEmpty()) { + cmd = replaceList.first(); + replaceList.removeFirst(); + doReplace(cmd); + } +} + +void TextWriter::write(QString *s) +{ + string = s; + write_helper(); + string = 0; +} + +void TextWriter::write(QTextCursor *textCursor) +{ + cursor = textCursor; + write_helper(); + cursor = 0; +} + +void TextWriter::write_helper() +{ + if (cursor) + cursor->beginEditBlock(); + { + Replace cmd; + while (!replaceList.isEmpty()) { + cmd = replaceList.first(); + replaceList.removeFirst(); + doReplace(cmd); + } + } + { + Move cmd; + while (!moveList.isEmpty()) { + cmd = moveList.first(); + moveList.removeFirst(); + doMove(cmd); + } + } + if (cursor) + cursor->endEditBlock(); +} + +QT_QML_END_NAMESPACE diff --git a/src/declarative/qml/rewriter/textwriter_p.h b/src/declarative/qml/rewriter/textwriter_p.h new file mode 100644 index 00000000..472539d5 --- /dev/null +++ b/src/declarative/qml/rewriter/textwriter_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TEXTWRITER_H +#define TEXTWRITER_H + +#include <qdeclarativejsglobal_p.h> + +#include <QtCore/QString> +#include <QtCore/QList> +#include <QtGui/QTextCursor> + +QT_BEGIN_HEADER +QT_QML_BEGIN_NAMESPACE + +namespace QDeclarativeJS { + +class TextWriter +{ + QString *string; + QTextCursor *cursor; + + struct Replace { + int pos; + int length; + QString replacement; + }; + + QList<Replace> replaceList; + + struct Move { + int pos; + int length; + int to; + }; + + QList<Move> moveList; + + bool hasOverlap(int pos, int length); + bool hasMoveInto(int pos, int length); + + void doReplace(const Replace &replace); + void doMove(const Move &move); + + void write_helper(); + +public: + TextWriter(); + + void replace(int pos, int length, const QString &replacement); + void move(int pos, int length, int to); + + void write(QString *s); + void write(QTextCursor *textCursor); + +}; + +} // end of namespace QDeclarativeJS + +QT_QML_END_NAMESPACE +QT_END_HEADER + +#endif // TEXTWRITER_H |