| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  | /**************************************************************************
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** This file is part of Qt Creator | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2011-01-11 16:28:15 +01:00
										 |  |  | ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2011-04-13 08:42:33 +02:00
										 |  |  | ** Contact: Nokia Corporation (info@qt.nokia.com) | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  | ** | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** GNU Lesser General Public License Usage | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2011-04-13 08:42:33 +02:00
										 |  |  | ** 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.
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2010-12-17 16:01:08 +01:00
										 |  |  | ** In addition, as a special exception, Nokia gives you certain additional | 
					
						
							| 
									
										
										
										
											2011-04-13 08:42:33 +02:00
										 |  |  | ** rights. These rights are described in the Nokia Qt LGPL Exception | 
					
						
							| 
									
										
										
										
											2010-12-17 16:01:08 +01:00
										 |  |  | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2011-04-13 08:42:33 +02:00
										 |  |  | ** 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. | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2010-12-17 16:01:08 +01:00
										 |  |  | ** If you have questions regarding the use of this file, please contact | 
					
						
							| 
									
										
										
										
											2011-05-06 15:05:37 +02:00
										 |  |  | ** Nokia at info@qt.nokia.com. | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  | ** | 
					
						
							|  |  |  | **************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "qmljspropertyreader.h"
 | 
					
						
							|  |  |  | #include "qmljsdocument.h"
 | 
					
						
							|  |  |  | #include <qmljs/parser/qmljsast_p.h>
 | 
					
						
							| 
									
										
										
										
											2010-08-13 13:26:44 +02:00
										 |  |  | #include <qmljs/qmljscheck.h>
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-20 14:03:07 +01:00
										 |  |  | #include <QtGui/QLinearGradient>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  | namespace QmlJS { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace AST; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline QString deEscape(const QString &value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QString result = value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     result.replace(QLatin1String("\\\\"), QLatin1String("\\")); | 
					
						
							|  |  |  |     result.replace(QLatin1String("\\\""), QLatin1String("\"")); | 
					
						
							|  |  |  |     result.replace(QLatin1String("\\\t"), QLatin1String("\t")); | 
					
						
							|  |  |  |     result.replace(QLatin1String("\\\r"), QLatin1String("\r")); | 
					
						
							|  |  |  |     result.replace(QLatin1String("\\\n"), QLatin1String("\n")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline QString stripQuotes(const QString &str) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"'))) | 
					
						
							|  |  |  |             || (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\'')))) | 
					
						
							|  |  |  |         return str.mid(1, str.length() - 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return str; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool isLiteralValue(ExpressionNode *expr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (cast<NumericLiteral*>(expr)) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     else if (cast<StringLiteral*>(expr)) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     else if (UnaryPlusExpression *plusExpr = cast<UnaryPlusExpression*>(expr)) | 
					
						
							|  |  |  |         return isLiteralValue(plusExpr->expression); | 
					
						
							|  |  |  |     else if (UnaryMinusExpression *minusExpr = cast<UnaryMinusExpression*>(expr)) | 
					
						
							|  |  |  |         return isLiteralValue(minusExpr->expression); | 
					
						
							|  |  |  |     else if (cast<TrueLiteral*>(expr)) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     else if (cast<FalseLiteral*>(expr)) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool isLiteralValue(UiScriptBinding *script) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!script || !script->statement) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ExpressionStatement *exprStmt = cast<ExpressionStatement *>(script->statement); | 
					
						
							|  |  |  |     if (exprStmt) | 
					
						
							|  |  |  |         return isLiteralValue(exprStmt->expression); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  | static inline QString textAt(const Document::Ptr doc, | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |                                   const SourceLocation &from, | 
					
						
							|  |  |  |                                   const SourceLocation &to) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return doc->source().mid(from.offset, to.end() - from.begin()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int propertyType(const QString &typeName) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (typeName == QLatin1String("bool")) | 
					
						
							|  |  |  |         return QMetaType::type("bool"); | 
					
						
							|  |  |  |     else if (typeName == QLatin1String("color")) | 
					
						
							|  |  |  |         return QMetaType::type("QColor"); | 
					
						
							|  |  |  |     else if (typeName == QLatin1String("date")) | 
					
						
							|  |  |  |         return QMetaType::type("QDate"); | 
					
						
							|  |  |  |     else if (typeName == QLatin1String("int")) | 
					
						
							|  |  |  |         return QMetaType::type("int"); | 
					
						
							|  |  |  |     else if (typeName == QLatin1String("real")) | 
					
						
							|  |  |  |         return QMetaType::type("double"); | 
					
						
							|  |  |  |     else if (typeName == QLatin1String("double")) | 
					
						
							|  |  |  |         return QMetaType::type("double"); | 
					
						
							|  |  |  |     else if (typeName == QLatin1String("string")) | 
					
						
							|  |  |  |         return QMetaType::type("QString"); | 
					
						
							|  |  |  |     else if (typeName == QLatin1String("url")) | 
					
						
							|  |  |  |         return QMetaType::type("QUrl"); | 
					
						
							|  |  |  |     else if (typeName == QLatin1String("variant")) | 
					
						
							|  |  |  |         return QMetaType::type("QVariant"); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline QString flatten(UiQualifiedId *qualifiedId) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QString result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) { | 
					
						
							| 
									
										
										
										
											2011-09-13 09:57:24 +02:00
										 |  |  |         if (iter->name.isEmpty()) | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |             continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!result.isEmpty()) | 
					
						
							|  |  |  |             result.append(QLatin1Char('.')); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-13 09:57:24 +02:00
										 |  |  |         result.append(iter->name); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool isEnum(AST::Statement *ast); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool isEnum(AST::ExpressionNode *ast) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!ast) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (FieldMemberExpression *memberExpr = cast<AST::FieldMemberExpression*>(ast)) | 
					
						
							|  |  |  |         return isEnum(memberExpr->base); | 
					
						
							|  |  |  |     else if (cast<IdentifierExpression*>(ast)) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool isEnum(AST::Statement *ast) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!ast) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ExpressionStatement *exprStmt = cast<ExpressionStatement*>(ast)) { | 
					
						
							|  |  |  |         return isEnum(exprStmt->expression); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-09 18:09:01 +02:00
										 |  |  | static QString cleanupSemicolon(const QString &str) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QString out = str; | 
					
						
							|  |  |  |     while (out.endsWith(QLatin1Char(';'))) | 
					
						
							|  |  |  |         out.chop(1); | 
					
						
							|  |  |  |     return out; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  | PropertyReader::PropertyReader(Document::Ptr doc, AST::UiObjectInitializer *ast) | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  |     m_ast = ast; | 
					
						
							|  |  |  |     m_doc = doc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!m_doc) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |     for (UiObjectMemberList *members = ast->members; members; members = members->next) { | 
					
						
							|  |  |  |         UiObjectMember *member = members->member; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (UiScriptBinding *property = AST::cast<UiScriptBinding *>(member)) { | 
					
						
							|  |  |  |             if (!property->qualifiedId) | 
					
						
							|  |  |  |                 continue; // better safe than sorry.
 | 
					
						
							|  |  |  |             const QString propertyName = flatten(property->qualifiedId); | 
					
						
							| 
									
										
										
										
											2010-07-09 18:09:01 +02:00
										 |  |  |             const QString astValue = cleanupSemicolon(textAt(doc, | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |                               property->statement->firstSourceLocation(), | 
					
						
							| 
									
										
										
										
											2010-07-09 18:09:01 +02:00
										 |  |  |                               property->statement->lastSourceLocation())); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |             if (isLiteralValue(property)) { | 
					
						
							|  |  |  |                 m_properties.insert(propertyName, QVariant(deEscape(stripQuotes(astValue)))); | 
					
						
							|  |  |  |             } else if (isEnum(property->statement)) { //enum
 | 
					
						
							|  |  |  |                  m_properties.insert(propertyName, QVariant(astValue)); | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  |                  m_bindingOrEnum.append(propertyName); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } else if (UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(member)) { //font { bold: true }
 | 
					
						
							| 
									
										
										
										
											2011-09-13 09:57:24 +02:00
										 |  |  |             const QString propertyName = objectDefinition->qualifiedTypeNameId->name.toString(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |             if (!propertyName.isEmpty() && !propertyName.at(0).isUpper()) { | 
					
						
							|  |  |  |                 for (UiObjectMemberList *iter = objectDefinition->initializer->members; iter; iter = iter->next) { | 
					
						
							|  |  |  |                     UiObjectMember *objectMember = iter->member; | 
					
						
							|  |  |  |                     if (UiScriptBinding *property = cast<UiScriptBinding *>(objectMember)) { | 
					
						
							|  |  |  |                         const QString propertyNamePart2 = flatten(property->qualifiedId); | 
					
						
							| 
									
										
										
										
											2010-07-09 18:09:01 +02:00
										 |  |  |                         const QString astValue = cleanupSemicolon(textAt(doc, | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |                             property->statement->firstSourceLocation(), | 
					
						
							| 
									
										
										
										
											2010-07-09 18:09:01 +02:00
										 |  |  |                             property->statement->lastSourceLocation())); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |                         if (isLiteralValue(property)) { | 
					
						
							|  |  |  |                             m_properties.insert(propertyName + '.' + propertyNamePart2, QVariant(deEscape(stripQuotes(astValue)))); | 
					
						
							|  |  |  |                         } else if (isEnum(property->statement)) { //enum
 | 
					
						
							|  |  |  |                             m_properties.insert(propertyName + '.' + propertyNamePart2, QVariant(astValue)); | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  |                             m_bindingOrEnum.append(propertyName + '.' + propertyNamePart2); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (UiObjectBinding* objectBinding = cast<UiObjectBinding *>(member)) { | 
					
						
							|  |  |  |             UiObjectInitializer *initializer = objectBinding->initializer; | 
					
						
							|  |  |  |             const QString astValue = cleanupSemicolon(textAt(doc, | 
					
						
							|  |  |  |                               initializer->lbraceToken, | 
					
						
							|  |  |  |                               initializer->rbraceToken)); | 
					
						
							| 
									
										
										
										
											2011-09-13 09:57:24 +02:00
										 |  |  |             const QString propertyName = objectBinding->qualifiedId->name.toString(); | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  |             m_properties.insert(propertyName, QVariant(astValue)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-21 12:57:11 +02:00
										 |  |  | QLinearGradient PropertyReader::parseGradient(const QString &propertyName,  bool *isBound) const | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!m_doc) | 
					
						
							|  |  |  |         return QLinearGradient(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-21 12:57:11 +02:00
										 |  |  |     *isBound = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  |     for (UiObjectMemberList *members = m_ast->members; members; members = members->next) { | 
					
						
							|  |  |  |         UiObjectMember *member = members->member; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (UiObjectBinding* objectBinding = cast<UiObjectBinding *>(member)) { | 
					
						
							|  |  |  |             UiObjectInitializer *initializer = objectBinding->initializer; | 
					
						
							|  |  |  |             const QString astValue = cleanupSemicolon(textAt(m_doc, | 
					
						
							|  |  |  |                                                              initializer->lbraceToken, | 
					
						
							|  |  |  |                                                              initializer->rbraceToken)); | 
					
						
							| 
									
										
										
										
											2011-09-13 09:57:24 +02:00
										 |  |  |             const QString objectPropertyName = objectBinding->qualifiedId->name.toString(); | 
					
						
							|  |  |  |             const QString typeName = objectBinding->qualifiedTypeNameId->name.toString(); | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  |             if (objectPropertyName == propertyName && typeName.contains("Gradient")) { | 
					
						
							|  |  |  |                 QLinearGradient gradient; | 
					
						
							|  |  |  |                 QVector<QGradientStop> stops; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 for (UiObjectMemberList *members = initializer->members; members; members = members->next) { | 
					
						
							|  |  |  |                     UiObjectMember *member = members->member; | 
					
						
							|  |  |  |                     if (UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(member)) { | 
					
						
							|  |  |  |                         PropertyReader localParser(m_doc, objectDefinition->initializer); | 
					
						
							|  |  |  |                         if (localParser.hasProperty("color") && localParser.hasProperty("position")) { | 
					
						
							| 
									
										
										
										
											2010-08-13 13:26:44 +02:00
										 |  |  |                             QColor color = QmlJS::toQColor(localParser.readProperty("color").toString()); | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  |                             qreal position = localParser.readProperty("position").toReal(); | 
					
						
							| 
									
										
										
										
											2010-07-21 12:57:11 +02:00
										 |  |  |                             if (localParser.isBindingOrEnum("color") || localParser.isBindingOrEnum("position")) | 
					
						
							|  |  |  |                                 *isBound = true; | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  |                             stops.append( QPair<qreal, QColor>(position, color)); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 gradient.setStops(stops); | 
					
						
							|  |  |  |                 return gradient; | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  |     return QLinearGradient(); | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-15 14:12:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-30 17:51:21 +02:00
										 |  |  | } //QmlJS
 |