Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Marco Bubke
flatpak-qt-creator
Commits
b03ef971
Commit
b03ef971
authored
Apr 22, 2010
by
Erik Verbruggen
Browse files
Fixed reading of grouped properties.
Task-number: BAUHAUS-620
parent
071722fb
Changes
4
Hide whitespace changes
Inline
Side-by-side
src/plugins/qmldesigner/core/model/texttomodelmerger.cpp
View file @
b03ef971
...
...
@@ -62,7 +62,7 @@ static inline QString stripQuotes(const QString &str)
return
str
;
}
static
inline
QString
descape
(
const
QString
&
value
)
static
inline
QString
de
E
scape
(
const
QString
&
value
)
{
QString
result
=
value
;
...
...
@@ -157,7 +157,7 @@ static inline int propertyType(const QString &typeName)
static
inline
QVariant
convertDynamicPropertyValueToVariant
(
const
QString
&
astValue
,
const
QString
&
astType
)
{
const
QString
cleanedValue
=
descape
(
stripQuotes
(
astValue
.
trimmed
()));
const
QString
cleanedValue
=
de
E
scape
(
stripQuotes
(
astValue
.
trimmed
()));
if
(
astType
.
isEmpty
())
return
QString
();
...
...
@@ -228,7 +228,7 @@ public:
/// When something is changed here, also change Check::checkScopeObjectMember in
/// qmljscheck.cpp
/// ### Maybe put this into the context as a helper method.
bool
lookupProperty
(
const
UiQualifiedId
*
id
,
const
Interpreter
::
Value
**
property
=
0
,
const
Interpreter
::
ObjectValue
**
parentObject
=
0
,
QString
*
name
=
0
)
bool
lookupProperty
(
const
QString
&
prefix
,
const
UiQualifiedId
*
id
,
const
Interpreter
::
Value
**
property
=
0
,
const
Interpreter
::
ObjectValue
**
parentObject
=
0
,
QString
*
name
=
0
)
{
QList
<
const
Interpreter
::
ObjectValue
*>
scopeObjects
=
m_context
->
scopeChain
().
qmlScopeObjects
;
if
(
scopeObjects
.
isEmpty
())
...
...
@@ -240,7 +240,12 @@ public:
if
(
!
id
->
name
)
// possible after error recovery
return
false
;
QString
propertyName
=
id
->
name
->
asString
();
QString
propertyName
;
if
(
prefix
.
isEmpty
())
propertyName
=
id
->
name
->
asString
();
else
propertyName
=
prefix
;
if
(
name
)
*
name
=
propertyName
;
...
...
@@ -279,7 +284,9 @@ public:
// member lookup
const
UiQualifiedId
*
idPart
=
id
;
while
(
idPart
->
next
)
{
if
(
prefix
.
isEmpty
())
idPart
=
idPart
->
next
;
for
(;
idPart
;
idPart
=
idPart
->
next
)
{
objectValue
=
Interpreter
::
value_cast
<
const
Interpreter
::
ObjectValue
*>
(
value
);
if
(
!
objectValue
)
{
// if (idPart->name)
...
...
@@ -290,13 +297,12 @@ public:
if
(
parentObject
)
*
parentObject
=
objectValue
;
if
(
!
idPart
->
next
->
name
)
{
if
(
!
idPart
->
name
)
{
// somebody typed "id." and error recovery still gave us a valid tree,
// so just bail out here.
return
false
;
}
idPart
=
idPart
->
next
;
propertyName
=
idPart
->
name
->
asString
();
if
(
name
)
*
name
=
propertyName
;
...
...
@@ -335,14 +341,14 @@ public:
return
false
;
}
QVariant
convertToVariant
(
const
QString
&
astValue
,
UiQualifiedId
*
propertyId
)
QVariant
convertToVariant
(
const
QString
&
astValue
,
const
QString
&
propertyPrefix
,
UiQualifiedId
*
propertyId
)
{
const
QString
cleanedValue
=
descape
(
stripQuotes
(
astValue
.
trimmed
()));
const
QString
cleanedValue
=
de
E
scape
(
stripQuotes
(
astValue
.
trimmed
()));
const
Interpreter
::
Value
*
property
=
0
;
const
Interpreter
::
ObjectValue
*
containingObject
=
0
;
QString
name
;
if
(
!
lookupProperty
(
propertyId
,
&
property
,
&
containingObject
,
&
name
))
{
qWarning
()
<<
"Unknown property"
<<
flatten
(
propertyId
)
if
(
!
lookupProperty
(
propertyPrefix
,
propertyId
,
&
property
,
&
containingObject
,
&
name
))
{
qWarning
()
<<
"Unknown property"
<<
propertyPrefix
+
QLatin1Char
(
'.'
)
+
flatten
(
propertyId
)
<<
"on line"
<<
propertyId
->
identifierToken
.
startLine
<<
"column"
<<
propertyId
->
identifierToken
.
startColumn
;
return
QVariant
(
cleanedValue
);
...
...
@@ -384,7 +390,7 @@ public:
return
v
;
}
QVariant
convertToEnum
(
Statement
*
rhs
,
UiQualifiedId
*
propertyId
)
QVariant
convertToEnum
(
Statement
*
rhs
,
const
QString
&
propertyPrefix
,
UiQualifiedId
*
propertyId
)
{
ExpressionStatement
*
eStmt
=
cast
<
ExpressionStatement
*>
(
rhs
);
if
(
!
eStmt
||
!
eStmt
->
expression
)
...
...
@@ -392,7 +398,7 @@ public:
const
Interpreter
::
ObjectValue
*
containingObject
=
0
;
QString
name
;
if
(
!
lookupProperty
(
propertyId
,
0
,
&
containingObject
,
&
name
))
{
if
(
!
lookupProperty
(
propertyPrefix
,
propertyId
,
0
,
&
containingObject
,
&
name
))
{
return
QVariant
();
}
...
...
@@ -640,7 +646,7 @@ void TextToModelMerger::syncNode(ModelNode &modelNode,
if
(
UiArrayBinding
*
array
=
cast
<
UiArrayBinding
*>
(
member
))
{
const
QString
astPropertyName
=
flatten
(
array
->
qualifiedId
);
if
(
typeName
==
QLatin1String
(
"Qt/PropertyChanges"
)
||
context
->
lookupProperty
(
array
->
qualifiedId
))
{
if
(
typeName
==
QLatin1String
(
"Qt/PropertyChanges"
)
||
context
->
lookupProperty
(
QString
(),
array
->
qualifiedId
))
{
AbstractProperty
modelProperty
=
modelNode
.
property
(
astPropertyName
);
QList
<
UiObjectMember
*>
arrayMembers
;
for
(
UiArrayMemberList
*
iter
=
array
->
members
;
iter
;
iter
=
iter
->
next
)
...
...
@@ -653,8 +659,19 @@ void TextToModelMerger::syncNode(ModelNode &modelNode,
qWarning
()
<<
"Skipping invalid array property"
<<
astPropertyName
<<
"for node type"
<<
modelNode
.
type
();
}
}
else
if
(
cast
<
UiObjectDefinition
*>
(
member
))
{
defaultPropertyItems
.
append
(
member
);
}
else
if
(
UiObjectDefinition
*
def
=
cast
<
UiObjectDefinition
*>
(
member
))
{
const
QString
name
=
def
->
qualifiedTypeNameId
->
name
->
asString
();
if
(
name
.
isEmpty
()
||
!
name
.
at
(
0
).
isUpper
())
{
QStringList
props
=
syncGroupedProperties
(
modelNode
,
name
,
def
->
initializer
->
members
,
context
,
differenceHandler
);
foreach
(
const
QString
&
prop
,
props
)
modelPropertyNames
.
remove
(
prop
);
}
else
{
defaultPropertyItems
.
append
(
member
);
}
}
else
if
(
UiObjectBinding
*
binding
=
cast
<
UiObjectBinding
*>
(
member
))
{
const
QString
astPropertyName
=
flatten
(
binding
->
qualifiedId
);
if
(
binding
->
hasOnToken
)
{
...
...
@@ -663,7 +680,7 @@ void TextToModelMerger::syncNode(ModelNode &modelNode,
const
Interpreter
::
Value
*
propertyType
=
0
;
const
Interpreter
::
ObjectValue
*
containingObject
=
0
;
QString
name
;
if
(
context
->
lookupProperty
(
binding
->
qualifiedId
,
&
propertyType
,
&
containingObject
,
&
name
)
||
typeName
==
QLatin1String
(
"Qt/PropertyChanges"
))
{
if
(
context
->
lookupProperty
(
QString
(),
binding
->
qualifiedId
,
&
propertyType
,
&
containingObject
,
&
name
)
||
typeName
==
QLatin1String
(
"Qt/PropertyChanges"
))
{
AbstractProperty
modelProperty
=
modelNode
.
property
(
astPropertyName
);
if
(
context
->
isArrayProperty
(
propertyType
,
containingObject
,
name
))
{
syncArrayProperty
(
modelProperty
,
QList
<
QmlJS
::
AST
::
UiObjectMember
*>
()
<<
member
,
context
,
differenceHandler
);
...
...
@@ -677,59 +694,7 @@ void TextToModelMerger::syncNode(ModelNode &modelNode,
}
}
}
else
if
(
UiScriptBinding
*
script
=
cast
<
UiScriptBinding
*>
(
member
))
{
const
QString
astPropertyName
=
flatten
(
script
->
qualifiedId
);
QString
astValue
;
if
(
script
->
statement
)
{
astValue
=
textAt
(
context
->
doc
(),
script
->
statement
->
firstSourceLocation
(),
script
->
statement
->
lastSourceLocation
());
astValue
=
astValue
.
trimmed
();
if
(
astValue
.
endsWith
(
QLatin1Char
(
';'
)))
astValue
=
astValue
.
left
(
astValue
.
length
()
-
1
);
astValue
=
astValue
.
trimmed
();
}
if
(
astPropertyName
==
QLatin1String
(
"id"
))
{
syncNodeId
(
modelNode
,
astValue
,
differenceHandler
);
}
else
if
(
isSignalPropertyName
(
astPropertyName
))
{
// skip signals
}
else
if
(
isLiteralValue
(
script
))
{
if
(
typeName
==
QLatin1String
(
"Qt/PropertyChanges"
))
{
AbstractProperty
modelProperty
=
modelNode
.
property
(
astPropertyName
);
const
QVariant
variantValue
(
descape
(
stripQuotes
(
astValue
)));
syncVariantProperty
(
modelProperty
,
variantValue
,
QString
(),
differenceHandler
);
modelPropertyNames
.
remove
(
astPropertyName
);
}
else
{
const
QVariant
variantValue
=
context
->
convertToVariant
(
astValue
,
script
->
qualifiedId
);
if
(
variantValue
.
isValid
())
{
AbstractProperty
modelProperty
=
modelNode
.
property
(
astPropertyName
);
syncVariantProperty
(
modelProperty
,
variantValue
,
QString
(),
differenceHandler
);
modelPropertyNames
.
remove
(
astPropertyName
);
}
else
{
qWarning
()
<<
"Skipping invalid variant property"
<<
astPropertyName
<<
"for node type"
<<
modelNode
.
type
();
}
}
}
else
{
// First see if it is a qualified enum:
const
QVariant
enumValue
=
context
->
convertToEnum
(
script
->
statement
,
script
->
qualifiedId
);
if
(
enumValue
.
isValid
())
{
const
QString
astPropertyName
=
flatten
(
script
->
qualifiedId
);
AbstractProperty
modelProperty
=
modelNode
.
property
(
astPropertyName
);
syncVariantProperty
(
modelProperty
,
enumValue
,
QString
(),
differenceHandler
);
modelPropertyNames
.
remove
(
astPropertyName
);
}
else
{
// apparently not, so:
if
(
typeName
==
QLatin1String
(
"Qt/PropertyChanges"
)
||
context
->
lookupProperty
(
script
->
qualifiedId
))
{
AbstractProperty
modelProperty
=
modelNode
.
property
(
astPropertyName
);
syncExpressionProperty
(
modelProperty
,
astValue
,
differenceHandler
);
modelPropertyNames
.
remove
(
astPropertyName
);
}
else
{
qWarning
()
<<
"Skipping invalid expression property"
<<
astPropertyName
<<
"for node type"
<<
modelNode
.
type
();
}
}
}
modelPropertyNames
.
remove
(
syncScriptBinding
(
modelNode
,
QString
(),
script
,
context
,
differenceHandler
));
}
else
if
(
UiPublicMember
*
property
=
cast
<
UiPublicMember
*>
(
member
))
{
if
(
property
->
type
==
UiPublicMember
::
Signal
)
continue
;
// QML designer doesn't support this yet.
...
...
@@ -786,6 +751,73 @@ void TextToModelMerger::syncNode(ModelNode &modelNode,
context
->
leaveScope
();
}
QString
TextToModelMerger
::
syncScriptBinding
(
ModelNode
&
modelNode
,
const
QString
&
prefix
,
UiScriptBinding
*
script
,
ReadingContext
*
context
,
DifferenceHandler
&
differenceHandler
)
{
QString
astPropertyName
=
flatten
(
script
->
qualifiedId
);
if
(
!
prefix
.
isEmpty
())
astPropertyName
.
prepend
(
prefix
+
QLatin1Char
(
'.'
));
QString
astValue
;
if
(
script
->
statement
)
{
astValue
=
textAt
(
context
->
doc
(),
script
->
statement
->
firstSourceLocation
(),
script
->
statement
->
lastSourceLocation
());
astValue
=
astValue
.
trimmed
();
if
(
astValue
.
endsWith
(
QLatin1Char
(
';'
)))
astValue
=
astValue
.
left
(
astValue
.
length
()
-
1
);
astValue
=
astValue
.
trimmed
();
}
if
(
astPropertyName
==
QLatin1String
(
"id"
))
{
syncNodeId
(
modelNode
,
astValue
,
differenceHandler
);
return
astPropertyName
;
}
if
(
isSignalPropertyName
(
astPropertyName
))
return
QString
();
if
(
isLiteralValue
(
script
))
{
if
(
modelNode
.
type
()
==
QLatin1String
(
"Qt/PropertyChanges"
))
{
AbstractProperty
modelProperty
=
modelNode
.
property
(
astPropertyName
);
const
QVariant
variantValue
(
deEscape
(
stripQuotes
(
astValue
)));
syncVariantProperty
(
modelProperty
,
variantValue
,
QString
(),
differenceHandler
);
return
astPropertyName
;
}
else
{
const
QVariant
variantValue
=
context
->
convertToVariant
(
astValue
,
prefix
,
script
->
qualifiedId
);
if
(
variantValue
.
isValid
())
{
AbstractProperty
modelProperty
=
modelNode
.
property
(
astPropertyName
);
syncVariantProperty
(
modelProperty
,
variantValue
,
QString
(),
differenceHandler
);
return
astPropertyName
;
}
else
{
qWarning
()
<<
"Skipping invalid variant property"
<<
astPropertyName
<<
"for node type"
<<
modelNode
.
type
();
return
QString
();
}
}
}
const
QVariant
enumValue
=
context
->
convertToEnum
(
script
->
statement
,
prefix
,
script
->
qualifiedId
);
if
(
enumValue
.
isValid
())
{
// It is a qualified enum:
AbstractProperty
modelProperty
=
modelNode
.
property
(
astPropertyName
);
syncVariantProperty
(
modelProperty
,
enumValue
,
QString
(),
differenceHandler
);
return
astPropertyName
;
}
else
{
// Not an enum, so:
if
(
modelNode
.
type
()
==
QLatin1String
(
"Qt/PropertyChanges"
)
||
context
->
lookupProperty
(
prefix
,
script
->
qualifiedId
))
{
AbstractProperty
modelProperty
=
modelNode
.
property
(
astPropertyName
);
syncExpressionProperty
(
modelProperty
,
astValue
,
differenceHandler
);
return
astPropertyName
;
}
else
{
qWarning
()
<<
"Skipping invalid expression property"
<<
astPropertyName
<<
"for node type"
<<
modelNode
.
type
();
return
QString
();
}
}
}
void
TextToModelMerger
::
syncNodeId
(
ModelNode
&
modelNode
,
const
QString
&
astObjectId
,
DifferenceHandler
&
differenceHandler
)
{
...
...
@@ -928,6 +960,27 @@ ModelNode TextToModelMerger::createModelNode(const QString &typeName,
return
newNode
;
}
QStringList
TextToModelMerger
::
syncGroupedProperties
(
ModelNode
&
modelNode
,
const
QString
&
name
,
UiObjectMemberList
*
members
,
ReadingContext
*
context
,
DifferenceHandler
&
differenceHandler
)
{
QStringList
props
;
for
(
UiObjectMemberList
*
iter
=
members
;
iter
;
iter
=
iter
->
next
)
{
UiObjectMember
*
member
=
iter
->
member
;
if
(
UiScriptBinding
*
script
=
cast
<
UiScriptBinding
*>
(
member
))
{
const
QString
prop
=
syncScriptBinding
(
modelNode
,
name
,
script
,
context
,
differenceHandler
);
if
(
!
prop
.
isEmpty
())
props
.
append
(
prop
);
}
}
return
props
;
}
void
ModelValidator
::
modelMissesImport
(
const
Import
&
import
)
{
Q_ASSERT
(
m_merger
->
view
()
->
model
()
->
imports
().
contains
(
import
));
...
...
src/plugins/qmldesigner/core/model/texttomodelmerger.h
View file @
b03ef971
...
...
@@ -34,8 +34,11 @@
#include
"import.h"
#include
"nodelistproperty.h"
#include
"modelnode.h"
#include
<qmljs/qmljsdocument.h>
#include
<QtCore/QStringList>
namespace
QmlDesigner
{
class
CORESHARED_EXPORT
RewriterView
;
...
...
@@ -68,6 +71,11 @@ public:
QmlJS
::
AST
::
UiObjectMember
*
astNode
,
ReadingContext
*
context
,
DifferenceHandler
&
differenceHandler
);
QString
syncScriptBinding
(
ModelNode
&
modelNode
,
const
QString
&
prefix
,
QmlJS
::
AST
::
UiScriptBinding
*
script
,
ReadingContext
*
context
,
DifferenceHandler
&
differenceHandler
);
void
syncNodeId
(
ModelNode
&
modelNode
,
const
QString
&
astObjectId
,
DifferenceHandler
&
differenceHandler
);
void
syncNodeProperty
(
AbstractProperty
&
modelProperty
,
...
...
@@ -95,6 +103,11 @@ public:
QmlJS
::
AST
::
UiObjectMember
*
astNode
,
ReadingContext
*
context
,
DifferenceHandler
&
differenceHandler
);
QStringList
syncGroupedProperties
(
ModelNode
&
modelNode
,
const
QString
&
name
,
QmlJS
::
AST
::
UiObjectMemberList
*
members
,
ReadingContext
*
context
,
DifferenceHandler
&
differenceHandler
);
private:
void
setupComponent
(
const
ModelNode
&
node
);
...
...
tests/auto/qml/qmldesigner/coretests/testcore.cpp
View file @
b03ef971
...
...
@@ -535,6 +535,38 @@ void TestCore::testRewriterDynamicProperties()
// QVERIFY(compareTree(testRewriterView1->rootModelNode(), testRewriterView2->rootModelNode()));
}
void
TestCore
::
testRewriterGroupedProperties
()
{
const
QLatin1String
qmlString
(
"
\n
"
"import Qt 4.6
\n
"
"
\n
"
"Text {
\n
"
" font {
\n
"
" pointSize: 10
\n
"
" underline: true
\n
"
" }
\n
"
"}"
);
QPlainTextEdit
textEdit1
;
textEdit1
.
setPlainText
(
qmlString
);
NotIndentingTextEditModifier
modifier1
(
&
textEdit1
);
QScopedPointer
<
Model
>
model1
(
Model
::
create
(
"Qt/Text"
));
QScopedPointer
<
TestRewriterView
>
testRewriterView1
(
new
TestRewriterView
());
testRewriterView1
->
setTextModifier
(
&
modifier1
);
model1
->
attachView
(
testRewriterView1
.
data
());
QVERIFY
(
testRewriterView1
->
errors
().
isEmpty
());
//
// text2model
//
ModelNode
rootModelNode
=
testRewriterView1
->
rootModelNode
();
QCOMPARE
(
rootModelNode
.
property
(
QLatin1String
(
"font.pointSize"
)).
toVariantProperty
().
value
().
toDouble
(),
10.0
);
QCOMPARE
(
rootModelNode
.
property
(
QLatin1String
(
"font.underline"
)).
toVariantProperty
().
value
().
toBool
(),
true
);
}
void
TestCore
::
loadSubItems
()
{
QFile
file
(
QString
(
QTCREATORDIR
)
+
"/tests/auto/qml/qmldesigner/data/fx/topitem.qml"
);
...
...
tests/auto/qml/qmldesigner/coretests/testcore.h
View file @
b03ef971
...
...
@@ -119,6 +119,7 @@ private slots:
void
testRewriterNodeSliding
();
void
testRewriterExceptionHandling
();
void
testRewriterDynamicProperties
();
void
testRewriterGroupedProperties
();
//
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment