summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brasser <michael.brasser@nokia.com>2009-09-08 22:46:10 (GMT)
committerMichael Brasser <michael.brasser@nokia.com>2009-09-08 22:46:10 (GMT)
commitd29c604b0365dfbc20f8aea8d2cb63f621995219 (patch)
tree511904026a961cadf5e7e13ff90b7e9baad1efbf
parentcce03d9a3c95dd81c31003e0a96c5bb3dca6f0c0 (diff)
parent7731e5f7d33d3ec251299c7651e777d7e0054573 (diff)
downloadQt-d29c604b0365dfbc20f8aea8d2cb63f621995219.zip
Qt-d29c604b0365dfbc20f8aea8d2cb63f621995219.tar.gz
Qt-d29c604b0365dfbc20f8aea8d2cb63f621995219.tar.bz2
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
-rw-r--r--doc/src/declarative/pics/qml-context-object.pngbin0 -> 23602 bytes
-rw-r--r--doc/src/declarative/pics/qml-context-tree.pngbin0 -> 10337 bytes
-rw-r--r--doc/src/declarative/pics/qml-context.pngbin0 -> 61465 bytes
-rw-r--r--doc/src/declarative/qmlformat.qdoc175
-rw-r--r--doc/src/declarative/qtdeclarative.qdoc2
-rw-r--r--examples/declarative/listview/content/pics/add.pngbin0 -> 1577 bytes
-rw-r--r--examples/declarative/listview/content/pics/del.pngbin0 -> 1661 bytes
-rw-r--r--examples/declarative/listview/content/pics/trash.pngbin0 -> 989 bytes
-rw-r--r--examples/declarative/listview/dynamic.qml91
-rw-r--r--src/declarative/QmlChanges.txt1
-rw-r--r--src/declarative/fx/qfxitem.cpp8
-rw-r--r--src/declarative/fx/qfxlistview.cpp3
-rw-r--r--src/declarative/fx/qfxvisualitemmodel.cpp19
-rw-r--r--src/declarative/qml/parser/qmljs.g1
-rw-r--r--src/declarative/qml/parser/qmljsastfwd_p.h4
-rw-r--r--src/declarative/qml/parser/qmljsengine_p.cpp6
-rw-r--r--src/declarative/qml/parser/qmljsengine_p.h4
-rw-r--r--src/declarative/qml/parser/qmljslexer.cpp16
-rw-r--r--src/declarative/qml/parser/qmljslexer_p.h3
-rw-r--r--src/declarative/qml/qmetaobjectbuilder_p.h8
-rw-r--r--src/declarative/util/qmllistmodel.cpp271
-rw-r--r--src/declarative/util/qmllistmodel.h8
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp4
-rw-r--r--tests/auto/declarative/qmlparser/listItemDeleteSelf.qml38
24 files changed, 608 insertions, 54 deletions
diff --git a/doc/src/declarative/pics/qml-context-object.png b/doc/src/declarative/pics/qml-context-object.png
new file mode 100644
index 0000000..1b91aff
--- /dev/null
+++ b/doc/src/declarative/pics/qml-context-object.png
Binary files differ
diff --git a/doc/src/declarative/pics/qml-context-tree.png b/doc/src/declarative/pics/qml-context-tree.png
new file mode 100644
index 0000000..6bba5f4
--- /dev/null
+++ b/doc/src/declarative/pics/qml-context-tree.png
Binary files differ
diff --git a/doc/src/declarative/pics/qml-context.png b/doc/src/declarative/pics/qml-context.png
new file mode 100644
index 0000000..bdf2ecd
--- /dev/null
+++ b/doc/src/declarative/pics/qml-context.png
Binary files differ
diff --git a/doc/src/declarative/qmlformat.qdoc b/doc/src/declarative/qmlformat.qdoc
index 9cfebf0..5013ee7 100644
--- a/doc/src/declarative/qmlformat.qdoc
+++ b/doc/src/declarative/qmlformat.qdoc
@@ -16,21 +16,148 @@ Much of a QML file consists of valid ECMAScript \e {Statement}s. Except where c
by ECMAScript, C++ or QObject prevented it, the syntactic extensions introduced by QML are designed
to look similar and fit well with existing ECMAScript syntax and concepts.
+\section1 QML engine
+
+The \l {QmlEngine}{QML engine} executes a \l {QmlComponent}{QML document} in a
+\l {QmlContext}{QML context} to produce a \l {QObject}{QML object}. A single QML
+document may be executed in one or many contexts to produce many QML objects. A single
+QML document may be executed many times in the same context to produce many QML objects.
+
+The QML engine provides the environment in which QML documents, contexts and objects
+exist. It must exist before any of these structures can be created. If the engine is removed,
+existing documents, contexts and objects are invalidated, but not destroyed. An invalid
+
+\list
+\i \e {QML document} can no longer be used to create QML objects.
+\i \e {QML context} can no longer host QML objects, new context properties cannot be added
+and existing context properties cannot be modified.
+\i \e {QML object} will no longer evaluate bindings or scripts.
+\endlist
+
+A QML document is a block of QML source code. QML documents generally correspond to files stored
+on a disk or network resource, but can be constructed directly from text data. Syntactically a QML
+document is self contained; QML does \bold {not} have a preprocessor that modifies the document
+before presentation to the compiler. Type references within a QML document are resolved based
+exclusively on the import statements present in the document.
+
+A simple QML document looks like this:
+
+\table
+\row
+\o
+\code
+import Qt 4.6
+
+Rectangle {
+ id: MyRect
+ width: 100; height: 100
+ color: background
+}
+\endcode
+\endtable
+
+To instantiate a QML object, a QML document is executed in a QML context. QML contexts are used by
+programmers to pass data to a QML document. QML documents may include property bindings or
+ECMAScript blocks that can contain variable references that need to be resolved. Each property
+binding and ECMAScript block has an associated QML context that is used to resolve these references
+that is determined by the QML context in which the document is executed. The example document above
+contains one variable reference, \c background.
+
+Each QML context defines a scope for variable resolution and each may define local, named context
+properties. A QML context may also have a \l {QmlContext::addDefaultObject()}{default object},
+which is an object whose properties are searched \e after the context properties when resolving a
+variable name. QML contexts form a tree, starting from a root context that is provided by the QML
+engine. When resolving variable references, the QML contexts are searched starting from the
+QML objects containing context upwards towards the root context.
+
+Consider the following QML context tree. If the example QML document is executed in \c Context1,
+the \c background variable will resolve to \c Context1's context property. If the document is
+executed in \c Context2, the \c background variable will resolve to the root context's context
+property.
+
+\image qml-context-tree.png
+
+While QML contexts can be created explicitly by the programmer to pass data into QML objects,
+the QML engine also creates a new implicit QML context for every object it instantiates.
+Property bindings and ECMAScript blocks in the document are associated with this QML engine
+created context. Object ids that are defined in the document are added as context properties, and
+their value is set to reference the appropriate object, and the instantiated QML object is set as
+the context's default object. The following diagram shows the result of executing a simple QML
+document.
+
+\image qml-context-object.png
+
+The blue rectangle in the diagram represents a property binding. Associated with each property
+binding is the QML context to which it belongs, the object property to which it is bound and a
+\e {scope object}. The scope object is usually, but not always, the object to which the bound
+property belongs. The context properties, context default objects and the scope object are all
+involved when resolving a variable name in a binding. The following psuedo code describes the
+alogithm used:
+
+\table
+\row
+\o
+\code
+if (scopeObject.hasProperty(name))
+ return scopeObject.property(name)
+
+foreach (context in contextChain) {
+ if (context.hasContextProperty(name)
+ return context.contextProperty(name)
+
+ if (context.defaultObject.hasProperty(name))
+ return context.defaultObject.property(name)
+}
+\endcode
+\endtable
+
+QML supports two categories of types: \e builtin types and \e composite types. Builtin types are
+those written in C++ and registered with the QML engine. Builtin types form the most basic
+building blocks of QML. Composite types are constructed by composing other builtin or composite
+types, property bindings and ECMAScript blocks together into a brand new type using the QML
+language. Using a composite type is identical to using a builtin type.
+
+For example, Qt 4.6 includes a builtin type called \c Image that shows a bitmap image. The
+\c Image type has \c width and \c height properties that control the size of the displayed image.
+A simple composite type, that will be called \c SquareImage can be built that adds a \c size
+property that sets both the width and the height.
+
+\table
+\row
+\o
+\code
+import Qt 4.6
+Image {
+ property int size
+ width: size
+ height: size
+}
+\endcode
+\endtable
+
+To the QML engine, a composite type is just another QML document. When a composite type is
+used the engine instantiates it just as it would any other document - by creating a new implicit
+QML context and the object tree described by the document. The diagram below shows the
+\c SquareImage composite type used from within another QML document. When instantiated, the
+\c SquareImage object is created in its own QML context. Any property bindings sepecified in the
+\c SquareImage composite type document are associated with this context. Property bindings created
+in the outer document, however, are associated with its context, even those that are applied to the
+created \c SquareImage object. That is, the \c size, \c source, \c width and \c height property
+bindings all share a common \e {scope object}, but are owned by two different QML contexts. The
+difference in containing context results in the \c Root variable resolving differently in the
+different property bindings.
+
+\image qml-context.png
+
+\section1 Syntax
+
\section2 Commenting
The commenting rules in QML are the same as for ECMAScript. Both \e {MultiLineComment} blocks and \e {SingleLineComment}'s are supported.
-\section1 Definitions
-
-\e {QML interpreter}: QmlEngine
-
-\e {QML execution context}: QmlContext
+\section2 QML Document
-\e {inherited characteristic}
-
-\section1 QML Document
-
-\section2 Syntax
+\section3 Syntax
\e {QMLDocument} \bold {:}
@@ -69,22 +196,16 @@ The commenting rules in QML are the same as for ECMAScript. Both \e {MultiLineC
\e {DecimalLiteral} \bold {but not} with \e {ExponentPart}
\endquotation
-\section2 Semantics
-
-A QML document is the unit in which QML code may be passed to the QML interpreter. A QML document
-is syntactically self contained. QML documents are evaluated by the QML interpreter in a QML
-execution context to produce a single instantiated object of the type specified by
-\e {QMLObjectDefinition}.
+\section3 Semantics
The \e {QMLImportList} is used to statically resolve type references used within the enclosing
-QML document. The import list is \bold {not} an \e {inherited characteristic}; its scope of
-influence is limited to structures logically contained by the document.
+QML document.
An import statement is used to bring a set of types into scope for a QML document.
-\section1 Object Definition
+\section2 Object Definition
-\section2 Syntax
+\section3 Syntax
\e {QMLObjectDefinition} \bold {:}
\quotation
@@ -125,11 +246,11 @@ An import statement is used to bring a set of types into scope for a QML documen
\endquotation
-\section2 Semantics
+\section3 Semantics
-\section1 Object Extension
+\section2 Object Extension
-\section2 Syntax
+\section3 Syntax
\e {QMLObjectExtensionDefinition} \bold {:}
\quotation
@@ -171,14 +292,14 @@ An import statement is used to bring a set of types into scope for a QML documen
\quotation
\e {FunctionDeclaration} \bold {but not} \e {Identifier} \sub {opt}
\endquotation
-\section2 Semantics
+\section3 Semantics
-\section1 Binding Expression
+\section2 Binding Expression
-\section2 Syntax
+\section3 Syntax
\e {QMLBindingExpression} \bold {:}
-\section2 Semantics
+\section3 Semantics
*/
diff --git a/doc/src/declarative/qtdeclarative.qdoc b/doc/src/declarative/qtdeclarative.qdoc
index 1b7644c..460819a 100644
--- a/doc/src/declarative/qtdeclarative.qdoc
+++ b/doc/src/declarative/qtdeclarative.qdoc
@@ -80,7 +80,7 @@
QML Reference:
\list
- \o \l {QML Format}
+ \o \l {QML Format Reference}
\o \l {elements}{QML Elements}
\endlist
diff --git a/examples/declarative/listview/content/pics/add.png b/examples/declarative/listview/content/pics/add.png
new file mode 100644
index 0000000..f29d84b
--- /dev/null
+++ b/examples/declarative/listview/content/pics/add.png
Binary files differ
diff --git a/examples/declarative/listview/content/pics/del.png b/examples/declarative/listview/content/pics/del.png
new file mode 100644
index 0000000..1d753a3
--- /dev/null
+++ b/examples/declarative/listview/content/pics/del.png
Binary files differ
diff --git a/examples/declarative/listview/content/pics/trash.png b/examples/declarative/listview/content/pics/trash.png
new file mode 100644
index 0000000..2042595
--- /dev/null
+++ b/examples/declarative/listview/content/pics/trash.png
Binary files differ
diff --git a/examples/declarative/listview/dynamic.qml b/examples/declarative/listview/dynamic.qml
new file mode 100644
index 0000000..58ce4b4
--- /dev/null
+++ b/examples/declarative/listview/dynamic.qml
@@ -0,0 +1,91 @@
+import Qt 4.6
+
+Item {
+ width: 300
+ height: 300
+
+ ListModel {
+ id: FruitModel
+ ListElement {
+ name: "Apple"
+ cost: 2.45
+ }
+ ListElement {
+ name: "Banana"
+ cost: 1.95
+ }
+ ListElement {
+ name: "Cumquat"
+ cost: 3.25
+ }
+ ListElement {
+ name: "Durian"
+ cost: 9.95
+ }
+ ListElement {
+ name: "Elderberry"
+ cost: 0.05
+ }
+ ListElement {
+ name: "Fig"
+ cost: 0.25
+ }
+ }
+
+ Component {
+ id: FruitDelegate
+ Item {
+ width: parent.width; height: 35
+ Text { font.pixelSize: 24; text: name }
+ Text { font.pixelSize: 24; text: '$'+Number(cost).toFixed(2); anchors.right: ItemButtons.left }
+ Row {
+ id: ItemButtons
+ anchors.right: parent.right
+ width: childrenRect.width
+ Image { source: "content/pics/add.png"
+ MouseRegion { anchors.fill: parent; onClicked: FruitModel.set(index,"cost",Number(cost)+0.25) }
+ }
+ Image { source: "content/pics/del.png"
+ MouseRegion { anchors.fill: parent; onClicked: FruitModel.set(index,"cost",Number(cost)-0.25) }
+ }
+ Image { source: "content/pics/trash.png"
+ MouseRegion { anchors.fill: parent; onClicked: FruitModel.remove(index) }
+ }
+ Column {
+ width: childrenRect.width
+ Image { source: "content/pics/moreUp.png"
+ MouseRegion { anchors.fill: parent; onClicked: FruitModel.move(index,index-1,1) }
+ }
+ Image { source: "content/pics/moreDown.png"
+ MouseRegion { anchors.fill: parent; onClicked: FruitModel.move(index,index+1,1) }
+ }
+ }
+ }
+ }
+ }
+
+ ListView {
+ model: FruitModel
+ delegate: FruitDelegate
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: Buttons.top
+ }
+
+ Row {
+ width: childrenRect.width
+ height: childrenRect.height
+ anchors.bottom: parent.bottom
+ id: Buttons
+ Image { source: "content/pics/add.png"
+ MouseRegion { anchors.fill: parent; onClicked: FruitModel.append({"name":"Pizza", "cost":5.95}) }
+ }
+ Image { source: "content/pics/add.png"
+ MouseRegion { anchors.fill: parent; onClicked: FruitModel.insert(0,{"name":"Pizza", "cost":5.95}) }
+ }
+ Image { source: "content/pics/trash.png"
+ MouseRegion { anchors.fill: parent; onClicked: FruitModel.clear() }
+ }
+ }
+}
diff --git a/src/declarative/QmlChanges.txt b/src/declarative/QmlChanges.txt
index e63eb8b..9bf4b10 100644
--- a/src/declarative/QmlChanges.txt
+++ b/src/declarative/QmlChanges.txt
@@ -31,6 +31,7 @@ ParentChangeAction -> ParentAction
VisualModel -> VisualDataModel
Renamed properties:
+Item: contents -> childrenRect
MouseRegion: xmin -> minimumX
MouseRegion: xmax -> maximumX
MouseRegion: ymin -> minimumY
diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp
index 5363148..3429010 100644
--- a/src/declarative/fx/qfxitem.cpp
+++ b/src/declarative/fx/qfxitem.cpp
@@ -235,10 +235,10 @@ QFxContents::QFxContents() : m_x(0), m_y(0), m_width(0), m_height(0)
}
/*!
- \qmlproperty qreal Item::childrenRect.x
- \qmlproperty qreal Item::childrenRect.y
- \qmlproperty qreal Item::childrenRect.width
- \qmlproperty qreal Item::childrenRect.height
+ \qmlproperty real Item::childrenRect.x
+ \qmlproperty real Item::childrenRect.y
+ \qmlproperty real Item::childrenRect.width
+ \qmlproperty real Item::childrenRect.height
The childrenRect properties allow an item access to the geometry of its
children. This property is useful if you have an item that needs to be
diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp
index c24610f..6c0a83e 100644
--- a/src/declarative/fx/qfxlistview.cpp
+++ b/src/declarative/fx/qfxlistview.cpp
@@ -1507,7 +1507,8 @@ void QFxListView::itemsInserted(int modelIndex, int count)
// Update the indexes of the following visible items.
for (; index < d->visibleItems.count(); ++index) {
FxListItem *listItem = d->visibleItems.at(index);
- listItem->setPosition(listItem->position() + (pos - initialPos));
+ if (listItem->item != d->currentItem->item)
+ listItem->setPosition(listItem->position() + (pos - initialPos));
if (listItem->index != -1)
listItem->index += count;
}
diff --git a/src/declarative/fx/qfxvisualitemmodel.cpp b/src/declarative/fx/qfxvisualitemmodel.cpp
index 82bec09..cac8b8d 100644
--- a/src/declarative/fx/qfxvisualitemmodel.cpp
+++ b/src/declarative/fx/qfxvisualitemmodel.cpp
@@ -243,6 +243,16 @@ public:
QmlContext *m_context;
QList<int> m_roles;
QHash<int,QString> m_roleNames;
+ void ensureRoles() {
+ if (m_roles.isEmpty()) {
+ if (m_listModelInterface) {
+ m_roles = m_listModelInterface->roles();
+ for (int ii = 0; ii < m_roles.count(); ++ii)
+ m_roleNames.insert(m_roles.at(ii),
+ m_listModelInterface->toString(m_roles.at(ii)));
+ }
+ }
+ }
struct ObjectRef {
ObjectRef(QObject *object=0) : obj(object), ref(1) {}
@@ -375,6 +385,7 @@ int QFxVisualDataModelDataMetaObject::createProperty(const char *name, const cha
return QmlOpenMetaObject::createProperty(name, type);
} else {
const QLatin1String sname(name);
+ data->m_model->ensureRoles();
for (QHash<int, QString>::ConstIterator iter = data->m_model->m_roleNames.begin();
iter != data->m_model->m_roleNames.end(); ++iter) {
@@ -397,6 +408,7 @@ QFxVisualDataModelDataMetaObject::propertyCreated(int, QMetaPropertyBuilder &pro
&& data->m_model->m_modelList) {
return data->m_model->m_modelList->at(data->m_index);
} else if (data->m_model->m_listModelInterface) {
+ data->m_model->ensureRoles();
for (QHash<int, QString>::ConstIterator iter = data->m_model->m_roleNames.begin();
iter != data->m_model->m_roleNames.end(); ++iter) {
@@ -410,6 +422,7 @@ QFxVisualDataModelDataMetaObject::propertyCreated(int, QMetaPropertyBuilder &pro
}
}
} else if (data->m_model->m_abstractItemModel) {
+ data->m_model->ensureRoles();
for (QHash<int, QString>::ConstIterator iter = data->m_model->m_roleNames.begin();
iter != data->m_model->m_roleNames.end(); ++iter) {
@@ -560,12 +573,6 @@ void QFxVisualDataModel::setModel(const QVariant &model)
if (object && (d->m_listModelInterface = qobject_cast<QListModelInterface *>(object))) {
d->m_roles.clear();
d->m_roleNames.clear();
- if (d->m_listModelInterface) {
- d->m_roles = d->m_listModelInterface->roles();
- for (int ii = 0; ii < d->m_roles.count(); ++ii)
- d->m_roleNames.insert(d->m_roles.at(ii),
- d->m_listModelInterface->toString(d->m_roles.at(ii)));
- }
QObject::connect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
this, SLOT(_q_itemsChanged(int,int,QList<int>)));
diff --git a/src/declarative/qml/parser/qmljs.g b/src/declarative/qml/parser/qmljs.g
index b0ef866..4ed75e8 100644
--- a/src/declarative/qml/parser/qmljs.g
+++ b/src/declarative/qml/parser/qmljs.g
@@ -80,6 +80,7 @@
%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"
diff --git a/src/declarative/qml/parser/qmljsastfwd_p.h b/src/declarative/qml/parser/qmljsastfwd_p.h
index f79cfc2..a6fee1d 100644
--- a/src/declarative/qml/parser/qmljsastfwd_p.h
+++ b/src/declarative/qml/parser/qmljsastfwd_p.h
@@ -62,9 +62,9 @@ namespace QmlJS { namespace AST {
class SourceLocation
{
public:
- SourceLocation(quint32 offset = 0, quint32 length = 0)
+ SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0)
: offset(offset), length(length),
- startLine(0), startColumn(0)
+ startLine(line), startColumn(column)
{ }
bool isValid() const { return length != 0; }
diff --git a/src/declarative/qml/parser/qmljsengine_p.cpp b/src/declarative/qml/parser/qmljsengine_p.cpp
index 02d9b9c..eab8944 100644
--- a/src/declarative/qml/parser/qmljsengine_p.cpp
+++ b/src/declarative/qml/parser/qmljsengine_p.cpp
@@ -178,6 +178,12 @@ 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(QmlJS::AST::SourceLocation(pos, len, line, col)); }
+
+QList<QmlJS::AST::SourceLocation> Engine::comments() const
+{ return _comments; }
+
NameId *Engine::intern(const QChar *u, int s)
{ return const_cast<NameId *>(&*_literals.insert(NameId(u, s))); }
diff --git a/src/declarative/qml/parser/qmljsengine_p.h b/src/declarative/qml/parser/qmljsengine_p.h
index 5aea983..877fff2 100644
--- a/src/declarative/qml/parser/qmljsengine_p.h
+++ b/src/declarative/qml/parser/qmljsengine_p.h
@@ -143,6 +143,7 @@ class Engine
Lexer *_lexer;
NodePool *_nodePool;
QSet<NameId> _literals;
+ QList<QmlJS::AST::SourceLocation> _comments;
public:
Engine();
@@ -150,6 +151,9 @@ public:
QSet<NameId> literals() const;
+ void addComment(int pos, int len, int line, int col);
+ QList<QmlJS::AST::SourceLocation> comments() const;
+
NameId *intern(const QChar *u, int s);
static QString toString(NameId *id);
diff --git a/src/declarative/qml/parser/qmljslexer.cpp b/src/declarative/qml/parser/qmljslexer.cpp
index 9da6ec0..3be1710 100644
--- a/src/declarative/qml/parser/qmljslexer.cpp
+++ b/src/declarative/qml/parser/qmljslexer.cpp
@@ -43,6 +43,8 @@
#include "config.h"
#endif
+#include <QDebug>
+
#include "qmljsengine_p.h"
#include "qmljslexer_p.h"
#include "qmljsgrammar_p.h"
@@ -71,7 +73,7 @@ extern double integerFromString(const char *buf, int size, int radix);
using namespace QmlJS;
-Lexer::Lexer(Engine *eng)
+Lexer::Lexer(Engine *eng, bool tokenizeComments)
: driver(eng),
yylineno(0),
done(false),
@@ -94,8 +96,9 @@ Lexer::Lexer(Engine *eng)
check_reserved(true),
parenthesesState(IgnoreParentheses),
parenthesesCount(0),
- prohibitAutomaticSemicolon(false)
-{
+ prohibitAutomaticSemicolon(false),
+ tokenizeComments(tokenizeComments)
+{qDebug()<<"--- new lexer";
driver->setLexer(this);
// allocate space for read buffers
buffer8 = new char[size8];
@@ -647,22 +650,29 @@ int Lexer::lex()
setDone(Other);
} else
state = Start;
+ qDebug() << "--- state is InSingleLineComment @" << startlineno << ":"<<startcolumn;
+ driver->addComment(startpos, tokenLength(), startlineno, startcolumn);
} else if (current == 0) {
+ driver->addComment(startpos, tokenLength(), startlineno, startcolumn);
setDone(Eof);
}
+
break;
case InMultiLineComment:
if (current == 0) {
setDone(Bad);
err = UnclosedComment;
errmsg = QLatin1String("Unclosed comment at end of file");
+ driver->addComment(startpos, tokenLength(), startlineno, startcolumn);
} else if (isLineTerminator()) {
shiftWindowsLineBreak();
yylineno++;
} else if (current == '*' && next1 == '/') {
state = Start;
shift(1);
+ driver->addComment(startpos, tokenLength(), startlineno, startcolumn);
}
+
break;
case InIdentifier:
if (isIdentLetter(current) || isDecimalDigit(current)) {
diff --git a/src/declarative/qml/parser/qmljslexer_p.h b/src/declarative/qml/parser/qmljslexer_p.h
index 5817868..6cca45d 100644
--- a/src/declarative/qml/parser/qmljslexer_p.h
+++ b/src/declarative/qml/parser/qmljslexer_p.h
@@ -67,7 +67,7 @@ class NameId;
class Lexer
{
public:
- Lexer(Engine *eng);
+ Lexer(Engine *eng, bool tokenizeComments = false);
~Lexer();
void setCode(const QString &c, int lineno);
@@ -239,6 +239,7 @@ private:
ParenthesesState parenthesesState;
int parenthesesCount;
bool prohibitAutomaticSemicolon;
+ bool tokenizeComments;
};
} // namespace QmlJS
diff --git a/src/declarative/qml/qmetaobjectbuilder_p.h b/src/declarative/qml/qmetaobjectbuilder_p.h
index d503163..c0b7426 100644
--- a/src/declarative/qml/qmetaobjectbuilder_p.h
+++ b/src/declarative/qml/qmetaobjectbuilder_p.h
@@ -68,7 +68,7 @@ class QMetaPropertyBuilderPrivate;
class QMetaEnumBuilder;
class QMetaEnumBuilderPrivate;
-class Q_CORE_EXPORT QMetaObjectBuilder
+class Q_DECLARATIVE_EXPORT QMetaObjectBuilder
{
public:
enum AddMember
@@ -189,7 +189,7 @@ private:
friend class QMetaEnumBuilder;
};
-class Q_CORE_EXPORT QMetaMethodBuilder
+class Q_DECLARATIVE_EXPORT QMetaMethodBuilder
{
public:
QMetaMethodBuilder() : _mobj(0), _index(0) {}
@@ -227,7 +227,7 @@ private:
QMetaMethodBuilderPrivate *d_func() const;
};
-class Q_CORE_EXPORT QMetaPropertyBuilder
+class Q_DECLARATIVE_EXPORT QMetaPropertyBuilder
{
public:
QMetaPropertyBuilder() : _mobj(0), _index(0) {}
@@ -278,7 +278,7 @@ private:
QMetaPropertyBuilderPrivate *d_func() const;
};
-class Q_CORE_EXPORT QMetaEnumBuilder
+class Q_DECLARATIVE_EXPORT QMetaEnumBuilder
{
public:
QMetaEnumBuilder() : _mobj(0), _index(0) {}
diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp
index 0d9ea94..5b7d2bb 100644
--- a/src/declarative/util/qmllistmodel.cpp
+++ b/src/declarative/util/qmllistmodel.cpp
@@ -72,7 +72,9 @@ struct ListModelData
\qmlclass ListModel
\brief The ListModel element defines a free-form list data source.
- The ListModel is a simple hierarchy of elements containing data roles.
+ The ListModel is a simple hierarchy of elements containing data roles. The contents can
+ be defined dynamically, or explicitly in QML:
+
For example:
\code
@@ -166,6 +168,29 @@ struct ListModelData
}
\endcode
+ The content of a ListModel may be created and modified using the clear(),
+ append(), and set() methods. For example:
+
+ \code
+ Component {
+ id: FruitDelegate
+ Item {
+ width: 200; height: 50
+ Text { text: name }
+ Text { text: '$'+cost; anchors.right: parent.right }
+
+ // Double the price when clicked.
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: FruitModel.set(index, "cost", cost*2)
+ }
+ }
+ }
+ \endcode
+
+ When creating content dynamically, note that the set of available properties cannot be changed
+ except by first clearing the model - whatever properties are first added are then the
+ only permitted properties in the model.
*/
class ModelObject : public QObject
@@ -189,7 +214,6 @@ struct ModelNode
{
ModelNode();
~ModelNode();
- QString className;
QList<QVariant> values;
QHash<QString, ModelNode *> properties;
@@ -214,6 +238,19 @@ struct ModelNode
return objectCache;
}
+ void setProperty(const QString& prop, const QVariant& val) {
+ QHash<QString, ModelNode *>::const_iterator it = properties.find(prop);
+ if (it != properties.end()) {
+ (*it)->values[0] = val;
+ } else {
+ ModelNode *n = new ModelNode;
+ n->values << val;
+ properties.insert(prop,n);
+ }
+ if (objectCache)
+ objectCache->setValue(prop.toLatin1(), val);
+ }
+
QmlListModel *modelCache;
ModelObject *objectCache;
};
@@ -235,7 +272,7 @@ QmlListModel::~QmlListModel()
void QmlListModel::checkRoles() const
{
- if (_rolesOk)
+ if (_rolesOk || !_root)
return;
for (int ii = 0; ii < _root->values.count(); ++ii) {
@@ -341,6 +378,232 @@ int QmlListModel::count() const
return _root->values.count();
}
+/*!
+ \qmlmethod ListModel::clear()
+
+ Deletes all content from the model. The properties are cleared such that
+ different properties may be set on subsequent additions.
+
+ \sa append() remove()
+*/
+void QmlListModel::clear()
+{
+ int cleared = count();
+ _rolesOk = false;
+ delete _root;
+ _root = 0;
+ roleStrings.clear();
+ emit itemsRemoved(0,cleared);
+}
+
+/*!
+ \qmlmethod ListModel::remove(int index)
+
+ Deletes the content at \a index from the model.
+
+ \sa clear()
+*/
+void QmlListModel::remove(int index)
+{
+ if (_root) {
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ _root->values.removeAt(index);
+ if (node)
+ delete node;
+ emit itemsRemoved(index,1);
+ }
+}
+
+/*!
+ \qmlmethod ListModel::insert(index,dict)
+
+ Adds a new item to the list model at position \a index, with the
+ values in \a dict.
+
+ \code
+ FruitModel.insert(2, {"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ If \a index is not in the list, sufficient empty items are
+ added to the list.
+
+ \sa set() append()
+*/
+void QmlListModel::insert(int index, const QVariantMap& valuemap)
+{
+ if (!_root)
+ _root = new ModelNode;
+ if (index >= _root->values.count()) {
+ set(index,valuemap);
+ return;
+ }
+ ModelNode *mn = new ModelNode;
+ for (QVariantMap::const_iterator it=valuemap.begin(); it!=valuemap.end(); ++it) {
+ addRole(it.key());
+ ModelNode *value = new ModelNode;
+ value->values << it.value();
+ mn->properties.insert(it.key(),value);
+ }
+ _root->values.insert(index,qVariantFromValue(mn));
+ emit itemsInserted(index,1);
+}
+
+/*!
+ \qmlmethod ListModel::move(from,to,n)
+
+ Moves \a n items \a from one position \a to another.
+
+ The from and to ranges must exist; for example, to move the first 3 items
+ to the end of the list:
+
+ \code
+ FruitModel.move(0,FruitModel.count-3,3)
+ \endcode
+
+ \sa append()
+*/
+void QmlListModel::move(int from, int to, int n)
+{
+ if (from+n > count() || to+n > count() || n==0 || from==to)
+ return;
+ if (from > to) {
+ // Only move forwards - flip if backwards moving
+ int tfrom = from;
+ int tto = to;
+ from = tto;
+ to = tto+n;
+ n = tfrom-tto;
+ }
+ if (n==1) {
+ _root->values.move(from,to);
+ } else {
+ QList<QVariant> replaced;
+ int i=0;
+ QVariantList::const_iterator it=_root->values.begin(); it += from+n;
+ for (; i<to-from; ++i,++it)
+ replaced.append(*it);
+ i=0;
+ it=_root->values.begin(); it += from;
+ for (; i<n; ++i,++it)
+ replaced.append(*it);
+ QVariantList::const_iterator f=replaced.begin();
+ QVariantList::iterator t=_root->values.begin(); t += from;
+ for (; f != replaced.end(); ++f, ++t)
+ *t = *f;
+ }
+ emit itemsMoved(from,to,n);
+}
+
+/*!
+ \qmlmethod ListModel::append(dict)
+
+ Adds a new item to the end of the list model, with the
+ values in \a dict.
+
+ \code
+ FruitModel.append({"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ \sa set() remove()
+*/
+void QmlListModel::append(const QVariantMap& valuemap)
+{
+ if (!_root)
+ _root = new ModelNode;
+ ModelNode *mn = new ModelNode;
+ for (QVariantMap::const_iterator it=valuemap.begin(); it!=valuemap.end(); ++it) {
+ addRole(it.key());
+ ModelNode *value = new ModelNode;
+ value->values << it.value();
+ mn->properties.insert(it.key(),value);
+ }
+ _root->values << qVariantFromValue(mn);
+ emit itemsInserted(count()-1,1);
+}
+
+/*!
+ \qmlmethod ListModel::set(index,dict)
+
+ Changes the item at \a index in the list model to the
+ values in \a dict.
+
+ \code
+ FruitModel.set(3, {"cost": 5.95, "name":"Pizza"})
+ \endcode
+
+ If \a index is not in the list, sufficient empty items are
+ added to the list.
+
+ \sa append()
+*/
+void QmlListModel::set(int index, const QVariantMap& valuemap)
+{
+ if (!_root)
+ _root = new ModelNode;
+ int initialcount = _root->values.count();
+ while (index > _root->values.count())
+ _root->values.append(qVariantFromValue(new ModelNode));
+ if (index == _root->values.count())
+ append(valuemap);
+ else {
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ QList<int> roles;
+ for (QVariantMap::const_iterator it=valuemap.begin(); it!=valuemap.end(); ++it) {
+ node->setProperty(it.key(),it.value());
+ int r = roleStrings.indexOf(it.key());
+ if (r<0) {
+ r = roleStrings.count();
+ roleStrings << it.key();
+ }
+ roles.append(r);
+ }
+ if (initialcount < index) {
+ emit itemsInserted(initialcount,index-initialcount+1);
+ } else {
+ emit itemsChanged(index,1,roles);
+ }
+ }
+}
+
+/*!
+ \qmlmethod ListModel::set(index,property,value)
+
+ Changes the \a property of the item at \a index in the list model to \a value.
+
+ \code
+ FruitModel.set(3, "cost", 5.95)
+ \endcode
+
+ If \a index is not in the list, sufficient empty items are
+ added to the list.
+
+ \sa append()
+*/
+void QmlListModel::set(int index, const QString& property, const QVariant& value)
+{
+ if (!_root)
+ _root = new ModelNode;
+ int initialcount = _root->values.count();
+ while (index >= _root->values.count())
+ _root->values.append(qVariantFromValue(new ModelNode));
+ ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
+ int r = roleStrings.indexOf(property);
+ if (r<0) {
+ r = roleStrings.count();
+ roleStrings << property;
+ }
+ QList<int> roles;
+ roles.append(r);
+
+ if (node)
+ node->setProperty(property,value);
+ if (initialcount < index)
+ emit itemsInserted(initialcount,index-initialcount+1);
+ else
+ emit itemsChanged(index,1,roles);
+}
+
+
class QmlListModelParser : public QmlCustomParser
{
public:
@@ -518,7 +781,7 @@ static void dump(ModelNode *node, int ind)
for (int ii = 0; ii < node->values.count(); ++ii) {
ModelNode *subNode = qvariant_cast<ModelNode *>(node->values.at(ii));
if (subNode) {
- qWarning().nospace() << indent << "Sub-node " << ii << ": class " << subNode->className;
+ qWarning().nospace() << indent << "Sub-node " << ii;
dump(subNode, ind + 1);
} else {
qWarning().nospace() << indent << "Sub-node " << ii << ": " << node->values.at(ii).toString();
diff --git a/src/declarative/util/qmllistmodel.h b/src/declarative/util/qmllistmodel.h
index 39edbe4..8bef347 100644
--- a/src/declarative/util/qmllistmodel.h
+++ b/src/declarative/util/qmllistmodel.h
@@ -72,6 +72,14 @@ public:
virtual int count() const;
virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const;
+ Q_INVOKABLE void clear();
+ Q_INVOKABLE void remove(int index);
+ Q_INVOKABLE void append(const QVariantMap& valuemap);
+ Q_INVOKABLE void insert(int index, const QVariantMap& valuemap);
+ Q_INVOKABLE void set(int index, const QVariantMap& valuemap);
+ Q_INVOKABLE void set(int index, const QString& property, const QVariant& value);
+ Q_INVOKABLE void move(int from, int to, int count);
+
private:
QVariant valueForNode(ModelNode *) const;
mutable QStringList roleStrings;
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 8bd3648..73ea75e 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -930,7 +930,7 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent)
}
QGraphicsItem *lastSubFocusItem = subFocusItem;
- if (subFocusItem && !inDestructor) {
+ if (subFocusItem) {
// Update the child focus chain; when reparenting an item that has a
// focus child, ensure that that focus child clears its focus child
// chain from our parents before it's reparented.
@@ -1204,6 +1204,8 @@ QGraphicsItem::~QGraphicsItem()
Q_ASSERT(d_ptr->children.isEmpty());
}
+ d_ptr->subFocusItem = 0;
+
if (d_ptr->scene) {
d_ptr->scene->d_func()->removeItemHelper(this);
} else {
diff --git a/tests/auto/declarative/qmlparser/listItemDeleteSelf.qml b/tests/auto/declarative/qmlparser/listItemDeleteSelf.qml
new file mode 100644
index 0000000..fa2e831
--- /dev/null
+++ b/tests/auto/declarative/qmlparser/listItemDeleteSelf.qml
@@ -0,0 +1,38 @@
+import Qt 4.6
+
+Item {
+ ListModel {
+ id: FruitModel
+ ListElement {
+ name: "Apple"
+ cost: 2.45
+ }
+ ListElement {
+ name: "Orange"
+ cost: 3.25
+ }
+ ListElement {
+ name: "Banana"
+ cost: 1.95
+ }
+ }
+
+ Component {
+ id: FruitDelegate
+ Item {
+ width: 200; height: 50
+ Text { text: name }
+ Text { text: '$'+cost; anchors.right: parent.right }
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: FruitModel.remove(index)
+ }
+ }
+ }
+
+ ListView {
+ model: FruitModel
+ delegate: FruitDelegate
+ anchors.fill: parent
+ }
+}