summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/declarative/touchinteraction/pincharea/flickresize.qml2
-rw-r--r--src/declarative/graphicsitems/qdeclarativegridview.cpp156
-rw-r--r--src/declarative/graphicsitems/qdeclarativegridview_p.h2
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp2
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview.cpp166
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview_p.h2
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp86
-rw-r--r--src/declarative/util/qdeclarativelistmodel.cpp83
-rw-r--r--src/declarative/util/qdeclarativelistmodel_p.h3
-rw-r--r--src/declarative/util/qdeclarativelistmodel_p_p.h6
-rw-r--r--src/declarative/util/qdeclarativelistmodelworkeragent.cpp28
-rw-r--r--src/declarative/util/qdeclarativelistmodelworkeragent_p.h5
-rw-r--r--tests/auto/declarative/qdeclarativegridview/data/gridview1.qml8
-rw-r--r--tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp59
-rw-r--r--tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp159
-rw-r--r--tests/auto/declarative/qdeclarativelistview/data/listviewtest.qml9
-rw-r--r--tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp59
-rw-r--r--tests/auto/declarative/qdeclarativeqt/data/formatting.qml53
-rw-r--r--tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro2
-rw-r--r--tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp107
20 files changed, 767 insertions, 230 deletions
diff --git a/examples/declarative/touchinteraction/pincharea/flickresize.qml b/examples/declarative/touchinteraction/pincharea/flickresize.qml
index aa426e7..a2f81ff 100644
--- a/examples/declarative/touchinteraction/pincharea/flickresize.qml
+++ b/examples/declarative/touchinteraction/pincharea/flickresize.qml
@@ -54,7 +54,7 @@ Rectangle {
PinchArea {
width: Math.max(flick.contentWidth, flick.width)
height: Math.max(flick.contentHeight, flick.height)
- onPinchChanged: {
+ onPinchUpdated: {
// adjust content pos due to drag
flick.contentX += pinch.previousCenter.x - pinch.center.x
flick.contentY += pinch.previousCenter.y - pinch.center.y
diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp
index c2c28c2..6e6e8c1 100644
--- a/src/declarative/graphicsitems/qdeclarativegridview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp
@@ -336,6 +336,7 @@ public:
}
}
+ void positionViewAtIndex(int index, int mode);
virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
virtual void flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
@@ -2124,6 +2125,77 @@ void QDeclarativeGridView::moveCurrentIndexRight()
}
}
+void QDeclarativeGridViewPrivate::positionViewAtIndex(int index, int mode)
+{
+ Q_Q(QDeclarativeGridView);
+ if (!isValid())
+ return;
+ if (mode < QDeclarativeGridView::Beginning || mode > QDeclarativeGridView::Contain)
+ return;
+
+ int idx = qMax(qMin(index, model->count()-1), 0);
+
+ if (layoutScheduled)
+ layout();
+ qreal pos = position();
+ FxGridItem *item = visibleItem(idx);
+ if (!item) {
+ int itemPos = rowPosAt(idx);
+ // save the currently visible items in case any of them end up visible again
+ QList<FxGridItem*> oldVisible = visibleItems;
+ visibleItems.clear();
+ visibleIndex = idx - idx % columns;
+ setPosition(itemPos);
+ // now release the reference to all the old visible items.
+ for (int i = 0; i < oldVisible.count(); ++i)
+ releaseItem(oldVisible.at(i));
+ item = visibleItem(idx);
+ }
+ if (item) {
+ qreal itemPos = item->rowPos();
+ switch (mode) {
+ case QDeclarativeGridView::Beginning:
+ pos = itemPos;
+ if (index < 0 && header) {
+ pos -= flow == QDeclarativeGridView::LeftToRight
+ ? header->item->height()
+ : header->item->width();
+ }
+ break;
+ case QDeclarativeGridView::Center:
+ pos = itemPos - (size() - rowSize())/2;
+ break;
+ case QDeclarativeGridView::End:
+ pos = itemPos - size() + rowSize();
+ if (index >= model->count() && footer) {
+ pos += flow == QDeclarativeGridView::LeftToRight
+ ? footer->item->height()
+ : footer->item->width();
+ }
+ break;
+ case QDeclarativeGridView::Visible:
+ if (itemPos > pos + size())
+ pos = itemPos - size() + rowSize();
+ else if (item->endRowPos() < pos)
+ pos = itemPos;
+ break;
+ case QDeclarativeGridView::Contain:
+ if (item->endRowPos() > pos + size())
+ pos = itemPos - size() + rowSize();
+ if (itemPos < pos)
+ pos = itemPos;
+ }
+ qreal maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
+ pos = qMin(pos, maxExtent);
+ qreal minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
+ pos = qMax(pos, minExtent);
+ moveReason = QDeclarativeGridViewPrivate::Other;
+ q->cancelFlick();
+ setPosition(pos);
+ }
+ fixupPosition();
+}
+
/*!
\qmlmethod GridView::positionViewAtIndex(int index, PositionMode mode)
@@ -2161,58 +2233,42 @@ void QDeclarativeGridView::positionViewAtIndex(int index, int mode)
Q_D(QDeclarativeGridView);
if (!d->isValid() || index < 0 || index >= d->model->count())
return;
- if (mode < Beginning || mode > Contain)
+ d->positionViewAtIndex(index, mode);
+}
+
+/*!
+ \qmlmethod GridView::positionViewAtBeginning()
+ \qmlmethod GridView::positionViewAtEnd()
+
+ Positions the view at the beginning or end, taking into account any header or footer.
+
+ It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
+ at a particular index. This is unreliable since removing items from the start
+ of the list does not cause all other items to be repositioned, and because
+ the actual start of the view can vary based on the size of the delegates.
+
+ \bold Note: methods should only be called after the Component has completed. To position
+ the view at startup, this method should be called by Component.onCompleted. For
+ example, to position the view at the end on startup:
+
+ \code
+ Component.onCompleted: positionViewAtEnd()
+ \endcode
+*/
+void QDeclarativeGridView::positionViewAtBeginning()
+{
+ Q_D(QDeclarativeGridView);
+ if (!d->isValid())
return;
+ d->positionViewAtIndex(-1, Beginning);
+}
- if (d->layoutScheduled)
- d->layout();
- qreal pos = d->position();
- FxGridItem *item = d->visibleItem(index);
- if (!item) {
- int itemPos = d->rowPosAt(index);
- // save the currently visible items in case any of them end up visible again
- QList<FxGridItem*> oldVisible = d->visibleItems;
- d->visibleItems.clear();
- d->visibleIndex = index - index % d->columns;
- d->setPosition(itemPos);
- // now release the reference to all the old visible items.
- for (int i = 0; i < oldVisible.count(); ++i)
- d->releaseItem(oldVisible.at(i));
- item = d->visibleItem(index);
- }
- if (item) {
- qreal itemPos = item->rowPos();
- switch (mode) {
- case Beginning:
- pos = itemPos;
- break;
- case Center:
- pos = itemPos - (d->size() - d->rowSize())/2;
- break;
- case End:
- pos = itemPos - d->size() + d->rowSize();
- break;
- case Visible:
- if (itemPos > pos + d->size())
- pos = itemPos - d->size() + d->rowSize();
- else if (item->endRowPos() < pos)
- pos = itemPos;
- break;
- case Contain:
- if (item->endRowPos() > pos + d->size())
- pos = itemPos - d->size() + d->rowSize();
- if (itemPos < pos)
- pos = itemPos;
- }
- qreal maxExtent = d->flow == QDeclarativeGridView::LeftToRight ? -maxYExtent() : -maxXExtent();
- pos = qMin(pos, maxExtent);
- qreal minExtent = d->flow == QDeclarativeGridView::LeftToRight ? -minYExtent() : -minXExtent();
- pos = qMax(pos, minExtent);
- d->moveReason = QDeclarativeGridViewPrivate::Other;
- cancelFlick();
- d->setPosition(pos);
- }
- d->fixupPosition();
+void QDeclarativeGridView::positionViewAtEnd()
+{
+ Q_D(QDeclarativeGridView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(d->model->count(), End);
}
/*!
diff --git a/src/declarative/graphicsitems/qdeclarativegridview_p.h b/src/declarative/graphicsitems/qdeclarativegridview_p.h
index ee632b1..e41537c 100644
--- a/src/declarative/graphicsitems/qdeclarativegridview_p.h
+++ b/src/declarative/graphicsitems/qdeclarativegridview_p.h
@@ -159,6 +159,8 @@ public:
Q_INVOKABLE void positionViewAtIndex(int index, int mode);
Q_INVOKABLE int indexAt(int x, int y) const;
+ Q_INVOKABLE Q_REVISION(1) void positionViewAtBeginning();
+ Q_INVOKABLE Q_REVISION(1) void positionViewAtEnd();
static QDeclarativeGridViewAttached *qmlAttachedProperties(QObject *);
diff --git a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp
index ddbde0b..529686e 100644
--- a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp
@@ -180,6 +180,8 @@ void QDeclarativeItemModule::defineModule()
qmlRegisterType<QDeclarativePinch>("QtQuick",1,1,"Pinch");
qmlRegisterType<QDeclarativePinchEvent>();
qmlRegisterType<QDeclarativeFlickable,1>("QtQuick",1,1,"Flickable");
+ qmlRegisterType<QDeclarativeListView,1>("QtQuick",1,1,"ListView");
+ qmlRegisterType<QDeclarativeGridView,1>("QtQuick",1,1,"GridView");
qmlRegisterType<QDeclarativeRepeater,1>("QtQuick",1,1,"Repeater");
qmlRegisterType<QDeclarativeTextEdit,1>("QtQuick",1,1,"TextEdit");
#ifndef QT_NO_LINEEDIT
diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp
index 702442b..470f947 100644
--- a/src/declarative/graphicsitems/qdeclarativelistview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp
@@ -451,6 +451,7 @@ public:
void updateHeader();
void updateFooter();
void fixupPosition();
+ void positionViewAtIndex(int index, int mode);
virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
virtual void flick(QDeclarativeFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
@@ -2558,6 +2559,79 @@ void QDeclarativeListView::decrementCurrentIndex()
}
}
+void QDeclarativeListViewPrivate::positionViewAtIndex(int index, int mode)
+{
+ Q_Q(QDeclarativeListView);
+ if (!isValid())
+ return;
+ if (mode < QDeclarativeListView::Beginning || mode > QDeclarativeListView::Contain)
+ return;
+qDebug() << "positionViewAtIndex";
+ int idx = qMax(qMin(index, model->count()-1), 0);
+
+ if (layoutScheduled)
+ layout();
+ qreal pos = position();
+ FxListItem *item = visibleItem(idx);
+ if (!item) {
+ int itemPos = positionAt(idx);
+ // save the currently visible items in case any of them end up visible again
+ QList<FxListItem*> oldVisible = visibleItems;
+ visibleItems.clear();
+ visiblePos = itemPos;
+ visibleIndex = idx;
+ setPosition(itemPos);
+ // now release the reference to all the old visible items.
+ for (int i = 0; i < oldVisible.count(); ++i)
+ releaseItem(oldVisible.at(i));
+ item = visibleItem(idx);
+ }
+ if (item) {
+ const qreal itemPos = item->position();
+ switch (mode) {
+ case QDeclarativeListView::Beginning:
+ pos = itemPos;
+ if (index < 0 && header)
+ pos -= header->size();
+ break;
+ case QDeclarativeListView::Center:
+ pos = itemPos - (size() - item->size())/2;
+ break;
+ case QDeclarativeListView::End:
+ pos = itemPos - size() + item->size();
+ if (index >= model->count() && footer)
+ pos += footer->size();
+ break;
+ case QDeclarativeListView::Visible:
+ if (itemPos > pos + size())
+ pos = itemPos - size() + item->size();
+ else if (item->endPosition() < pos)
+ pos = itemPos;
+ break;
+ case QDeclarativeListView::Contain:
+ if (item->endPosition() > pos + size())
+ pos = itemPos - size() + item->size();
+ if (itemPos < pos)
+ pos = itemPos;
+ }
+ qreal maxExtent = orient == QDeclarativeListView::Vertical ? -q->maxYExtent() : -q->maxXExtent();
+ pos = qMin(pos, maxExtent);
+ qreal minExtent = orient == QDeclarativeListView::Vertical ? -q->minYExtent() : -q->minXExtent();
+ pos = qMax(pos, minExtent);
+ moveReason = QDeclarativeListViewPrivate::Other;
+ q->cancelFlick();
+ setPosition(pos);
+ if (highlight) {
+ if (autoHighlight) {
+ highlight->setPosition(currentItem->itemPosition());
+ highlight->setSize(currentItem->itemSize());
+ }
+ updateHighlight();
+ }
+ }
+ fixupPosition();
+}
+
/*!
\qmlmethod ListView::positionViewAtIndex(int index, PositionMode mode)
@@ -2596,66 +2670,42 @@ void QDeclarativeListView::positionViewAtIndex(int index, int mode)
Q_D(QDeclarativeListView);
if (!d->isValid() || index < 0 || index >= d->model->count())
return;
- if (mode < Beginning || mode > Contain)
+ d->positionViewAtIndex(index, mode);
+}
+
+/*!
+ \qmlmethod ListView::positionViewAtBeginning()
+ \qmlmethod ListView::positionViewAtEnd()
+
+ Positions the view at the beginning or end, taking into account any header or footer.
+
+ It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
+ at a particular index. This is unreliable since removing items from the start
+ of the list does not cause all other items to be repositioned, and because
+ the actual start of the view can vary based on the size of the delegates.
+
+ \bold Note: methods should only be called after the Component has completed. To position
+ the view at startup, this method should be called by Component.onCompleted. For
+ example, to position the view at the end on startup:
+
+ \code
+ Component.onCompleted: positionViewAtEnd()
+ \endcode
+*/
+void QDeclarativeListView::positionViewAtBeginning()
+{
+ Q_D(QDeclarativeListView);
+ if (!d->isValid())
return;
+ d->positionViewAtIndex(-1, Beginning);
+}
- if (d->layoutScheduled)
- d->layout();
- qreal pos = d->position();
- FxListItem *item = d->visibleItem(index);
- if (!item) {
- int itemPos = d->positionAt(index);
- // save the currently visible items in case any of them end up visible again
- QList<FxListItem*> oldVisible = d->visibleItems;
- d->visibleItems.clear();
- d->visiblePos = itemPos;
- d->visibleIndex = index;
- d->setPosition(itemPos);
- // now release the reference to all the old visible items.
- for (int i = 0; i < oldVisible.count(); ++i)
- d->releaseItem(oldVisible.at(i));
- item = d->visibleItem(index);
- }
- if (item) {
- const qreal itemPos = item->position();
- switch (mode) {
- case Beginning:
- pos = itemPos;
- break;
- case Center:
- pos = itemPos - (d->size() - item->size())/2;
- break;
- case End:
- pos = itemPos - d->size() + item->size();
- break;
- case Visible:
- if (itemPos > pos + d->size())
- pos = itemPos - d->size() + item->size();
- else if (item->endPosition() < pos)
- pos = itemPos;
- break;
- case Contain:
- if (item->endPosition() > pos + d->size())
- pos = itemPos - d->size() + item->size();
- if (itemPos < pos)
- pos = itemPos;
- }
- qreal maxExtent = d->orient == QDeclarativeListView::Vertical ? -maxYExtent() : -maxXExtent();
- pos = qMin(pos, maxExtent);
- qreal minExtent = d->orient == QDeclarativeListView::Vertical ? -minYExtent() : -minXExtent();
- pos = qMax(pos, minExtent);
- d->moveReason = QDeclarativeListViewPrivate::Other;
- cancelFlick();
- d->setPosition(pos);
- if (d->highlight) {
- if (d->autoHighlight) {
- d->highlight->setPosition(d->currentItem->itemPosition());
- d->highlight->setSize(d->currentItem->itemSize());
- }
- d->updateHighlight();
- }
- }
- d->fixupPosition();
+void QDeclarativeListView::positionViewAtEnd()
+{
+ Q_D(QDeclarativeListView);
+ if (!d->isValid())
+ return;
+ d->positionViewAtIndex(d->model->count(), End);
}
/*!
diff --git a/src/declarative/graphicsitems/qdeclarativelistview_p.h b/src/declarative/graphicsitems/qdeclarativelistview_p.h
index 2678b90..2f7f6da 100644
--- a/src/declarative/graphicsitems/qdeclarativelistview_p.h
+++ b/src/declarative/graphicsitems/qdeclarativelistview_p.h
@@ -209,6 +209,8 @@ public:
Q_INVOKABLE void positionViewAtIndex(int index, int mode);
Q_INVOKABLE int indexAt(int x, int y) const;
+ Q_INVOKABLE Q_REVISION(1) void positionViewAtBeginning();
+ Q_INVOKABLE Q_REVISION(1) void positionViewAtEnd();
public Q_SLOTS:
void incrementCurrentIndex();
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index b940457..52df518 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -1379,7 +1379,17 @@ QScriptValue QDeclarativeEnginePrivate::vector3d(QScriptContext *ctxt, QScriptEn
/*!
\qmlmethod string Qt::formatDate(datetime date, variant format)
-Returns the string representation of \c date, formatted according to \c 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)
@@ -1406,9 +1416,16 @@ QScriptValue QDeclarativeEnginePrivate::formatDate(QScriptContext*ctxt, QScriptE
/*!
\qmlmethod string Qt::formatTime(datetime time, variant format)
-Returns the string representation of \c time, formatted according to \c format.
-See Qt::formatDateTime for how to define \c 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)
{
@@ -1416,29 +1433,49 @@ QScriptValue QDeclarativeEnginePrivate::formatTime(QScriptContext*ctxt, QScriptE
if(argCount == 0 || argCount > 2)
return ctxt->throwError(QLatin1String("Qt.formatTime(): Invalid arguments"));
- QTime date = ctxt->argument(0).toDateTime().time();
+ 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(qVariantFromValue(date.toString(format)));
+ return engine->newVariant(qVariantFromValue(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(qVariantFromValue(date.toString(enumFormat)));
+ return engine->newVariant(qVariantFromValue(time.toString(enumFormat)));
}
/*!
\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format)
-Returns the string representation of \c dateTime, formatted according to \c format.
-\c format for the date/time formatting functions is be specified as follows.
+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.
- These expressions may be used for the date:
+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
@@ -1462,7 +1499,7 @@ Returns the string representation of \c dateTime, formatted according to \c form
\row \i yyyy \i the year as four digit number
\endtable
- These expressions may be used for the time:
+In addition the following expressions can be used to specify the time:
\table
\header \i Expression \i Output
@@ -1483,23 +1520,28 @@ Returns the string representation of \c dateTime, formatted according to \c form
\endtable
All other input characters will be ignored. Any sequence of characters that
- are enclosed in singlequotes will be treated as text and not be used as an
- expression. Two consecutive singlequotes ("''") are replaced by a singlequote
+ 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.
- Example format strings (assumed that the date and time is 21 May 2001
- 14:13:09):
+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
+ \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
-
-If no format is specified the locale's short format is used. Alternatively, you can specify
-\c Qt.DefaultLocaleLongDate to get the locale's long format.
*/
QScriptValue QDeclarativeEnginePrivate::formatDateTime(QScriptContext*ctxt, QScriptEngine*engine)
{
diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp
index 538e8af..8290665 100644
--- a/src/declarative/util/qdeclarativelistmodel.cpp
+++ b/src/declarative/util/qdeclarativelistmodel.cpp
@@ -559,6 +559,14 @@ QScriptValue QDeclarativeListModel::get(int index) const
*/
void QDeclarativeListModel::set(int index, const QScriptValue& valuemap)
{
+ QList<int> roles;
+ set(index, valuemap, &roles);
+ if (!roles.isEmpty() && !inWorkerThread())
+ emit itemsChanged(index, 1, roles);
+}
+
+void QDeclarativeListModel::set(int index, const QScriptValue& valuemap, QList<int> *roles)
+{
if (!valuemap.isObject() || valuemap.isArray()) {
qmlInfo(this) << tr("set: value is not an object");
return;
@@ -571,14 +579,10 @@ void QDeclarativeListModel::set(int index, const QScriptValue& valuemap)
if (index == count()) {
append(valuemap);
} else {
- QList<int> roles;
if (m_flat)
- m_flat->set(index, valuemap, &roles);
+ m_flat->set(index, valuemap, roles);
else
- m_nested->set(index, valuemap, &roles);
-
- if (!inWorkerThread())
- emit itemsChanged(index, 1, roles);
+ m_nested->set(index, valuemap, roles);
}
}
@@ -597,19 +601,23 @@ void QDeclarativeListModel::set(int index, const QScriptValue& valuemap)
*/
void QDeclarativeListModel::setProperty(int index, const QString& property, const QVariant& value)
{
+ QList<int> roles;
+ setProperty(index, property, value, &roles);
+ if (!roles.isEmpty() && !inWorkerThread())
+ emit itemsChanged(index, 1, roles);
+}
+
+void QDeclarativeListModel::setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles)
+{
if (count() == 0 || index >= count() || index < 0) {
qmlInfo(this) << tr("set: index %1 out of range").arg(index);
return;
}
- QList<int> roles;
if (m_flat)
- m_flat->setProperty(index, property, value, &roles);
+ m_flat->setProperty(index, property, value, roles);
else
- m_nested->setProperty(index, property, value, &roles);
-
- if (!inWorkerThread())
- emit itemsChanged(index, 1, roles);
+ m_nested->setProperty(index, property, value, roles);
}
/*!
@@ -1011,9 +1019,11 @@ void FlatListModel::setProperty(int index, const QString& property, const QVaria
} else {
role = iter.value();
}
- roles->append(role);
- m_values[index][role] = value;
+ if (m_values[index][role] != value) {
+ roles->append(role);
+ m_values[index][role] = value;
+ }
}
void FlatListModel::move(int from, int to, int n)
@@ -1043,6 +1053,10 @@ bool FlatListModel::addValue(const QScriptValue &value, QHash<int, QVariant> *ro
iter = m_strings.insert(name, role);
if (roles)
roles->append(role);
+ } else {
+ int role = iter.value();
+ if (roles && row->contains(role) && row->value(role) != v)
+ roles->append(role);
}
row->insert(*iter, v);
}
@@ -1151,14 +1165,14 @@ void FlatListScriptClass::setProperty(Object *obj, const Identifier &name, const
QHash<int, QVariant> &row = m_model->m_values[index];
row[role] = value.toVariant();
+ QList<int> roles;
+ roles << role;
if (m_model->m_parentAgent) {
// This is the list in the worker thread, so tell the agent to
// emit itemsChanged() later
- m_model->m_parentAgent->changedData(index, 1);
+ m_model->m_parentAgent->changedData(index, 1, roles);
} else {
// This is the list in the main thread, so emit itemsChanged()
- QList<int> roles;
- roles << role;
emit m_model->m_listModel->itemsChanged(index, 1, roles);
}
}
@@ -1350,7 +1364,9 @@ void NestedListModel::set(int index, const QScriptValue& valuemap, QList<int> *r
Q_ASSERT(index >=0 && index < count());
ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
- node->setObjectValue(valuemap);
+ bool emitItemsChanged = node->setObjectValue(valuemap);
+ if (!emitItemsChanged)
+ return;
QScriptValueIterator it(valuemap);
while (it.hasNext()) {
@@ -1369,7 +1385,9 @@ void NestedListModel::setProperty(int index, const QString& property, const QVar
Q_ASSERT(index >=0 && index < count());
ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index));
- node->setProperty(property, value);
+ bool emitItemsChanged = node->setProperty(property, value);
+ if (!emitItemsChanged)
+ return;
int r = roleStrings.indexOf(property);
if (r < 0) {
@@ -1441,26 +1459,37 @@ void ModelNode::clear()
properties.clear();
}
-void ModelNode::setObjectValue(const QScriptValue& valuemap, bool writeToCache) {
+bool ModelNode::setObjectValue(const QScriptValue& valuemap, bool writeToCache)
+{
+ bool emitItemsChanged = false;
+
QScriptValueIterator it(valuemap);
while (it.hasNext()) {
it.next();
+ ModelNode *prev = properties.value(it.name());
ModelNode *value = new ModelNode(m_model);
QScriptValue v = it.value();
+
if (v.isArray()) {
value->isArray = true;
value->setListValue(v);
if (writeToCache && objectCache)
objectCache->setValue(it.name().toUtf8(), QVariant::fromValue(value->model(m_model)));
+ emitItemsChanged = true; // for now, too inefficient to check whether list and sublists have changed
} else {
value->values << v.toVariant();
if (writeToCache && objectCache)
objectCache->setValue(it.name().toUtf8(), value->values.last());
+ if (!emitItemsChanged && prev && prev->values.count() == 1
+ && prev->values[0] != value->values.last()) {
+ emitItemsChanged = true;
+ }
}
if (properties.contains(it.name()))
delete properties[it.name()];
properties.insert(it.name(), value);
}
+ return emitItemsChanged;
}
void ModelNode::setListValue(const QScriptValue& valuelist) {
@@ -1483,9 +1512,12 @@ void ModelNode::setListValue(const QScriptValue& valuelist) {
}
}
-void ModelNode::setProperty(const QString& prop, const QVariant& val) {
+bool ModelNode::setProperty(const QString& prop, const QVariant& val) {
QHash<QString, ModelNode *>::const_iterator it = properties.find(prop);
+ bool emitItemsChanged = false;
if (it != properties.end()) {
+ if (val != (*it)->values[0])
+ emitItemsChanged = true;
(*it)->values[0] = val;
} else {
ModelNode *n = new ModelNode(m_model);
@@ -1494,6 +1526,7 @@ void ModelNode::setProperty(const QString& prop, const QVariant& val) {
}
if (objectCache)
objectCache->setValue(prop.toUtf8(), val);
+ return emitItemsChanged;
}
void ModelNode::updateListIndexes()
@@ -1561,7 +1594,7 @@ ModelObject::ModelObject(ModelNode *node, NestedListModel *model, QScriptEngine
void ModelObject::setValue(const QByteArray &name, const QVariant &val)
{
m_meta->setValue(name, val);
- setProperty(name.constData(), val);
+ //setProperty(name.constData(), val);
}
void ModelObject::setNodeUpdatesEnabled(bool enable)
@@ -1588,9 +1621,9 @@ void ModelNodeMetaObject::propertyWritten(int index)
QScriptValue sv = m_seng->newObject();
sv.setProperty(propName, m_seng->newVariant(value));
- m_obj->m_node->setObjectValue(sv, false);
-
- m_obj->m_node->changedProperty(propName);
+ bool changed = m_obj->m_node->setObjectValue(sv, false);
+ if (changed)
+ m_obj->m_node->changedProperty(propName);
}
diff --git a/src/declarative/util/qdeclarativelistmodel_p.h b/src/declarative/util/qdeclarativelistmodel_p.h
index 90036f9..0b4becd 100644
--- a/src/declarative/util/qdeclarativelistmodel_p.h
+++ b/src/declarative/util/qdeclarativelistmodel_p.h
@@ -103,6 +103,9 @@ private:
// Constructs a flat list model for a worker agent
QDeclarativeListModel(const QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *parent);
+ void set(int index, const QScriptValue&, QList<int> *roles);
+ void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles);
+
bool flatten();
bool inWorkerThread() const;
diff --git a/src/declarative/util/qdeclarativelistmodel_p_p.h b/src/declarative/util/qdeclarativelistmodel_p_p.h
index 43a0a9b..ec1b538 100644
--- a/src/declarative/util/qdeclarativelistmodel_p_p.h
+++ b/src/declarative/util/qdeclarativelistmodel_p_p.h
@@ -190,7 +190,7 @@ public:
bool insert(int index, const QScriptValue&);
QScriptValue get(int index) const;
void set(int index, const QScriptValue&, QList<int> *roles);
- void setProperty(int index, const QString& property, const QVariant& value, QList<int> *role);
+ void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles);
void move(int from, int to, int count);
QVariant valueForNode(ModelNode *, bool *hasNested = 0) const;
@@ -255,9 +255,9 @@ struct ModelNode
QDeclarativeListModel *model(const NestedListModel *model);
ModelObject *object(const NestedListModel *model);
- void setObjectValue(const QScriptValue& valuemap, bool writeToCache = true);
+ bool setObjectValue(const QScriptValue& valuemap, bool writeToCache = true);
void setListValue(const QScriptValue& valuelist);
- void setProperty(const QString& prop, const QVariant& val);
+ bool setProperty(const QString& prop, const QVariant& val);
void changedProperty(const QString &name) const;
void updateListIndexes();
static void dump(ModelNode *node, int ind);
diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp
index 852b055..76d3048 100644
--- a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp
+++ b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp
@@ -60,25 +60,25 @@ void QDeclarativeListModelWorkerAgent::Data::clearChange()
void QDeclarativeListModelWorkerAgent::Data::insertChange(int index, int count)
{
- Change c = { Change::Inserted, index, count, 0 };
+ Change c = { Change::Inserted, index, count, 0, QList<int>() };
changes << c;
}
void QDeclarativeListModelWorkerAgent::Data::removeChange(int index, int count)
{
- Change c = { Change::Removed, index, count, 0 };
+ Change c = { Change::Removed, index, count, 0, QList<int>() };
changes << c;
}
void QDeclarativeListModelWorkerAgent::Data::moveChange(int index, int count, int to)
{
- Change c = { Change::Moved, index, count, to };
+ Change c = { Change::Moved, index, count, to, QList<int>() };
changes << c;
}
-void QDeclarativeListModelWorkerAgent::Data::changedChange(int index, int count)
+void QDeclarativeListModelWorkerAgent::Data::changedChange(int index, int count, const QList<int> &roles)
{
- Change c = { Change::Changed, index, count, 0 };
+ Change c = { Change::Changed, index, count, 0, roles };
changes << c;
}
@@ -165,14 +165,18 @@ QScriptValue QDeclarativeListModelWorkerAgent::get(int index) const
void QDeclarativeListModelWorkerAgent::set(int index, const QScriptValue &value)
{
- m_copy->set(index, value);
- data.changedChange(index, 1);
+ QList<int> roles;
+ m_copy->set(index, value, &roles);
+ if (!roles.isEmpty())
+ data.changedChange(index, 1, roles);
}
void QDeclarativeListModelWorkerAgent::setProperty(int index, const QString& property, const QVariant& value)
{
- m_copy->setProperty(index, property, value);
- data.changedChange(index, 1);
+ QList<int> roles;
+ m_copy->setProperty(index, property, value, &roles);
+ if (!roles.isEmpty())
+ data.changedChange(index, 1, roles);
}
void QDeclarativeListModelWorkerAgent::move(int from, int to, int count)
@@ -194,9 +198,9 @@ void QDeclarativeListModelWorkerAgent::sync()
mutex.unlock();
}
-void QDeclarativeListModelWorkerAgent::changedData(int index, int count)
+void QDeclarativeListModelWorkerAgent::changedData(int index, int count, const QList<int> &roles)
{
- data.changedChange(index, count);
+ data.changedChange(index, count, roles);
}
bool QDeclarativeListModelWorkerAgent::event(QEvent *e)
@@ -255,7 +259,7 @@ bool QDeclarativeListModelWorkerAgent::event(QEvent *e)
emit m_orig->itemsMoved(change.index, change.to, change.count);
break;
case Change::Changed:
- emit m_orig->itemsChanged(change.index, change.count, orig->m_roles.keys());
+ emit m_orig->itemsChanged(change.index, change.count, change.roles);
break;
}
}
diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h
index 10c3bca..0823b7e 100644
--- a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h
+++ b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h
@@ -124,6 +124,7 @@ private:
int index; // Inserted/Removed/Moved/Changed
int count; // Inserted/Removed/Moved/Changed
int to; // Moved
+ QList<int> roles;
};
struct Data {
@@ -133,7 +134,7 @@ private:
void insertChange(int index, int count);
void removeChange(int index, int count);
void moveChange(int index, int count, int to);
- void changedChange(int index, int count);
+ void changedChange(int index, int count, const QList<int> &roles);
};
Data data;
@@ -143,7 +144,7 @@ private:
QDeclarativeListModel *list;
};
- void changedData(int index, int count);
+ void changedData(int index, int count, const QList<int> &roles);
QAtomicInt m_ref;
QDeclarativeListModel *m_orig;
diff --git a/tests/auto/declarative/qdeclarativegridview/data/gridview1.qml b/tests/auto/declarative/qdeclarativegridview/data/gridview1.qml
index 77c94ba..e4e699c 100644
--- a/tests/auto/declarative/qdeclarativegridview/data/gridview1.qml
+++ b/tests/auto/declarative/qdeclarativegridview/data/gridview1.qml
@@ -2,6 +2,8 @@ import QtQuick 1.0
Rectangle {
id: root
+ property bool showHeader: false
+ property bool showFooter: false
property int added: -1
property variant removed
@@ -40,6 +42,10 @@ Rectangle {
GridView.onAdd: root.added = index
GridView.onRemove: root.removed = name
}
+ },
+ Component {
+ id: headerFooter
+ Rectangle { width: 30; height: 320; color: "blue" }
}
]
GridView {
@@ -52,5 +58,7 @@ Rectangle {
flow: (testTopToBottom == false) ? "LeftToRight" : "TopToBottom"
model: testModel
delegate: myDelegate
+ header: root.showHeader ? headerFooter : null
+ footer: root.showFooter ? headerFooter : null
}
}
diff --git a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp
index bb06c3c..ab80b56 100644
--- a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp
+++ b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp
@@ -86,6 +86,8 @@ private slots:
void footer();
void header();
void indexAt();
+ void testQtQuick11Attributes();
+ void testQtQuick11Attributes_data();
private:
QDeclarativeView *createView();
@@ -1133,6 +1135,24 @@ void tst_QDeclarativeGridView::positionViewAtIndex()
gridview->positionViewAtIndex(25, QDeclarativeGridView::Contain);
QTRY_COMPARE(gridview->contentX(), 240.);
+ // positionViewAtBeginning
+ gridview->positionViewAtBeginning();
+ QTRY_COMPARE(gridview->contentX(), 0.);
+
+ gridview->setContentX(80);
+ canvas->rootObject()->setProperty("showHeader", true);
+ gridview->positionViewAtBeginning();
+ QTRY_COMPARE(gridview->contentX(), -30.);
+
+ // positionViewAtEnd
+ gridview->positionViewAtEnd();
+ QTRY_COMPARE(gridview->contentX(), 430.);
+
+ gridview->setContentX(80);
+ canvas->rootObject()->setProperty("showFooter", true);
+ gridview->positionViewAtEnd();
+ QTRY_COMPARE(gridview->contentX(), 460.);
+
delete canvas;
}
@@ -1429,6 +1449,45 @@ void tst_QDeclarativeGridView::indexAt()
delete canvas;
}
+void tst_QDeclarativeGridView::testQtQuick11Attributes()
+{
+ QFETCH(QString, code);
+ QFETCH(QString, warning);
+ QFETCH(QString, error);
+
+ QDeclarativeEngine engine;
+ QObject *obj;
+
+ QDeclarativeComponent valid(&engine);
+ valid.setData("import QtQuick 1.1; GridView { " + code.toUtf8() + " }", QUrl(""));
+ obj = valid.create();
+ QVERIFY(obj);
+ QVERIFY(valid.errorString().isEmpty());
+ delete obj;
+
+ QDeclarativeComponent invalid(&engine);
+ invalid.setData("import QtQuick 1.0; GridView { " + code.toUtf8() + " }", QUrl(""));
+ QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
+ obj = invalid.create();
+ QCOMPARE(invalid.errorString(), error);
+ delete obj;
+}
+
+void tst_QDeclarativeGridView::testQtQuick11Attributes_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<QString>("warning");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("positionViewAtBeginning") << "Component.onCompleted: positionViewAtBeginning()"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtBeginning"
+ << "";
+
+ QTest::newRow("positionViewAtEnd") << "Component.onCompleted: positionViewAtEnd()"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtEnd"
+ << "";
+}
+
QDeclarativeView *tst_QDeclarativeGridView::createView()
{
QDeclarativeView *canvas = new QDeclarativeView(0);
diff --git a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp
index 55f7421..bdc5988 100644
--- a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp
+++ b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp
@@ -59,6 +59,7 @@
#endif
Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<QVariantHash>)
class tst_qdeclarativelistmodel : public QObject
{
@@ -101,6 +102,10 @@ private slots:
void get_nested_data();
void crash_model_with_multiple_roles();
void set_model_cache();
+ void property_changes();
+ void property_changes_data();
+ void property_changes_worker();
+ void property_changes_worker_data();
};
int tst_qdeclarativelistmodel::roleFromName(const QDeclarativeListModel *model, const QString &roleName)
{
@@ -298,13 +303,10 @@ void tst_qdeclarativelistmodel::dynamic_data()
QTest::newRow("nested-append3") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]});get(0).bars.append({'a':4});get(0).bars.get(3).a}" << 4 << "";
QTest::newRow("nested-insert") << "{append({'foo':123});insert(0,{'bars':[{'a':1},{'b':2},{'c':3}]});get(0).bars.get(0).a}" << 1 << "";
- QTest::newRow("nested-set") << "{append({'foo':123});set(0,{'foo':[{'x':123}]});get(0).foo.get(0).x}" << 123 << "";
+ QTest::newRow("nested-set") << "{append({'foo':[{'x':1}]});set(0,{'foo':[{'x':123}]});get(0).foo.get(0).x}" << 123 << "";
QTest::newRow("nested-count") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]}); get(0).bars.count}" << 3 << "";
QTest::newRow("nested-clear") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]}); get(0).bars.clear(); get(0).bars.count}" << 0 << "";
-
- // XXX
- //QTest::newRow("nested-setprop") << "{append({'foo':123});setProperty(0,'foo',[{'x':123}]);get(0).foo.get(0).x}" << 123 << "";
}
void tst_qdeclarativelistmodel::dynamic()
@@ -421,6 +423,9 @@ void tst_qdeclarativelistmodel::dynamic_worker_sync()
if (QByteArray(QTest::currentDataTag()).startsWith("nested"))
QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML ListModel: Cannot add list-type data when modifying or after modification from a worker script");
+ if (QByteArray(QTest::currentDataTag()).startsWith("nested-set"))
+ QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML ListModel: Cannot add list-type data when modifying or after modification from a worker script");
+
QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker",
Q_ARG(QVariant, operations.mid(0, operations.length()-1))));
waitForWorker(item);
@@ -940,6 +945,152 @@ void tst_qdeclarativelistmodel::set_model_cache()
QVERIFY(model->property("ok").toBool());
}
+void tst_qdeclarativelistmodel::property_changes()
+{
+ QFETCH(QString, script_setup);
+ QFETCH(QString, script_change);
+ QFETCH(QString, roleName);
+ QFETCH(int, listIndex);
+ QFETCH(bool, itemsChanged);
+ QFETCH(QString, testExpression);
+
+ QDeclarativeEngine engine;
+ QDeclarativeListModel model;
+ QDeclarativeEngine::setContextForObject(&model, engine.rootContext());
+ engine.rootContext()->setContextObject(&model);
+
+ QDeclarativeExpression expr(engine.rootContext(), &model, script_setup);
+ expr.evaluate();
+ QVERIFY2(!expr.hasError(), QTest::toString(expr.error().toString()));
+
+ QString signalHandler = "on" + QString(roleName[0].toUpper()) + roleName.mid(1, roleName.length()) + "Changed:";
+ QString qml = "import QtQuick 1.0\n"
+ "Connections {\n"
+ "property bool gotSignal: false\n"
+ "target: model.get(0)\n"
+ + signalHandler + " gotSignal = true\n"
+ "}\n";
+ QDeclarativeComponent component(&engine);
+ component.setData(qml.toUtf8(), QUrl::fromLocalFile(""));
+ engine.rootContext()->setContextProperty("model", &model);
+ QObject *connectionsObject = component.create();
+ QVERIFY2(component.errorString().isEmpty(), QTest::toString(component.errorString()));
+
+ QSignalSpy spyItemsChanged(&model, SIGNAL(itemsChanged(int, int, QList<int>)));
+
+ expr.setExpression(script_change);
+ expr.evaluate();
+ QVERIFY2(!expr.hasError(), QTest::toString(expr.error()));
+
+ // test the object returned by get() emits the correct signals
+ QCOMPARE(connectionsObject->property("gotSignal").toBool(), itemsChanged);
+
+ // test itemsChanged() is emitted correctly
+ if (itemsChanged) {
+ QCOMPARE(spyItemsChanged.count(), 1);
+ QCOMPARE(spyItemsChanged.at(0).at(0).toInt(), listIndex);
+ QCOMPARE(spyItemsChanged.at(0).at(1).toInt(), 1);
+ } else {
+ QCOMPARE(spyItemsChanged.count(), 0);
+ }
+
+ expr.setExpression(testExpression);
+ QCOMPARE(expr.evaluate().toBool(), true);
+
+ delete connectionsObject;
+}
+
+void tst_qdeclarativelistmodel::property_changes_data()
+{
+ QTest::addColumn<QString>("script_setup");
+ QTest::addColumn<QString>("script_change");
+ QTest::addColumn<QString>("roleName");
+ QTest::addColumn<int>("listIndex");
+ QTest::addColumn<bool>("itemsChanged");
+ QTest::addColumn<QString>("testExpression");
+
+ QTest::newRow("set: plain") << "append({'a':123, 'b':456, 'c':789});" << "set(0,{'b':123});"
+ << "b" << 0 << true << "get(0).b == 123";
+ QTest::newRow("setProperty: plain") << "append({'a':123, 'b':456, 'c':789});" << "setProperty(0, 'b', 123);"
+ << "b" << 0 << true << "get(0).b == 123";
+
+ QTest::newRow("set: plain, no changes") << "append({'a':123, 'b':456, 'c':789});" << "set(0,{'b':456});"
+ << "b" << 0 << false << "get(0).b == 456";
+ QTest::newRow("setProperty: plain, no changes") << "append({'a':123, 'b':456, 'c':789});" << "setProperty(0, 'b', 456);"
+ << "b" << 0 << false << "get(0).b == 456";
+
+ // Following tests only call set() since setProperty() only allows plain
+ // values, not lists, as the argument.
+ // Note that when a list is changed, itemsChanged() is currently always
+ // emitted regardless of whether it actually changed or not.
+
+ QTest::newRow("nested-set: list, new size") << "append({'a':123, 'b':[{'a':1},{'a':2},{'a':3}], 'c':789});" << "set(0,{'b':[{'a':1},{'a':2}]});"
+ << "b" << 0 << true << "get(0).b.get(0).a == 1 && get(0).b.get(1).a == 2";
+
+ QTest::newRow("nested-set: list, empty -> non-empty") << "append({'a':123, 'b':[], 'c':789});" << "set(0,{'b':[{'a':1},{'a':2},{'a':3}]});"
+ << "b" << 0 << true << "get(0).b.get(0).a == 1 && get(0).b.get(1).a == 2 && get(0).b.get(2).a == 3";
+
+ QTest::newRow("nested-set: list, non-empty -> empty") << "append({'a':123, 'b':[{'a':1},{'a':2},{'a':3}], 'c':789});" << "set(0,{'b':[]});"
+ << "b" << 0 << true << "get(0).b.count == 0";
+
+ QTest::newRow("nested-set: list, same size, different values") << "append({'a':123, 'b':[{'a':1},{'a':2},{'a':3}], 'c':789});" << "set(0,{'b':[{'a':1},{'a':222},{'a':3}]});"
+ << "b" << 0 << true << "get(0).b.get(0).a == 1 && get(0).b.get(1).a == 222 && get(0).b.get(2).a == 3";
+
+ QTest::newRow("nested-set: list, no changes") << "append({'a':123, 'b':[{'a':1},{'a':2},{'a':3}], 'c':789});" << "set(0,{'b':[{'a':1},{'a':2},{'a':3}]});"
+ << "b" << 0 << true << "get(0).b.get(0).a == 1 && get(0).b.get(1).a == 2 && get(0).b.get(2).a == 3";
+
+ QTest::newRow("nested-set: list, no changes, empty") << "append({'a':123, 'b':[], 'c':789});" << "set(0,{'b':[]});"
+ << "b" << 0 << true << "get(0).b.count == 0";
+}
+
+
+void tst_qdeclarativelistmodel::property_changes_worker()
+{
+ // nested models are not supported when WorkerScript is involved
+ if (QByteArray(QTest::currentDataTag()).startsWith("nested-"))
+ return;
+
+ QFETCH(QString, script_setup);
+ QFETCH(QString, script_change);
+ QFETCH(QString, roleName);
+ QFETCH(int, listIndex);
+ QFETCH(bool, itemsChanged);
+
+ QDeclarativeListModel model;
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/model.qml"));
+ QVERIFY2(component.errorString().isEmpty(), component.errorString().toUtf8());
+ QDeclarativeItem *item = createWorkerTest(&engine, &component, &model);
+ QVERIFY(item != 0);
+
+ QDeclarativeExpression expr(engine.rootContext(), &model, script_setup);
+ expr.evaluate();
+ QVERIFY2(!expr.hasError(), QTest::toString(expr.error().toString()));
+
+ QSignalSpy spyItemsChanged(&model, SIGNAL(itemsChanged(int, int, QList<int>)));
+
+ QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker",
+ Q_ARG(QVariant, QStringList(script_change))));
+ waitForWorker(item);
+
+ // test itemsChanged() is emitted correctly
+ if (itemsChanged) {
+ QCOMPARE(spyItemsChanged.count(), 1);
+ QCOMPARE(spyItemsChanged.at(0).at(0).toInt(), listIndex);
+ QCOMPARE(spyItemsChanged.at(0).at(1).toInt(), 1);
+ } else {
+ QCOMPARE(spyItemsChanged.count(), 0);
+ }
+
+ delete item;
+ qApp->processEvents();
+}
+
+void tst_qdeclarativelistmodel::property_changes_worker_data()
+{
+ property_changes_data();
+}
+
QTEST_MAIN(tst_qdeclarativelistmodel)
#include "tst_qdeclarativelistmodel.moc"
diff --git a/tests/auto/declarative/qdeclarativelistview/data/listviewtest.qml b/tests/auto/declarative/qdeclarativelistview/data/listviewtest.qml
index 534540f..3cd6f42 100644
--- a/tests/auto/declarative/qdeclarativelistview/data/listviewtest.qml
+++ b/tests/auto/declarative/qdeclarativelistview/data/listviewtest.qml
@@ -1,10 +1,13 @@
import QtQuick 1.0
Rectangle {
+ id: root
width: 240
height: 320
color: "#ffffff"
+ property bool showHeader: false
+ property bool showFooter: false
property real hr: list.visibleArea.heightRatio
function heightRatio() {
return list.visibleArea.heightRatio
@@ -105,6 +108,10 @@ Rectangle {
Component {
id: invalidHl
SmoothedAnimation {}
+ },
+ Component {
+ id: headerFooter
+ Rectangle { height: 30; width: 240; color: "blue" }
}
]
ListView {
@@ -119,5 +126,7 @@ Rectangle {
highlightMoveSpeed: 1000
highlightResizeSpeed: 1000
cacheBuffer: testObject.cacheBuffer
+ header: root.showHeader ? headerFooter : null
+ footer: root.showFooter ? headerFooter : null
}
}
diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp
index e76cb15..80c0118 100644
--- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp
+++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp
@@ -108,6 +108,8 @@ private slots:
void QTBUG_16037();
void indexAt();
void incrementalModel();
+ void testQtQuick11Attributes();
+ void testQtQuick11Attributes_data();
private:
template <class T> void items();
@@ -1370,6 +1372,24 @@ void tst_QDeclarativeListView::positionViewAtIndex()
listview->positionViewAtIndex(20, QDeclarativeListView::Contain);
QTRY_COMPARE(listview->contentY(), 100.);
+ // positionAtBeginnging
+ listview->positionViewAtBeginning();
+ QTRY_COMPARE(listview->contentY(), 0.);
+
+ listview->setContentY(80);
+ canvas->rootObject()->setProperty("showHeader", true);
+ listview->positionViewAtBeginning();
+ QTRY_COMPARE(listview->contentY(), -30.);
+
+ // positionAtEnd
+ listview->positionViewAtEnd();
+ QTRY_COMPARE(listview->contentY(), 480.); // 40*20 - 320
+
+ listview->setContentY(80);
+ canvas->rootObject()->setProperty("showFooter", true);
+ listview->positionViewAtEnd();
+ QTRY_COMPARE(listview->contentY(), 510.);
+
delete canvas;
}
@@ -2026,6 +2046,45 @@ void tst_QDeclarativeListView::incrementalModel()
delete canvas;
}
+void tst_QDeclarativeListView::testQtQuick11Attributes()
+{
+ QFETCH(QString, code);
+ QFETCH(QString, warning);
+ QFETCH(QString, error);
+
+ QDeclarativeEngine engine;
+ QObject *obj;
+
+ QDeclarativeComponent valid(&engine);
+ valid.setData("import QtQuick 1.1; ListView { " + code.toUtf8() + " }", QUrl(""));
+ obj = valid.create();
+ QVERIFY(obj);
+ QVERIFY(valid.errorString().isEmpty());
+ delete obj;
+
+ QDeclarativeComponent invalid(&engine);
+ invalid.setData("import QtQuick 1.0; ListView { " + code.toUtf8() + " }", QUrl(""));
+ QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
+ obj = invalid.create();
+ QCOMPARE(invalid.errorString(), error);
+ delete obj;
+}
+
+void tst_QDeclarativeListView::testQtQuick11Attributes_data()
+{
+ QTest::addColumn<QString>("code");
+ QTest::addColumn<QString>("warning");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("positionViewAtBeginning") << "Component.onCompleted: positionViewAtBeginning()"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtBeginning"
+ << "";
+
+ QTest::newRow("positionViewAtEnd") << "Component.onCompleted: positionViewAtEnd()"
+ << "<Unknown File>:1: ReferenceError: Can't find variable: positionViewAtEnd"
+ << "";
+}
+
void tst_QDeclarativeListView::qListModelInterface_items()
{
items<TestModel>();
diff --git a/tests/auto/declarative/qdeclarativeqt/data/formatting.qml b/tests/auto/declarative/qdeclarativeqt/data/formatting.qml
index 35c6a29..f520aeb 100644
--- a/tests/auto/declarative/qdeclarativeqt/data/formatting.qml
+++ b/tests/auto/declarative/qdeclarativeqt/data/formatting.qml
@@ -1,29 +1,44 @@
import QtQuick 1.0
QtObject {
- property date date1: "2008-12-24"
- property string test1: Qt.formatDate(date1)
- property string test2: Qt.formatDate(date1, Qt.DefaultLocaleLongDate)
- property string test3: Qt.formatDate(date1, "ddd MMMM d yy")
+ property date dateFromString: "2008-12-24"
+ property variant jsdate: new Date(2008,11,24,14,15,38,200) // months are 0-based
- property variant time1: new Date(0,0,0,14,15,38,200)
- property string test4: Qt.formatTime(time1)
- property string test5: Qt.formatTime(time1, Qt.DefaultLocaleLongDate)
- property string test6: Qt.formatTime(time1, "H:m:s a")
- property string test7: Qt.formatTime(time1, "hh:mm:ss.zzz")
+ function formatDate(prop) {
+ var v = eval(prop)
+ return [
+ Qt.formatDate(v),
+ Qt.formatDate(v, Qt.DefaultLocaleLongDate),
+ Qt.formatDate(v, "ddd MMMM d yy")
+ ]
+ }
- property variant dateTime1: new Date(1978,2,4,9,13,54)
- property string test8: Qt.formatDateTime(dateTime1)
- property string test9: Qt.formatDateTime(dateTime1, Qt.DefaultLocaleLongDate)
- property string test10: Qt.formatDateTime(dateTime1, "M/d/yy H:m:s a")
+ function formatTime(prop) {
+ var v = eval(prop)
+ return [
+ Qt.formatTime(v),
+ Qt.formatTime(v, Qt.DefaultLocaleLongDate),
+ Qt.formatTime(v, "H:m:s a"),
+ Qt.formatTime(v, "hh:mm:ss.zzz")
+ ]
+ }
+
+ function formatDateTime(prop) {
+ var v = eval(prop)
+ return [
+ Qt.formatDateTime(v),
+ Qt.formatDateTime(v, Qt.DefaultLocaleLongDate),
+ Qt.formatDateTime(v, "M/d/yy H:m:s a")
+ ]
+ }
// Error cases
- property string test11: Qt.formatDate()
- property string test12: Qt.formatDate(new Date, new Object)
+ property string err_date1: Qt.formatDate()
+ property string err_date2: Qt.formatDate(new Date, new Object)
- property string test13: Qt.formatTime()
- property string test14: Qt.formatTime(new Date, new Object)
+ property string err_time1: Qt.formatTime()
+ property string err_time2: Qt.formatTime(new Date, new Object)
- property string test15: Qt.formatDateTime()
- property string test16: Qt.formatDateTime(new Date, new Object)
+ property string err_dateTime1: Qt.formatDateTime()
+ property string err_dateTime2: Qt.formatDateTime(new Date, new Object)
}
diff --git a/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro b/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro
index 6af6500..9e698fe 100644
--- a/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro
+++ b/tests/auto/declarative/qdeclarativeqt/qdeclarativeqt.pro
@@ -1,5 +1,5 @@
load(qttest_p4)
-contains(QT_CONFIG,declarative): QT += declarative
+contains(QT_CONFIG,declarative): QT += declarative script
SOURCES += tst_qdeclarativeqt.cpp
macx:CONFIG -= app_bundle
diff --git a/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp b/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp
index 9f45d74..c8c1a22 100644
--- a/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp
+++ b/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp
@@ -38,6 +38,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+#include <private/qdeclarativeengine_p.h>
#include <qtest.h>
#include <QDebug>
@@ -81,7 +82,8 @@ private slots:
void createComponent_pragmaLibrary();
void createQmlObject();
void consoleLog();
- void formatting();
+ void dateTimeFormatting();
+ void dateTimeFormatting_data();
void isQtObject();
void btoa();
void atob();
@@ -446,49 +448,88 @@ void tst_qdeclarativeqt::consoleLog()
delete object;
}
-void tst_qdeclarativeqt::formatting()
+void tst_qdeclarativeqt::dateTimeFormatting()
{
- QDeclarativeComponent component(&engine, TEST_FILE("formatting.qml"));
+ QFETCH(QString, method);
+ QFETCH(QStringList, inputProperties);
+ QFETCH(QStringList, expectedResults);
- QString warning1 = component.url().toString() + ":22: Error: Qt.formatDate(): Invalid date format";
- QString warning2 = component.url().toString() + ":21: Error: Qt.formatDate(): Invalid arguments";
- QString warning3 = component.url().toString() + ":28: Error: Qt.formatDateTime(): Invalid datetime format";
- QString warning4 = component.url().toString() + ":27: Error: Qt.formatDateTime(): Invalid arguments";
- QString warning5 = component.url().toString() + ":25: Error: Qt.formatTime(): Invalid time format";
- QString warning6 = component.url().toString() + ":24: Error: Qt.formatTime(): Invalid arguments";
+ QDate date(2008,12,24);
+ QTime time(14,15,38,200);
+ QDateTime dateTime(date, time);
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning3));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning4));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning5));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning6));
+ QDeclarativeEngine eng;
+
+ eng.rootContext()->setContextProperty("qdate", date);
+ eng.rootContext()->setContextProperty("qtime", time);
+ eng.rootContext()->setContextProperty("qdatetime", dateTime);
+
+ QDeclarativeComponent component(&eng, TEST_FILE("formatting.qml"));
+
+ QStringList warnings;
+ warnings << component.url().toString() + ":37: Error: Qt.formatDate(): Invalid date format"
+ << component.url().toString() + ":36: Error: Qt.formatDate(): Invalid arguments"
+ << component.url().toString() + ":40: Error: Qt.formatTime(): Invalid time format"
+ << component.url().toString() + ":39: Error: Qt.formatTime(): Invalid arguments"
+ << component.url().toString() + ":43: Error: Qt.formatDateTime(): Invalid datetime format"
+ << component.url().toString() + ":42: Error: Qt.formatDateTime(): Invalid arguments";
+
+ foreach (const QString &warning, warnings)
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QObject *object = component.create();
+ QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
QVERIFY(object != 0);
- QDate date1(2008,12,24);
- QCOMPARE(object->property("date1").toDate(), date1);
- QCOMPARE(object->property("test1").toString(), date1.toString(Qt::DefaultLocaleShortDate));
- QCOMPARE(object->property("test2").toString(), date1.toString(Qt::DefaultLocaleLongDate));
- QCOMPARE(object->property("test3").toString(), date1.toString("ddd MMMM d yy"));
-
- QTime time1(14,15,38,200);
- QCOMPARE(object->property("time1").toTime(), time1);
- QCOMPARE(object->property("test4").toString(), time1.toString(Qt::DefaultLocaleShortDate));
- QCOMPARE(object->property("test5").toString(), time1.toString(Qt::DefaultLocaleLongDate));
- QCOMPARE(object->property("test6").toString(), time1.toString("H:m:s a"));
- QCOMPARE(object->property("test7").toString(), time1.toString("hh:mm:ss.zzz"));
-
- QDateTime dateTime1(QDate(1978,03,04),QTime(9,13,54));
- QCOMPARE(object->property("dateTime1").toDateTime(),dateTime1);
- QCOMPARE(object->property("test8").toString(), dateTime1.toString(Qt::DefaultLocaleShortDate));
- QCOMPARE(object->property("test9").toString(), dateTime1.toString(Qt::DefaultLocaleLongDate));
- QCOMPARE(object->property("test10").toString(), dateTime1.toString("M/d/yy H:m:s a"));
+ QVERIFY(inputProperties.count() > 0);
+
+ QVariant result;
+ foreach(const QString &prop, inputProperties) {
+ QVERIFY(QMetaObject::invokeMethod(object, method.toUtf8().constData(),
+ Q_RETURN_ARG(QVariant, result),
+ Q_ARG(QVariant, prop)));
+
+ QStringList output = result.toStringList();
+ for (int i=0; i<output.count(); i++)
+ QCOMPARE(output[i], expectedResults[i]);
+ }
delete object;
}
+void tst_qdeclarativeqt::dateTimeFormatting_data()
+{
+ QTest::addColumn<QString>("method");
+ QTest::addColumn<QStringList>("inputProperties");
+ QTest::addColumn<QStringList>("expectedResults");
+
+ QDate date(2008,12,24);
+ QTime time(14,15,38,200);
+ QDateTime dateTime(date, time);
+
+ QTest::newRow("formatDate")
+ << "formatDate"
+ << (QStringList() << "dateFromString" << "jsdate" << "qdate" << "qdatetime")
+ << (QStringList() << date.toString(Qt::DefaultLocaleShortDate)
+ << date.toString(Qt::DefaultLocaleLongDate)
+ << date.toString("ddd MMMM d yy"));
+
+ QTest::newRow("formatTime")
+ << "formatTime"
+ << (QStringList() << "jsdate" << "qtime" << "qdatetime")
+ << (QStringList() << time.toString(Qt::DefaultLocaleShortDate)
+ << time.toString(Qt::DefaultLocaleLongDate)
+ << time.toString("H:m:s a")
+ << time.toString("hh:mm:ss.zzz"));
+
+ QTest::newRow("formatDateTime")
+ << "formatDateTime"
+ << (QStringList() << "jsdate" << "qdatetime")
+ << (QStringList() << dateTime.toString(Qt::DefaultLocaleShortDate)
+ << dateTime.toString(Qt::DefaultLocaleLongDate)
+ << dateTime.toString("M/d/yy H:m:s a"));
+}
+
void tst_qdeclarativeqt::isQtObject()
{
QDeclarativeComponent component(&engine, TEST_FILE("isQtObject.qml"));