From 7d09f690d5b4c56699092444665d1879deb86a6e Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 9 Jul 2010 16:28:18 +0200 Subject: Fixes crash in QGraphicsScene::addItem(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Crashed because tabFocusFirst could end up being a dangling pointer when removing an item from the scene before deleting it. When setting tabFocusFirst in fixFocusChainBeforeReparenting, we now check that the item is in the scene. If it is not, tabFocusFirst is set to 0. Autotest included. Task-number: QTBUG-12056 Reviewed-by: Alexis Ménard --- src/gui/graphicsview/qgraphicswidget_p.cpp | 4 ++-- tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp index 28070da..f7850ca 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.cpp +++ b/src/gui/graphicsview/qgraphicswidget_p.cpp @@ -761,7 +761,7 @@ void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *new QGraphicsWidget *firstOld = 0; bool wasPreviousNew = true; - + while (w != q) { bool isCurrentNew = q->isAncestorOf(w); if (isCurrentNew) { @@ -796,7 +796,7 @@ void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *new newScene = newParent->scene(); if (oldScene && newScene != oldScene) - oldScene->d_func()->tabFocusFirst = firstOld; + oldScene->d_func()->tabFocusFirst = (firstOld && firstOld->scene() == oldScene) ? firstOld : 0; QGraphicsItem *topLevelItem = newParent ? newParent->topLevelItem() : 0; QGraphicsWidget *topLevel = 0; diff --git a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp index ed8ff04..a771332 100644 --- a/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp +++ b/tests/auto/qgraphicswidget/tst_qgraphicswidget.cpp @@ -176,6 +176,7 @@ private slots: void task243004_setStyleCrash(); void task250119_shortcutContext(); void QT_BUG_6544_tabFocusFirstUnsetWhenRemovingItems(); + void QT_BUG_12056_tabFocusFirstUnsetWhenRemovingItems(); }; @@ -3089,6 +3090,25 @@ void tst_QGraphicsWidget::QT_BUG_6544_tabFocusFirstUnsetWhenRemovingItems() //This should not crash } +void tst_QGraphicsWidget::QT_BUG_12056_tabFocusFirstUnsetWhenRemovingItems() +{ + QGraphicsScene scene; + QGraphicsWidget* item1 = new QGraphicsWidget; + QGraphicsWidget* item2 = new QGraphicsWidget; + QGraphicsWidget* item3 = new QGraphicsWidget; + + scene.addItem(item1); + scene.addItem(item2); + + scene.removeItem(item2); + scene.removeItem(item1); + delete item2; + delete item1; + + scene.addItem(item3); + + //This should not crash +} QTEST_MAIN(tst_QGraphicsWidget) #include "tst_qgraphicswidget.moc" -- cgit v0.12 From b5b011a181bd187dcef5ee8f46a3ac2c5dc2e09c Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 13 Jul 2010 14:21:44 +0200 Subject: Fixes QGraphicsItem::focusItem() returning incorrect value. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When setting focus on an item, subfocus chain was previously updated only for items with a common ancestor. We now make sure that this chain is updated also for the previously focused item (possibly not sharing any common ancestor with the newly focused item). Autotest included. Task-number: QTBUG-12112 Reviewed-by: Alexis Ménard --- src/gui/graphicsview/qgraphicsitem.cpp | 6 ++++-- tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 27 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 848de2c..fe2a84e 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -3257,6 +3257,8 @@ void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool clim } // Update the child focus chain. + if (scene && scene->focusItem()) + scene->focusItem()->d_ptr->clearSubFocus(); f->d_ptr->setSubFocus(); // Update the scene's focus item. @@ -7637,9 +7639,9 @@ int QGraphicsItemPrivate::children_count(QDeclarativeListProperty *list, int index) { QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast(list->object)); - if (index >= 0 && index < d->children.count()) + if (index >= 0 && index < d->children.count()) return d->children.at(index)->toGraphicsObject(); - else + else return 0; } diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 1ae3ecf..3634ce9 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -463,6 +463,7 @@ private slots: void sortItemsWhileAdding(); void doNotMarkFullUpdateIfNotInScene(); void itemDiesDuringDraggingOperation(); + void QTBUG_12112_focusItem(); private: QList paintedItems; @@ -10724,5 +10725,31 @@ void tst_QGraphicsItem::itemDiesDuringDraggingOperation() delete item; QVERIFY(QGraphicsScenePrivate::get(&scene)->dragDropItem == 0); } + +void tst_QGraphicsItem::QTBUG_12112_focusItem() +{ + QGraphicsScene scene; + QGraphicsView view(&scene); + QGraphicsRectItem *item1 = new QGraphicsRectItem(0, 0, 20, 20); + item1->setFlag(QGraphicsItem::ItemIsFocusable); + QGraphicsRectItem *item2 = new QGraphicsRectItem(20, 20, 20, 20); + item2->setFlag(QGraphicsItem::ItemIsFocusable); + item1->setFocus(); + scene.addItem(item2); + scene.addItem(item1); + + view.show(); + QApplication::setActiveWindow(&view); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(QApplication::activeWindow(), (QWidget *)&view); + + QVERIFY(item1->focusItem()); + QVERIFY(!item2->focusItem()); + + item2->setFocus(); + QVERIFY(!item1->focusItem()); + QVERIFY(item2->focusItem()); +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" -- cgit v0.12 From 7bd9e6c5805ab78c68161bec20c225965ea59ddb Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 14 Jul 2010 10:09:41 +1000 Subject: Enter key performs same action as Return key in QML demos. N900 has an Enter key, not a return key --- demos/declarative/flickr/mobile/TitleBar.qml | 1 + demos/declarative/photoviewer/PhotoViewerCore/EditableButton.qml | 4 ++++ demos/declarative/twitter/TwitterCore/AuthView.qml | 2 ++ demos/declarative/twitter/TwitterCore/HomeTitleBar.qml | 1 + demos/declarative/twitter/TwitterCore/TitleBar.qml | 1 + 5 files changed, 9 insertions(+) diff --git a/demos/declarative/flickr/mobile/TitleBar.qml b/demos/declarative/flickr/mobile/TitleBar.qml index c7e1a53..335c315 100644 --- a/demos/declarative/flickr/mobile/TitleBar.qml +++ b/demos/declarative/flickr/mobile/TitleBar.qml @@ -109,6 +109,7 @@ Item { Item { id: returnKey Keys.onReturnPressed: container.accept() + Keys.onEnterPressed: container.accept() Keys.onEscapePressed: titleBar.state = "" } } diff --git a/demos/declarative/photoviewer/PhotoViewerCore/EditableButton.qml b/demos/declarative/photoviewer/PhotoViewerCore/EditableButton.qml index 6109535..be7dfa4 100644 --- a/demos/declarative/photoviewer/PhotoViewerCore/EditableButton.qml +++ b/demos/declarative/photoviewer/PhotoViewerCore/EditableButton.qml @@ -64,6 +64,10 @@ Item { container.labelChanged(textInput.text) container.focus = true } + Keys.onEnterPressed: { + container.labelChanged(textInput.text) + container.focus = true + } Keys.onEscapePressed: { textInput.text = container.label container.focus = true diff --git a/demos/declarative/twitter/TwitterCore/AuthView.qml b/demos/declarative/twitter/TwitterCore/AuthView.qml index 4f75777..0d05deb 100644 --- a/demos/declarative/twitter/TwitterCore/AuthView.qml +++ b/demos/declarative/twitter/TwitterCore/AuthView.qml @@ -115,6 +115,7 @@ Item { KeyNavigation.tab: guest KeyNavigation.backtab: passIn Keys.onReturnPressed: login.doLogin(); + Keys.onEnterPressed: login.doLogin(); Keys.onSelectPressed: login.doLogin(); Keys.onSpacePressed: login.doLogin(); onClicked: login.doLogin(); @@ -135,6 +136,7 @@ Item { KeyNavigation.tab: nameIn KeyNavigation.backtab: login Keys.onReturnPressed: guest.doGuest(); + Keys.onEnterPressed: guest.doGuest(); Keys.onSelectPressed: guest.doGuest(); Keys.onSpacePressed: guest.doGuest(); onClicked: guest.doGuest(); diff --git a/demos/declarative/twitter/TwitterCore/HomeTitleBar.qml b/demos/declarative/twitter/TwitterCore/HomeTitleBar.qml index b26f7b3..56f31b1 100644 --- a/demos/declarative/twitter/TwitterCore/HomeTitleBar.qml +++ b/demos/declarative/twitter/TwitterCore/HomeTitleBar.qml @@ -136,6 +136,7 @@ Item { Item { id: returnKey Keys.onReturnPressed: container.accept() + Keys.onEnterPressed: container.accept() Keys.onEscapePressed: titleBar.state = "" } } diff --git a/demos/declarative/twitter/TwitterCore/TitleBar.qml b/demos/declarative/twitter/TwitterCore/TitleBar.qml index 6cd0a50..558bc18 100644 --- a/demos/declarative/twitter/TwitterCore/TitleBar.qml +++ b/demos/declarative/twitter/TwitterCore/TitleBar.qml @@ -98,6 +98,7 @@ Item { Item { id: returnKey Keys.onReturnPressed: container.accept() + Keys.onEnterPressed: container.accept() Keys.onEscapePressed: titleBar.state = "" } } -- cgit v0.12 From 237bc693a527f9cb2b6bbe7c518018cbf56b0eb6 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 14 Jul 2010 11:51:04 +1000 Subject: Fix test for get() to check for undefined return values Task-number: QTBUG-10658 --- .../qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp index f15ac8f..858c26d 100644 --- a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp +++ b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp @@ -193,8 +193,9 @@ void tst_qdeclarativelistmodel::dynamic_data() QTest::newRow("count") << "count" << 0 << ""; - QTest::newRow("get1") << "{get(0)}" << 0 << ""; - QTest::newRow("get2") << "{get(-1)}" << 0 << ""; + QTest::newRow("get1") << "{get(0) === undefined}" << 1 << ""; + QTest::newRow("get2") << "{get(-1) === undefined}" << 1 << ""; + QTest::newRow("get3") << "{append({'foo':123});get(0) != undefined}" << 1 << ""; QTest::newRow("append1") << "{append({'foo':123});count}" << 1 << ""; QTest::newRow("append2") << "{append({'foo':123,'bar':456});count}" << 1 << ""; @@ -292,8 +293,6 @@ void tst_qdeclarativelistmodel::dynamic() if (e.hasError()) qDebug() << e.error(); // errors not expected - if (QTest::currentDataTag() != QLatin1String("clear3") && QTest::currentDataTag() != QLatin1String("remove3")) - QVERIFY(!e.hasError()); QCOMPARE(actual,result); } @@ -308,6 +307,9 @@ void tst_qdeclarativelistmodel::dynamic_worker() QFETCH(int, result); QFETCH(QString, warning); + // This is same as dynamic() except it applies the test to a ListModel called + // from a WorkerScript (i.e. testing the internal NestedListModel class) + QDeclarativeListModel model; QDeclarativeEngine eng; QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); -- cgit v0.12 From 07ebc9161263c04dc072b9fc2a922b9665cbe7be Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 14 Jul 2010 11:51:22 +1000 Subject: improvements to docs and examples --- doc/src/declarative/anchor-layout.qdoc | 5 +- doc/src/declarative/basictypes.qdoc | 3 + doc/src/images/qml-mousearea-example.png | Bin 5527 -> 6969 bytes doc/src/images/qml-xmllistmodel-example.png | Bin 0 -> 5252 bytes doc/src/snippets/declarative/mousearea.qml | 13 +++-- .../cppextensions/imageprovider/imageprovider.cpp | 2 +- .../mousearea/mousearea-example.qml | 64 ++++++++++++--------- .../graphicsitems/qdeclarativeimage.cpp | 59 +++++++++---------- src/declarative/graphicsitems/qdeclarativeitem.cpp | 6 +- .../graphicsitems/qdeclarativemousearea.cpp | 10 +++- src/declarative/qml/qdeclarativeimageprovider.cpp | 16 ++++-- .../util/qdeclarativestateoperations.cpp | 2 +- src/declarative/util/qdeclarativexmllistmodel.cpp | 17 ++++-- 13 files changed, 115 insertions(+), 82 deletions(-) create mode 100644 doc/src/images/qml-xmllistmodel-example.png diff --git a/doc/src/declarative/anchor-layout.qdoc b/doc/src/declarative/anchor-layout.qdoc index 9c217e1..5c025e5 100644 --- a/doc/src/declarative/anchor-layout.qdoc +++ b/doc/src/declarative/anchor-layout.qdoc @@ -33,7 +33,10 @@ In addition to the more traditional \l Grid, \l Row, and \l Column, QML also provides a way to layout items using the concept of \e anchors. Each item can be thought of as having a set of 7 invisible "anchor lines": -\e left, \e horizontalCenter, \e right, \e top, \e verticalCenter, \e baseline, and \e bottom. +\l {Item::anchors.left}{left}, \l {Item::anchors.horizontalCenter}{horizontalCenter}, +\l {Item::anchors.right}{right}, \l {Item::anchors.top}{top}, +\l {Item::anchors.verticalCenter}{verticalCenter}, \l {Item::anchors.baseline}{baseline}, +and \l {Item::anchors.bottom}{bottom}. \image edges_qml.png diff --git a/doc/src/declarative/basictypes.qdoc b/doc/src/declarative/basictypes.qdoc index 109e6d5..e327d4a 100644 --- a/doc/src/declarative/basictypes.qdoc +++ b/doc/src/declarative/basictypes.qdoc @@ -107,6 +107,9 @@ Text { text: "Hello world!" } \endqml + Strings have a \c length attribute that holds the number of + characters in the string. + \sa {QML Basic Types} */ diff --git a/doc/src/images/qml-mousearea-example.png b/doc/src/images/qml-mousearea-example.png index c6e52d6..c0eef7f 100644 Binary files a/doc/src/images/qml-mousearea-example.png and b/doc/src/images/qml-mousearea-example.png differ diff --git a/doc/src/images/qml-xmllistmodel-example.png b/doc/src/images/qml-xmllistmodel-example.png new file mode 100644 index 0000000..be2d15d Binary files /dev/null and b/doc/src/images/qml-xmllistmodel-example.png differ diff --git a/doc/src/snippets/declarative/mousearea.qml b/doc/src/snippets/declarative/mousearea.qml index 8e7c737..fb6cba0 100644 --- a/doc/src/snippets/declarative/mousearea.qml +++ b/doc/src/snippets/declarative/mousearea.qml @@ -83,17 +83,18 @@ Rectangle { id: container width: 600; height: 200 - Image { - id: pic - source: "pics/qt.png" - opacity: (600.0 - pic.x) / 600 + Rectangle { + id: rect + width: 50; height: 50 + color: "red" + opacity: (600.0 - rect.x) / 600 MouseArea { anchors.fill: parent - drag.target: pic + drag.target: rect drag.axis: Drag.XAxis drag.minimumX: 0 - drag.maximumX: container.width - pic.width + drag.maximumX: container.width - rect.width } } } diff --git a/examples/declarative/cppextensions/imageprovider/imageprovider.cpp b/examples/declarative/cppextensions/imageprovider/imageprovider.cpp index 995192a..18d027e 100644 --- a/examples/declarative/cppextensions/imageprovider/imageprovider.cpp +++ b/examples/declarative/cppextensions/imageprovider/imageprovider.cpp @@ -54,7 +54,7 @@ class ColorImageProvider : public QDeclarativeImageProvider { public: ColorImageProvider() - : QDeclarativeImageProvider(Pixmap) + : QDeclarativeImageProvider(QDeclarativeImageProvider::Pixmap) { } diff --git a/examples/declarative/touchinteraction/mousearea/mousearea-example.qml b/examples/declarative/touchinteraction/mousearea/mousearea-example.qml index 64f72a9..85ea2dc 100644 --- a/examples/declarative/touchinteraction/mousearea/mousearea-example.qml +++ b/examples/declarative/touchinteraction/mousearea/mousearea-example.qml @@ -44,59 +44,69 @@ Rectangle { id: box width: 350; height: 250 - function showInfo(text) { - statusText.text = text - } - Rectangle { + id: redSquare width: 80; height: 80 + anchors.top: parent.top; anchors.left: parent.left; anchors.margins: 10 color: "red" Text { text: "Click"; font.pixelSize: 16; anchors.centerIn: parent } MouseArea { - anchors.fill: parent + anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton - onPressed: box.showInfo('Pressed (x=' + mouse.x + ' y=' + mouse.y + ' button=' - + (mouse.button == Qt.RightButton ? 'right' : 'left') - + ' Shift=' + (mouse.modifiers & Qt.ShiftModifier ? 'true' : 'false') + ')') - onReleased: box.showInfo('Released (x=' + mouse.x + ' y=' + mouse.y - + ' isClick=' + mouse.isClick + ' wasHeld=' + mouse.wasHeld + ')') - onClicked: box.showInfo('Clicked (x=' + mouse.x + ' y=' + mouse.y + ' wasHeld=' + mouse.wasHeld + ')') - onDoubleClicked: box.showInfo('Double clicked (x=' + mouse.x + ' y=' + mouse.y + ')') - onPressAndHold: box.showInfo('Press and hold') - onEntered: box.showInfo('Entered (pressed=' + pressed + ')') - onExited: box.showInfo('Exited (pressed=' + pressed + ')') + onEntered: info.text = 'Entered' + onExited: info.text = 'Exited (pressed=' + pressed + ')' + + onPressed: { + info.text = 'Pressed (button=' + (mouse.button == Qt.RightButton ? 'right' : 'left') + + ' shift=' + (mouse.modifiers & Qt.ShiftModifier ? 'true' : 'false') + ')' + var posInBox = redSquare.mapToItem(box, mouse.x, mouse.y) + posInfo.text = + mouse.x + ',' + mouse.y + ' in square' + + ' (' + posInBox.x + ',' + posInBox.y + ' in window)' + } + + onReleased: { + info.text = 'Released (isClick=' + mouse.isClick + ' wasHeld=' + mouse.wasHeld + ')' + posInfo.text = '' + } + + onPressAndHold: info.text = 'Press and hold' + onClicked: info.text = 'Clicked (wasHeld=' + mouse.wasHeld + ')' + onDoubleClicked: info.text = 'Double clicked' } } Rectangle { - width: 80; height: 80; anchors.right: parent.right + id: blueSquare + width: 80; height: 80 + x: box.width - width - 10; y: 10 // making this item draggable, so don't use anchors color: "blue" Text { text: "Drag"; font.pixelSize: 16; color: "white"; anchors.centerIn: parent } MouseArea { anchors.fill: parent - drag.target: parent - drag.axis: Drag.XAxis + drag.target: blueSquare + drag.axis: Drag.XandYAxis drag.minimumX: 0 - drag.maximumX: 150 - - onPressed: box.showInfo('Pressed') - onReleased: box.showInfo('Released (isClick=' + mouse.isClick + ' wasHeld=' + mouse.wasHeld + ')') - onClicked: box.showInfo('Clicked' + ' (wasHeld=' + mouse.wasHeld + ')') - onDoubleClicked: box.showInfo('Double clicked') - onPressAndHold: box.showInfo('Press and hold') + drag.maximumX: box.width - parent.width + drag.minimumY: 0 + drag.maximumY: box.height - parent.width } } Text { - id: statusText - anchors.bottom: parent.bottom; anchors.horizontalCenter: parent.horizontalCenter; anchors.margins: 30 + id: info + anchors.bottom: posInfo.top; anchors.horizontalCenter: parent.horizontalCenter; anchors.margins: 30 onTextChanged: console.log(text) } + + Text { + id: posInfo + anchors.bottom: parent.bottom; anchors.horizontalCenter: parent.horizontalCenter; anchors.margins: 30 + } } diff --git a/src/declarative/graphicsitems/qdeclarativeimage.cpp b/src/declarative/graphicsitems/qdeclarativeimage.cpp index 34d33f5..90738c8 100644 --- a/src/declarative/graphicsitems/qdeclarativeimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimage.cpp @@ -324,17 +324,34 @@ qreal QDeclarativeImage::paintedHeight() const /*! \qmlproperty QSize Image::sourceSize - This property holds the size of the loaded image, in pixels. + This property holds the actual width and height of the loaded image. - This is used to control the storage used by a loaded image. Unlike - the width and height properties, which scale the painting of the image, this property - affects the number of pixels stored. + Unlike the \l {Item::}{width} and \l {Item::}{height} properties, which scale + the painting of the image, this property sets the actual number of pixels + stored for the loaded image so that large images do not use more + memory than necessary. For example, this ensures the image is memory is no + larger than 1024x1024 pixels, regardless of the Image's \l {Item::}{width} and + \l {Item::}{height} values: + + \code + Rectangle { + width: ... + height: ... + + Image { + anchors.fill: parent + source: "reallyBigImage.jpg" + sourceSize.width: 1024 + sourceSize.height: 1024 + } + } + \endcode If the image's actual size is larger than the sourceSize, the image is scaled down. If only one dimension of the size is set to greater than 0, the other dimension is set in proportion to preserve the source image's aspect ratio. (The \l fillMode is independent of this.) - + If the source is an instrinsically scalable image (eg. SVG), this property determines the size of the loaded image regardless of intrinsic size. Avoid changing this property dynamically; rendering an SVG is \e slow compared @@ -344,34 +361,8 @@ qreal QDeclarativeImage::paintedHeight() const be no greater than this property specifies. For some formats (currently only JPEG), the whole image will never actually be loaded into memory. - \note \e{Changing this property dynamically will lead to the image source being reloaded, - potentially even from the network if it is not in the disk cache.} - - Here is an example that ensures the size of the image in memory is - no larger than 1024x1024 pixels, regardless of the size of the Image element. - - \code - Image { - anchors.fill: parent - source: "images/reallyBigImage.jpg" - sourceSize.width: 1024 - sourceSize.height: 1024 - } - \endcode - - The example below ensures the memory used by the image is no more than necessary - to display the image at the size of the Image element. - Of course if the Image element is resized a costly reload will be required, so - use this technique \e only when the Image size is fixed. - - \code - Image { - anchors.fill: parent - source: "images/reallyBigImage.jpg" - sourceSize.width: width - sourceSize.height: height - } - \endcode + \note \e {Changing this property dynamically causes the image source to be reloaded, + potentially even from the network, if it is not in the disk cache.} */ void QDeclarativeImage::updatePaintedGeometry() @@ -415,6 +406,8 @@ void QDeclarativeImage::geometryChanged(const QRectF &newGeometry, const QRectF Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt. The URL may be absolute, or relative to the URL of the component. + + \sa QDeclarativeImageProvider */ /*! diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp index 7022fac..190b22c 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp @@ -2097,7 +2097,7 @@ QDeclarativeAnchorLine QDeclarativeItemPrivate::baseline() const relationship with other items. Margins apply to top, bottom, left, right, and fill anchors. - The margins property can be used to set all of the various margins at once, to the same value. + The \c anchors.margins property can be used to set all of the various margins at once, to the same value. Offsets apply for horizontal center, vertical center, and baseline anchors. @@ -2132,10 +2132,12 @@ QDeclarativeAnchorLine QDeclarativeItemPrivate::baseline() const \endqml \endtable - anchors.fill provides a convenient way for one item to have the + \c anchors.fill provides a convenient way for one item to have the same geometry as another item, and is equivalent to connecting all four directional anchors. + To clear an anchor value, set it to \c undefined. + \note You can only anchor an item to siblings or a parent. For more information see \l {anchor-layout}{Anchor Layouts}. diff --git a/src/declarative/graphicsitems/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp index 7b65ca7..b7b0c9e 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea.cpp +++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp @@ -767,10 +767,16 @@ QDeclarativeDrag *QDeclarativeMouseArea::drag() \i \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes. \endlist - The following example displays an image that can be dragged along the X-axis. The opacity - of the image is reduced when it is dragged to the right. + The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity + of the rectangle is reduced when it is dragged to the right. \snippet doc/src/snippets/declarative/mousearea.qml drag + + \note Items cannot be dragged if they are anchored for the requested + \c drag.axis. For example, if \c anchors.left or \c anchors.right was set + for \c rect in the above example, it cannot be dragged along the X-axis. + This can be avoided by settng the anchor value to \c undefined in + an \l onPressed handler. */ QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeimageprovider.cpp b/src/declarative/qml/qdeclarativeimageprovider.cpp index f38da4e..a294c38 100644 --- a/src/declarative/qml/qdeclarativeimageprovider.cpp +++ b/src/declarative/qml/qdeclarativeimageprovider.cpp @@ -180,9 +180,13 @@ QDeclarativeImageProvider::ImageType QDeclarativeImageProvider::imageType() cons Implement this method to return the image with \a id. The default implementation returns an empty image. - If \a requestedSize is a valid size, the image returned should be of that size. + The \a requestedSize corresponds to the \l {Image::sourceSize} requested by + an Image element. If \a requestedSize is a valid size, the image + returned should be of that size. - In all cases, \a size must be set to the original size of the image. + In all cases, \a size must be set to the original size of the image. This + is used to set the \l {Item::}{width} and \l {Item::}{height} of image + elements that should be automatically sized to the loaded image. \note this method may be called by multiple threads, so ensure the implementation of this method is reentrant. @@ -201,9 +205,13 @@ QImage QDeclarativeImageProvider::requestImage(const QString &id, QSize *size, c Implement this method to return the pixmap with \a id. The default implementation returns an empty pixmap. - If \a requestedSize is a valid size, the image returned should be of that size. + The \a requestedSize corresponds to the \l {Image::sourceSize} requested by + an Image element. If \a requestedSize is a valid size, the image + returned should be of that size. - In all cases, \a size must be set to the original size of the image. + In all cases, \a size must be set to the original size of the image. This + is used to set the \l {Item::}{width} and \l {Item::}{height} of image + elements that should be automatically sized to the loaded image. \note this method may be called by multiple threads, so ensure the implementation of this method is reentrant. diff --git a/src/declarative/util/qdeclarativestateoperations.cpp b/src/declarative/util/qdeclarativestateoperations.cpp index 51e6f99..5590449 100644 --- a/src/declarative/util/qdeclarativestateoperations.cpp +++ b/src/declarative/util/qdeclarativestateoperations.cpp @@ -1039,7 +1039,7 @@ public: /*! \qmlproperty Item AnchorChanges::target - This property holds the Item whose anchors will change + This property holds the \l Item for which the anchor changes will be applied. */ QDeclarativeAnchorChanges::QDeclarativeAnchorChanges(QObject *parent) diff --git a/src/declarative/util/qdeclarativexmllistmodel.cpp b/src/declarative/util/qdeclarativexmllistmodel.cpp index 00169db..9895ff2 100644 --- a/src/declarative/util/qdeclarativexmllistmodel.cpp +++ b/src/declarative/util/qdeclarativexmllistmodel.cpp @@ -508,8 +508,8 @@ void QDeclarativeXmlListModelPrivate::clear_role(QDeclarativeListProperty - Item A + A blog post Sat, 07 Sep 2010 10:00:01 GMT - Item B + Another blog post Sat, 07 Sep 2010 15:35:01 GMT @@ -560,10 +560,17 @@ void QDeclarativeXmlListModelPrivate::clear_role(QDeclarativeListProperty Date: Wed, 14 Jul 2010 12:24:38 +1000 Subject: Split responsibilities in QDeclarativeExpression more cleanly --- src/declarative/qml/qdeclarativebinding.cpp | 139 ++++--- src/declarative/qml/qdeclarativebinding_p_p.h | 28 +- src/declarative/qml/qdeclarativecontext_p.h | 1 + src/declarative/qml/qdeclarativeengine.cpp | 2 +- src/declarative/qml/qdeclarativeengine_p.h | 1 - src/declarative/qml/qdeclarativeexpression.cpp | 478 ++++++++++++++----------- src/declarative/qml/qdeclarativeexpression_p.h | 83 +++-- 7 files changed, 401 insertions(+), 331 deletions(-) diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index 882e981..e3b33c0 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -54,27 +54,20 @@ QT_BEGIN_NAMESPACE -QDeclarativeBindingData::QDeclarativeBindingData() -: updating(false), enabled(false) +void QDeclarativeBindingPrivate::refresh() { + Q_Q(QDeclarativeBinding); + q->update(); } -QDeclarativeBindingData::~QDeclarativeBindingData() -{ - removeError(); -} - -void QDeclarativeBindingData::refresh() +QDeclarativeBindingPrivate::QDeclarativeBindingPrivate() +: updating(false), enabled(false), deleted(0) { - if (enabled && !updating && q) { - QDeclarativeBinding *b = static_cast(QDeclarativeExpressionPrivate::get(q)); - b->update(); - } } -QDeclarativeBindingPrivate::QDeclarativeBindingPrivate() -: QDeclarativeExpressionPrivate(new QDeclarativeBindingData) +QDeclarativeBindingPrivate::~QDeclarativeBindingPrivate() { + if (deleted) *deleted = true; } QDeclarativeBinding::QDeclarativeBinding(void *data, QDeclarativeRefCount *rc, QObject *obj, @@ -109,7 +102,7 @@ QDeclarativeBinding::~QDeclarativeBinding() void QDeclarativeBinding::setTarget(const QDeclarativeProperty &prop) { Q_D(QDeclarativeBinding); - d->bindingData()->property = prop; + d->property = prop; update(); } @@ -117,50 +110,53 @@ void QDeclarativeBinding::setTarget(const QDeclarativeProperty &prop) QDeclarativeProperty QDeclarativeBinding::property() const { Q_D(const QDeclarativeBinding); - return d->bindingData()->property; + return d->property; } void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) { Q_D(QDeclarativeBinding); - QDeclarativeBindingData *data = d->bindingData(); - - if (!data->enabled || !data->context() || !data->context()->isValid()) + if (!d->enabled || !d->context() || !d->context()->isValid()) return; - data->addref(); + if (!d->updating) { + d->updating = true; + bool wasDeleted = false; + d->deleted = &wasDeleted; - if (!data->updating) { - data->updating = true; + if (d->property.propertyType() == qMetaTypeId()) { - if (data->property.propertyType() == qMetaTypeId()) { - - int idx = data->property.index(); + int idx = d->property.index(); Q_ASSERT(idx != -1); - QDeclarativeBinding *t = this; int status = -1; void *a[] = { &t, 0, &status, &flags }; - QMetaObject::metacall(data->property.object(), + QMetaObject::metacall(d->property.object(), QMetaObject::WriteProperty, idx, a); + if (wasDeleted) + return; + } else { - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(data->context()->engine); + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine); bool isUndefined = false; QVariant value; QScriptValue scriptValue = d->scriptValue(0, &isUndefined); - if (data->property.propertyTypeCategory() == QDeclarativeProperty::List) { + if (wasDeleted) + return; + + if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) { value = ep->scriptValueToVariant(scriptValue, qMetaTypeId >()); } else if (scriptValue.isNull() && - data->property.propertyTypeCategory() == QDeclarativeProperty::Object) { + d->property.propertyTypeCategory() == QDeclarativeProperty::Object) { value = QVariant::fromValue((QObject *)0); } else { - value = ep->scriptValueToVariant(scriptValue, data->property.propertyType()); + value = ep->scriptValueToVariant(scriptValue, d->property.propertyType()); if (value.userType() == QMetaType::QObjectStar && !qvariant_cast(value)) { // If the object is null, we extract the predicted type. While this isn't // 100% reliable, in many cases it gives us better error messages if we @@ -172,73 +168,72 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) } - if (data->error.isValid()) { + if (d->error.isValid()) { - } else if (isUndefined && data->property.isResettable()) { + } else if (isUndefined && d->property.isResettable()) { - data->property.reset(); + d->property.reset(); - } else if (isUndefined && data->property.propertyType() == qMetaTypeId()) { + } else if (isUndefined && d->property.propertyType() == qMetaTypeId()) { - QDeclarativePropertyPrivate::write(data->property, QVariant(), flags); + QDeclarativePropertyPrivate::write(d->property, QVariant(), flags); } else if (isUndefined) { - QUrl url = QUrl(data->url); - int line = data->line; + QUrl url = QUrl(d->url); + int line = d->line; if (url.isEmpty()) url = QUrl(QLatin1String("")); - data->error.setUrl(url); - data->error.setLine(line); - data->error.setColumn(-1); - data->error.setDescription(QLatin1String("Unable to assign [undefined] to ") - + QLatin1String(QMetaType::typeName(data->property.propertyType())) - + QLatin1String(" ") + data->property.name()); + d->error.setUrl(url); + d->error.setLine(line); + d->error.setColumn(-1); + d->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + + QLatin1String(QMetaType::typeName(d->property.propertyType())) + + QLatin1String(" ") + d->property.name()); } else if (!scriptValue.isRegExp() && scriptValue.isFunction()) { - QUrl url = QUrl(data->url); - int line = data->line; + QUrl url = QUrl(d->url); + int line = d->line; if (url.isEmpty()) url = QUrl(QLatin1String("")); - data->error.setUrl(url); - data->error.setLine(line); - data->error.setColumn(-1); - data->error.setDescription(QLatin1String("Unable to assign a function to a property.")); + d->error.setUrl(url); + d->error.setLine(line); + d->error.setColumn(-1); + d->error.setDescription(QLatin1String("Unable to assign a function to a property.")); - } else if (data->property.object() && - !QDeclarativePropertyPrivate::write(data->property, value, flags)) { + } else if (d->property.object() && + !QDeclarativePropertyPrivate::write(d->property, value, flags)) { - QUrl url = QUrl(data->url); - int line = data->line; + QUrl url = QUrl(d->url); + int line = d->line; if (url.isEmpty()) url = QUrl(QLatin1String("")); const char *valueType = 0; if (value.userType() == QVariant::Invalid) valueType = "null"; else valueType = QMetaType::typeName(value.userType()); - data->error.setUrl(url); - data->error.setLine(line); - data->error.setColumn(-1); - data->error.setDescription(QLatin1String("Unable to assign ") + - QLatin1String(valueType) + - QLatin1String(" to ") + - QLatin1String(QMetaType::typeName(data->property.propertyType()))); + d->error.setUrl(url); + d->error.setLine(line); + d->error.setColumn(-1); + d->error.setDescription(QLatin1String("Unable to assign ") + + QLatin1String(valueType) + + QLatin1String(" to ") + + QLatin1String(QMetaType::typeName(d->property.propertyType()))); } - if (data->error.isValid()) { - if (!data->addError(ep)) ep->warning(this->error()); + if (d->error.isValid()) { + if (!d->addError(ep)) ep->warning(this->error()); } else { - data->removeError(); + d->removeError(); } } - data->updating = false; + d->updating = false; + d->deleted = 0; } else { - qmlInfo(data->property.object()) << tr("Binding loop detected for property \"%1\"").arg(data->property.name()); + qmlInfo(d->property.object()) << tr("Binding loop detected for property \"%1\"").arg(d->property.name()); } - - data->release(); } void QDeclarativeBindingPrivate::emitValueChanged() @@ -250,13 +245,13 @@ void QDeclarativeBindingPrivate::emitValueChanged() void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags) { Q_D(QDeclarativeBinding); - d->bindingData()->enabled = e; + d->enabled = e; setNotifyOnValueChanged(e); QDeclarativeAbstractBinding::setEnabled(e, flags); if (e) { - addToObject(d->bindingData()->property.object()); + addToObject(d->property.object()); update(flags); } else { removeFromObject(); @@ -266,14 +261,14 @@ void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteF int QDeclarativeBinding::propertyIndex() { Q_D(QDeclarativeBinding); - return QDeclarativePropertyPrivate::bindingIndex(d->bindingData()->property); + return QDeclarativePropertyPrivate::bindingIndex(d->property); } bool QDeclarativeBinding::enabled() const { Q_D(const QDeclarativeBinding); - return d->bindingData()->enabled; + return d->enabled; } QString QDeclarativeBinding::expression() const diff --git a/src/declarative/qml/qdeclarativebinding_p_p.h b/src/declarative/qml/qdeclarativebinding_p_p.h index 617ec4b..6926158 100644 --- a/src/declarative/qml/qdeclarativebinding_p_p.h +++ b/src/declarative/qml/qdeclarativebinding_p_p.h @@ -60,30 +60,24 @@ QT_BEGIN_NAMESPACE -class QDeclarativeBindingData : public QDeclarativeExpressionData -{ -public: - QDeclarativeBindingData(); - virtual ~QDeclarativeBindingData(); - - bool updating:1; - bool enabled:1; - - QDeclarativeProperty property; - - virtual void refresh(); -}; - class QDeclarativeBindingPrivate : public QDeclarativeExpressionPrivate { Q_DECLARE_PUBLIC(QDeclarativeBinding) public: QDeclarativeBindingPrivate(); - - QDeclarativeBindingData *bindingData() { return static_cast(data); } - const QDeclarativeBindingData *bindingData() const { return static_cast(data); } + ~QDeclarativeBindingPrivate(); virtual void emitValueChanged(); + +protected: + virtual void refresh(); + +private: + bool updating:1; + bool enabled:1; + QDeclarativeProperty property; + + bool *deleted; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h index 1f5aaf1..c5a039a 100644 --- a/src/declarative/qml/qdeclarativecontext_p.h +++ b/src/declarative/qml/qdeclarativecontext_p.h @@ -198,6 +198,7 @@ public: // context QDeclarativeComponentAttached *componentAttached; + // Return the outermost id for obj, if any. QString findObjectId(const QObject *obj) const; static QDeclarativeContextData *get(QDeclarativeContext *context) { diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 00bc1b7..97ef99c 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -219,7 +219,7 @@ of their use. QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e) -: captureProperties(false), rootContext(0), currentExpression(0), isDebugging(false), +: captureProperties(false), rootContext(0), isDebugging(false), outputWarningsToStdErr(true), contextClass(0), sharedContext(0), sharedScope(0), objectClass(0), valueTypeClass(0), globalClass(0), cleanup(0), erroredBindings(0), inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttached(0), diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h index f457b53..a5c8c38 100644 --- a/src/declarative/qml/qdeclarativeengine_p.h +++ b/src/declarative/qml/qdeclarativeengine_p.h @@ -162,7 +162,6 @@ public: QPODVector capturedProperties; QDeclarativeContext *rootContext; - QDeclarativeExpression *currentExpression; bool isDebugging; bool outputWarningsToStdErr; diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp index 96cdec1..9935e38 100644 --- a/src/declarative/qml/qdeclarativeexpression.cpp +++ b/src/declarative/qml/qdeclarativeexpression.cpp @@ -71,109 +71,95 @@ bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e) return true; } -QDeclarativeExpressionData::QDeclarativeExpressionData() -: q(0), dataRef(0), expressionFunctionValid(false), expressionRewritten(false), me(0), - trackChange(false), isShared(false), line(-1), guardList(0), guardListLength(0) +QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression() +: dataRef(0), expressionFunctionMode(ExplicitContext), scopeObject(0), trackChange(false), + guardList(0), guardListLength(0), guardObject(0), guardObjectNotifyIndex(-1), deleted(0) { } -QDeclarativeExpressionData::~QDeclarativeExpressionData() +QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression() { if (guardList) { delete [] guardList; guardList = 0; } if (dataRef) dataRef->release(); + if (deleted) *deleted = true; } QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate() -: data(new QDeclarativeExpressionData) +: expressionFunctionValid(true), line(-1) { - data->q = this; -} - -QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate(QDeclarativeExpressionData *d) -: data(d) -{ - data->q = this; } QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate() { - if (data) { - delete [] data->guardList; - data->guardList = 0; - data->guardListLength = 0; - data->q = 0; - data->release(); - data = 0; - } } void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, QObject *me) { - data->expression = expr; + expression = expr; - data->QDeclarativeAbstractExpression::setContext(ctxt); - data->me = me; + QDeclarativeAbstractExpression::setContext(ctxt); + scopeObject = me; + expressionFunctionValid = false; } -void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr, QDeclarativeRefCount *rc, - QObject *me, const QString &url, int lineNumber) +void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr, + QDeclarativeRefCount *rc, + QObject *me, const QString &srcUrl, int lineNumber) { - data->url = url; - data->line = lineNumber; + url = srcUrl; + line = lineNumber; - if (data->dataRef) data->dataRef->release(); - data->dataRef = rc; - if (data->dataRef) data->dataRef->addref(); + if (dataRef) dataRef->release(); + dataRef = rc; + if (dataRef) dataRef->addref(); quint32 *exprData = (quint32 *)expr; QDeclarativeCompiledData *dd = (QDeclarativeCompiledData *)rc; - data->expressionRewritten = true; - data->expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]); + expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]); int progIdx = *(exprData); - bool isShared = progIdx & 0x80000000; + bool isSharedProgram = progIdx & 0x80000000; progIdx &= 0x7FFFFFFF; QDeclarativeEngine *engine = ctxt->engine; QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); - if (isShared) { + if (isSharedProgram) { if (!dd->cachedClosures.at(progIdx)) { QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); scriptContext->pushScope(ep->contextClass->newSharedContext()); scriptContext->pushScope(ep->globalClass->staticGlobalObject()); - dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(data->expression, data->url, data->line)); + dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(expression, url, line)); scriptEngine->popContext(); } - data->expressionFunction = *dd->cachedClosures.at(progIdx); - data->isShared = true; - data->expressionFunctionValid = true; + expressionFunction = *dd->cachedClosures.at(progIdx); + expressionFunctionMode = SharedContext; + expressionFunctionValid = true; } else { #if !defined(Q_OS_SYMBIAN) //XXX Why doesn't this work? if (!dd->cachedPrograms.at(progIdx)) { - dd->cachedPrograms[progIdx] = - new QScriptProgram(data->expression, data->url, data->line); + dd->cachedPrograms[progIdx] = new QScriptProgram(expression, url, line); } - data->expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx), - &data->expressionContext); + expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx), + &expressionContext); #else - data->expressionFunction = evalInObjectScope(ctxt, me, data->expression, - &data->expressionContext); + expressionFunction = evalInObjectScope(ctxt, me, expression, &expressionContext); #endif - data->expressionFunctionValid = true; + expressionFunctionMode = ExplicitContext; + expressionFunctionValid = true; } - data->QDeclarativeAbstractExpression::setContext(ctxt); - data->me = me; + QDeclarativeAbstractExpression::setContext(ctxt); + scopeObject = me; } QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, @@ -240,6 +226,8 @@ QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContex \endcode */ +static int QDeclarativeExpression_notifyIdx = -1; + /*! Create an invalid QDeclarativeExpression. @@ -249,6 +237,11 @@ QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContex QDeclarativeExpression::QDeclarativeExpression() : QObject(*new QDeclarativeExpressionPrivate, 0) { + Q_D(QDeclarativeExpression); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); } /*! \internal */ @@ -260,6 +253,10 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, vo { Q_D(QDeclarativeExpression); d->init(ctxt, expr, rc, me, url, lineNumber); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); } /*! @@ -277,6 +274,10 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContext *ctxt, { Q_D(QDeclarativeExpression); d->init(QDeclarativeContextData::get(ctxt), expression, scope); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); } /*! @@ -288,6 +289,10 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO { Q_D(QDeclarativeExpression); d->init(ctxt, expression, scope); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); } /*! \internal */ @@ -297,6 +302,10 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO { Q_D(QDeclarativeExpression); d->init(ctxt, expression, scope); + + if (QDeclarativeExpression_notifyIdx == -1) + QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); + d->setNotifyObject(this, QDeclarativeExpression_notifyIdx); } /*! @@ -313,7 +322,7 @@ QDeclarativeExpression::~QDeclarativeExpression() QDeclarativeEngine *QDeclarativeExpression::engine() const { Q_D(const QDeclarativeExpression); - return d->data->context()?d->data->context()->engine:0; + return d->context()?d->context()->engine:0; } /*! @@ -323,7 +332,7 @@ QDeclarativeEngine *QDeclarativeExpression::engine() const QDeclarativeContext *QDeclarativeExpression::context() const { Q_D(const QDeclarativeExpression); - QDeclarativeContextData *data = d->data->context(); + QDeclarativeContextData *data = d->context(); return data?data->asQDeclarativeContext():0; } @@ -333,7 +342,7 @@ QDeclarativeContext *QDeclarativeExpression::context() const QString QDeclarativeExpression::expression() const { Q_D(const QDeclarativeExpression); - return d->data->expression; + return d->expression; } /*! @@ -343,12 +352,10 @@ void QDeclarativeExpression::setExpression(const QString &expression) { Q_D(QDeclarativeExpression); - d->clearGuards(); - - d->data->expression = expression; - d->data->expressionFunctionValid = false; - d->data->expressionRewritten = false; - d->data->expressionFunction = QScriptValue(); + d->resetNotifyOnChange(); + d->expression = expression; + d->expressionFunctionValid = false; + d->expressionFunction = QScriptValue(); } void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine, @@ -378,59 +385,108 @@ void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine } } -QScriptValue QDeclarativeExpressionPrivate::eval(QObject *secondaryScope, bool *isUndefined) +bool QDeclarativeQtScriptExpression::notifyOnValueChange() const { - QDeclarativeExpressionData *data = this->data; - QDeclarativeEngine *engine = data->context()->engine; - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + return trackChange; +} - QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); +void QDeclarativeQtScriptExpression::setNotifyOnValueChange(bool notify) +{ + trackChange = notify; + if (!notify && guardList) + clearGuards(); +} - if (!data->expressionFunctionValid) { +void QDeclarativeQtScriptExpression::resetNotifyOnChange() +{ + clearGuards(); +} - QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); - data->expressionContext = ep->contextClass->newContext(data->context(), data->me); - scriptContext->pushScope(data->expressionContext); - scriptContext->pushScope(ep->globalClass->staticGlobalObject()); +void QDeclarativeQtScriptExpression::setNotifyObject(QObject *object, int notifyIndex) +{ + if (guardList) clearGuards(); + + if (!object || notifyIndex == -1) { + guardObject = 0; + notifyIndex = -1; + } else { + guardObject = object; + guardObjectNotifyIndex = notifyIndex; + + } +} + +QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope, bool *isUndefined) +{ + Q_ASSERT(context() && context()->engine); + Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1)); + + if (!expressionFunction.isValid()) { + if (isUndefined) *isUndefined = true; + return QScriptValue(); + } + + DeleteWatcher watcher(this); + + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine); + + bool lastCaptureProperties = ep->captureProperties; + QPODVector lastCapturedProperties; + ep->captureProperties = trackChange; + ep->capturedProperties.copyAndClear(lastCapturedProperties); + + QScriptValue value = eval(secondaryScope, isUndefined); + + if (!watcher.wasDeleted() && trackChange) { + if (ep->capturedProperties.count() == 0) { + + if (guardList) clearGuards(); - if (data->expressionRewritten) { - data->expressionFunction = scriptEngine->evaluate(data->expression, - data->url, data->line); } else { - QDeclarativeRewrite::RewriteBinding rewriteBinding; - bool ok = true; - const QString code = rewriteBinding(data->expression, &ok); - if (!ok) { - scriptEngine->popContext(); - return QScriptValue(); - } - data->expressionFunction = scriptEngine->evaluate(code, data->url, data->line); - } + updateGuards(ep->capturedProperties); - scriptEngine->popContext(); - data->expressionFunctionValid = true; + } } + lastCapturedProperties.copyAndClear(ep->capturedProperties); + ep->captureProperties = lastCaptureProperties; + + return value; +} + +QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined) +{ + Q_ASSERT(context() && context()->engine); + + DeleteWatcher watcher(this); + + QDeclarativeEngine *engine = context()->engine; + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); + QDeclarativeContextData *oldSharedContext = 0; QObject *oldSharedScope = 0; QObject *oldOverride = 0; - if (data->isShared) { + bool isShared = (expressionFunctionMode == SharedContext); + + if (isShared) { oldSharedContext = ep->sharedContext; oldSharedScope = ep->sharedScope; - ep->sharedContext = data->context(); - ep->sharedScope = data->me; + ep->sharedContext = context(); + ep->sharedScope = scopeObject; } else { - oldOverride = ep->contextClass->setOverrideObject(data->expressionContext, secondaryScope); + oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope); } - QScriptValue svalue = data->expressionFunction.call(); + QScriptValue svalue = expressionFunction.call(); // This could cause this to be deleted - if (data->isShared) { + if (isShared) { ep->sharedContext = oldSharedContext; ep->sharedScope = oldSharedScope; - } else { - ep->contextClass->setOverrideObject(data->expressionContext, oldOverride); + } else if (!watcher.wasDeleted()) { + ep->contextClass->setOverrideObject(expressionContext, oldOverride); } if (isUndefined) @@ -438,63 +494,134 @@ QScriptValue QDeclarativeExpressionPrivate::eval(QObject *secondaryScope, bool * // Handle exception if (scriptEngine->hasUncaughtException()) { - exceptionToError(scriptEngine, data->error); + if (!watcher.wasDeleted()) + QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error); + scriptEngine->clearExceptions(); return QScriptValue(); } else { - data->error = QDeclarativeError(); + if (!watcher.wasDeleted()) + error = QDeclarativeError(); + return svalue; } } -QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined) +void QDeclarativeQtScriptExpression::updateGuards(const QPODVector &properties) { - Q_Q(QDeclarativeExpression); - Q_ASSERT(q->engine()); + Q_ASSERT(guardObject); + Q_ASSERT(guardObjectNotifyIndex != -1); - if (data->expression.isEmpty()) - return QScriptValue(); + if (properties.count() != guardListLength) { + QDeclarativeNotifierEndpoint *newGuardList = new QDeclarativeNotifierEndpoint[properties.count()]; - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine()); + for (int ii = 0; ii < qMin(guardListLength, properties.count()); ++ii) + guardList[ii].copyAndClear(newGuardList[ii]); - QDeclarativeExpression *lastCurrentExpression = ep->currentExpression; - bool lastCaptureProperties = ep->captureProperties; - QPODVector lastCapturedProperties; - ep->capturedProperties.copyAndClear(lastCapturedProperties); + delete [] guardList; + guardList = newGuardList; + guardListLength = properties.count(); + } - ep->currentExpression = q; - ep->captureProperties = data->trackChange; + bool outputWarningHeader = false; + bool noChanges = true; + for (int ii = 0; ii < properties.count(); ++ii) { + QDeclarativeNotifierEndpoint &guard = guardList[ii]; + const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii); - // This object might be deleted during the eval - QDeclarativeExpressionData *localData = data; - localData->addref(); + guard.target = guardObject; + guard.targetMethod = guardObjectNotifyIndex; - QScriptValue value = eval(secondaryScope, isUndefined); + if (property.notifier != 0) { - ep->currentExpression = lastCurrentExpression; - ep->captureProperties = lastCaptureProperties; + if (!noChanges && guard.isConnected(property.notifier)) { + // Nothing to do - // Check if we were deleted - if (localData->q) { - if ((!data->trackChange || !ep->capturedProperties.count()) && data->guardList) { - clearGuards(); - } else if(data->trackChange) { - updateGuards(ep->capturedProperties); + } else { + noChanges = false; + + bool existing = false; + for (int jj = 0; !existing && jj < ii; ++jj) + if (guardList[jj].isConnected(property.notifier)) + existing = true; + + if (existing) { + // duplicate + guard.disconnect(); + } else { + guard.connect(property.notifier); + } + } + + + } else if (property.notifyIndex != -1) { + + if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) { + // Nothing to do + + } else { + noChanges = false; + + bool existing = false; + for (int jj = 0; !existing && jj < ii; ++jj) + if (guardList[jj].isConnected(property.object, property.notifyIndex)) + existing = true; + + if (existing) { + // duplicate + guard.disconnect(); + } else { + guard.connect(property.object, property.notifyIndex); + } + } + + } else { + if (!outputWarningHeader) { + outputWarningHeader = true; + qWarning() << "QDeclarativeExpression: Expression" << expression + << "depends on non-NOTIFYable properties:"; + } + + const QMetaObject *metaObj = property.object->metaObject(); + QMetaProperty metaProp = metaObj->property(property.coreIndex); + + qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name(); } } +} - localData->release(); +QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined) +{ + if (!expressionFunctionValid) { + QDeclarativeEngine *engine = context()->engine; + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); - lastCapturedProperties.copyAndClear(ep->capturedProperties); + QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); - return value; + QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine); + expressionContext = ep->contextClass->newContext(context(), scopeObject); + scriptContext->pushScope(expressionContext); + scriptContext->pushScope(ep->globalClass->staticGlobalObject()); + + QDeclarativeRewrite::RewriteBinding rewriteBinding; + bool ok = true; + const QString code = rewriteBinding(expression, &ok); + if (ok) + expressionFunction = scriptEngine->evaluate(code, url, line); + + scriptEngine->popContext(); + expressionFunctionMode = ExplicitContext; + expressionFunctionValid = true; + } + + return QDeclarativeQtScriptExpression::scriptValue(secondaryScope, isUndefined); } QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) { Q_Q(QDeclarativeExpression); - if (!data || !data->context() || !data->context()->isValid()) { + if (!context() || !context()->isValid()) { qWarning("QDeclarativeExpression: Attempted to evaluate an expression in an invalid context"); return QVariant(); } @@ -526,7 +653,7 @@ value changes. bool QDeclarativeExpression::notifyOnValueChanged() const { Q_D(const QDeclarativeExpression); - return d->data->trackChange; + return d->notifyOnValueChange(); } /*! @@ -548,7 +675,7 @@ bool QDeclarativeExpression::notifyOnValueChanged() const void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange) { Q_D(QDeclarativeExpression); - d->data->trackChange = notifyOnChange; + d->setNotifyOnValueChange(notifyOnChange); } /*! @@ -558,7 +685,7 @@ void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange) QString QDeclarativeExpression::sourceFile() const { Q_D(const QDeclarativeExpression); - return d->data->url; + return d->url; } /*! @@ -568,7 +695,7 @@ QString QDeclarativeExpression::sourceFile() const int QDeclarativeExpression::lineNumber() const { Q_D(const QDeclarativeExpression); - return d->data->line; + return d->line; } /*! @@ -578,8 +705,8 @@ int QDeclarativeExpression::lineNumber() const void QDeclarativeExpression::setSourceLocation(const QString &url, int line) { Q_D(QDeclarativeExpression); - d->data->url = url; - d->data->line = line; + d->url = url; + d->line = line; } /*! @@ -591,7 +718,7 @@ void QDeclarativeExpression::setSourceLocation(const QString &url, int line) QObject *QDeclarativeExpression::scopeObject() const { Q_D(const QDeclarativeExpression); - return d->data->me; + return d->scopeObject; } /*! @@ -603,7 +730,7 @@ QObject *QDeclarativeExpression::scopeObject() const bool QDeclarativeExpression::hasError() const { Q_D(const QDeclarativeExpression); - return d->data->error.isValid(); + return d->error.isValid(); } /*! @@ -615,7 +742,7 @@ bool QDeclarativeExpression::hasError() const void QDeclarativeExpression::clearError() { Q_D(QDeclarativeExpression); - d->data->error = QDeclarativeError(); + d->error = QDeclarativeError(); } /*! @@ -628,7 +755,7 @@ void QDeclarativeExpression::clearError() QDeclarativeError QDeclarativeExpression::error() const { Q_D(const QDeclarativeExpression); - return d->data->error; + return d->error; } /*! \internal */ @@ -637,98 +764,11 @@ void QDeclarativeExpressionPrivate::_q_notify() emitValueChanged(); } -void QDeclarativeExpressionPrivate::clearGuards() -{ - delete [] data->guardList; - data->guardList = 0; - data->guardListLength = 0; -} - -void QDeclarativeExpressionPrivate::updateGuards(const QPODVector &properties) +void QDeclarativeQtScriptExpression::clearGuards() { - Q_Q(QDeclarativeExpression); - - static int notifyIdx = -1; - if (notifyIdx == -1) - notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()"); - - if (properties.count() != data->guardListLength) { - QDeclarativeNotifierEndpoint *newGuardList = - new QDeclarativeNotifierEndpoint[properties.count()]; - - for (int ii = 0; ii < qMin(data->guardListLength, properties.count()); ++ii) - data->guardList[ii].copyAndClear(newGuardList[ii]); - - delete [] data->guardList; - data->guardList = newGuardList; - data->guardListLength = properties.count(); - } - - bool outputWarningHeader = false; - bool noChanges = true; - for (int ii = 0; ii < properties.count(); ++ii) { - QDeclarativeNotifierEndpoint &guard = data->guardList[ii]; - const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii); - - guard.target = q; - guard.targetMethod = notifyIdx; - - if (property.notifier != 0) { - - if (!noChanges && guard.isConnected(property.notifier)) { - // Nothing to do - - } else { - noChanges = false; - - bool existing = false; - for (int jj = 0; !existing && jj < ii; ++jj) - if (data->guardList[jj].isConnected(property.notifier)) - existing = true; - - if (existing) { - // duplicate - guard.disconnect(); - } else { - guard.connect(property.notifier); - } - } - - - } else if (property.notifyIndex != -1) { - - if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) { - // Nothing to do - - } else { - noChanges = false; - - bool existing = false; - for (int jj = 0; !existing && jj < ii; ++jj) - if (data->guardList[jj].isConnected(property.object, property.notifyIndex)) - existing = true; - - if (existing) { - // duplicate - guard.disconnect(); - } else { - guard.connect(property.object, property.notifyIndex); - } - } - - } else { - if (!outputWarningHeader) { - outputWarningHeader = true; - qWarning() << "QDeclarativeExpression: Expression" << q->expression() - << "depends on non-NOTIFYable properties:"; - } - - const QMetaObject *metaObj = property.object->metaObject(); - QMetaProperty metaProp = metaObj->property(property.coreIndex); - - qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name(); - } - } + delete [] guardList; + guardList = 0; + guardListLength = 0; } /*! diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h index 4ff3162..b629e20 100644 --- a/src/declarative/qml/qdeclarativeexpression_p.h +++ b/src/declarative/qml/qdeclarativeexpression_p.h @@ -107,56 +107,73 @@ private: QDeclarativeDelayedError **prevError; }; -class QDeclarativeExpressionData : public QDeclarativeAbstractExpression, public QDeclarativeDelayedError, public QDeclarativeRefCount +class QDeclarativeQtScriptExpression : public QDeclarativeAbstractExpression, + public QDeclarativeDelayedError { public: - QDeclarativeExpressionData(); - virtual ~QDeclarativeExpressionData(); + enum Mode { SharedContext, ExplicitContext }; - QDeclarativeExpressionPrivate *q; + QDeclarativeQtScriptExpression(); + virtual ~QDeclarativeQtScriptExpression(); QDeclarativeRefCount *dataRef; + QString expression; - bool expressionFunctionValid:1; - bool expressionRewritten:1; + + Mode expressionFunctionMode; QScriptValue expressionFunction; - QScriptValue expressionContext; - QObject *me; - bool trackChange; + QScriptValue expressionContext; // Only used in ExplicitContext + QObject *scopeObject; // Only used in SharedContext - bool isShared; + bool notifyOnValueChange() const; + void setNotifyOnValueChange(bool); + void resetNotifyOnChange(); + void setNotifyObject(QObject *, int ); - QString url; // This is a QString for a reason. QUrls are slooooooow... - int line; + QScriptValue scriptValue(QObject *secondaryScope, bool *isUndefined); + + class DeleteWatcher { + public: + inline DeleteWatcher(QDeclarativeQtScriptExpression *data); + inline ~DeleteWatcher(); + inline bool wasDeleted() const; + private: + bool *m_wasDeleted; + bool m_wasDeletedStorage; + QDeclarativeQtScriptExpression *m_d; + }; + +private: + void clearGuards(); + QScriptValue eval(QObject *secondaryScope, bool *isUndefined); + void updateGuards(const QPODVector &properties); + + bool trackChange; QDeclarativeNotifierEndpoint *guardList; int guardListLength; + + QObject *guardObject; + int guardObjectNotifyIndex; + bool *deleted; }; class QDeclarativeExpression; class QString; -class QDeclarativeExpressionPrivate : public QObjectPrivate +class QDeclarativeExpressionPrivate : public QObjectPrivate, public QDeclarativeQtScriptExpression { Q_DECLARE_PUBLIC(QDeclarativeExpression) public: QDeclarativeExpressionPrivate(); - QDeclarativeExpressionPrivate(QDeclarativeExpressionData *); ~QDeclarativeExpressionPrivate(); void init(QDeclarativeContextData *, const QString &, QObject *); void init(QDeclarativeContextData *, void *, QDeclarativeRefCount *, QObject *, const QString &, int); - QDeclarativeExpressionData *data; - QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0); QScriptValue scriptValue(QObject *secondaryScope = 0, bool *isUndefined = 0); - QScriptValue eval(QObject *secondaryScope, bool *isUndefined = 0); - - void updateGuards(const QPODVector &properties); - void clearGuards(); - static QDeclarativeExpressionPrivate *get(QDeclarativeExpression *expr) { return static_cast(QObjectPrivate::get(expr)); } @@ -172,8 +189,32 @@ public: int, QScriptValue *); static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QScriptProgram &, QScriptValue *); + + bool expressionFunctionValid:1; + + QString url; // This is a QString for a reason. QUrls are slooooooow... + int line; }; +QDeclarativeQtScriptExpression::DeleteWatcher::DeleteWatcher(QDeclarativeQtScriptExpression *data) +: m_wasDeletedStorage(false), m_d(data) +{ + if (!m_d->deleted) + m_d->deleted = &m_wasDeletedStorage; + m_wasDeleted = m_d->deleted; +} + +QDeclarativeQtScriptExpression::DeleteWatcher::~DeleteWatcher() +{ + if (false == *m_wasDeleted && m_wasDeleted == m_d->deleted) + m_d->deleted = 0; +} + +bool QDeclarativeQtScriptExpression::DeleteWatcher::wasDeleted() const +{ + return *m_wasDeleted; +} + QT_END_NAMESPACE #endif // QDECLARATIVEEXPRESSION_P_H -- cgit v0.12 From 05971cf88bf03f2cbf563cb194ebee62bb907394 Mon Sep 17 00:00:00 2001 From: Aaron McCarthy Date: Wed, 14 Jul 2010 13:51:17 +1000 Subject: Attempt to fix build failure with msvc200{5,8} on Windows XP. --- tests/auto/qfileinfo/tst_qfileinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qfileinfo/tst_qfileinfo.cpp b/tests/auto/qfileinfo/tst_qfileinfo.cpp index 4c651bf..93b1891 100644 --- a/tests/auto/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/qfileinfo/tst_qfileinfo.cpp @@ -1082,7 +1082,7 @@ void tst_QFileInfo::isHidden_data() #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) QVERIFY(QDir("./hidden-directory").exists() || QDir().mkdir("./hidden-directory")); - QVERIFY(SetFileAttributesW(QString("./hidden-directory").utf16(),FILE_ATTRIBUTE_HIDDEN)); + QVERIFY(SetFileAttributesW(reinterpret_cast(QString("./hidden-directory").utf16()),FILE_ATTRIBUTE_HIDDEN)); QTest::newRow("C:/path/to/hidden-directory") << QDir::currentPath() + QString::fromLatin1("/hidden-directory") << true; QTest::newRow("C:/path/to/hidden-directory/.") << QDir::currentPath() + QString::fromLatin1("/hidden-directory/.") << true; #endif -- cgit v0.12 From b2002d0814e18f7a50bdbf8d17c4bc1662fa70ee Mon Sep 17 00:00:00 2001 From: Aaron McCarthy Date: Wed, 14 Jul 2010 13:52:48 +1000 Subject: Revert "Fix an Assert in QTextTable" This reverts commit b2a4c7f0142a48f60e7ec4fc5866917e3da8b7c3. Unit test tst_qtexttable::QTBUG11282_insertBeforeMergedEnding fails on mac and Linux, reverting for now. --- src/gui/text/qtexttable.cpp | 28 +++-------------- tests/auto/qtexttable/tst_qtexttable.cpp | 54 -------------------------------- 2 files changed, 4 insertions(+), 78 deletions(-) diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp index e3985ce..5100176 100644 --- a/src/gui/text/qtexttable.cpp +++ b/src/gui/text/qtexttable.cpp @@ -754,39 +754,19 @@ void QTextTable::insertColumns(int pos, int num) QTextFormatCollection *c = p->formatCollection(); p->beginEditBlock(); - QList extendedSpans; for (int i = 0; i < d->nRows; ++i) { int cell; if (i == d->nRows - 1 && pos == d->nCols) cell = d->fragment_end; else cell = d->grid[i*d->nCols + pos]; + QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell); + QTextCharFormat fmt = c->charFormat(it->format); if (pos > 0 && pos < d->nCols && cell == d->grid[i*d->nCols + pos - 1]) { // cell spans the insertion place, extend it - if (!extendedSpans.contains(cell)) { - QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell); - QTextCharFormat fmt = c->charFormat(it->format); - fmt.setTableCellColumnSpan(fmt.tableCellColumnSpan() + num); - p->setCharFormat(it.position(), 1, fmt); - d->dirty = true; - extendedSpans << cell; - } + fmt.setTableCellColumnSpan(fmt.tableCellColumnSpan() + num); + p->setCharFormat(it.position(), 1, fmt); } else { - /* If the next cell is spanned from the row above, we need to find the right position - to insert to */ - if (i > 0 && pos < d->nCols && cell == d->grid[(i-1) * d->nCols + pos]) { - int gridIndex = i*d->nCols + pos; - const int gridEnd = d->nRows * d->nCols - 1; - while (gridIndex < gridEnd && cell == d->grid[gridIndex]) { - ++gridIndex; - } - if (gridIndex == gridEnd) - cell = d->fragment_end; - else - cell = d->grid[gridIndex]; - } - QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell); - QTextCharFormat fmt = c->charFormat(it->format); fmt.setTableCellRowSpan(1); fmt.setTableCellColumnSpan(1); Q_ASSERT(fmt.objectIndex() == objectIndex()); diff --git a/tests/auto/qtexttable/tst_qtexttable.cpp b/tests/auto/qtexttable/tst_qtexttable.cpp index b0cb34d..2e6007e 100644 --- a/tests/auto/qtexttable/tst_qtexttable.cpp +++ b/tests/auto/qtexttable/tst_qtexttable.cpp @@ -48,14 +48,9 @@ #include #include #include -#include -#include //TESTED_FILES= -typedef QList IntList; -Q_DECLARE_METATYPE(IntList) - QT_FORWARD_DECLARE_CLASS(QTextDocument) class tst_QTextTable : public QObject @@ -83,7 +78,6 @@ private slots: void insertRows(); void deleteInTable(); void mergeCells(); - void mergeAndInsert(); void splitCells(); void blocksForTableShouldHaveEmptyFormat(); void removeTableByRemoveRows(); @@ -99,8 +93,6 @@ private slots: void removeColumns3(); void removeColumns4(); void removeColumns5(); - void QTBUG11282_insertBeforeMergedEnding_data(); - void QTBUG11282_insertBeforeMergedEnding(); private: QTextTable *create2x2Table(); @@ -594,16 +586,6 @@ void tst_QTextTable::mergeCells() QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1)); } -void tst_QTextTable::mergeAndInsert() -{ - QTextTable *table = cursor.insertTable(4,3); - table->mergeCells(0,1,3,2); - table->mergeCells(3,0,1,3); - //Don't crash ! - table->insertColumns(1,2); - QCOMPARE(table->columns(), 5); -} - void tst_QTextTable::splitCells() { QTextTable *table = create4x4Table(); @@ -949,41 +931,5 @@ void tst_QTextTable::removeColumns5() QCOMPARE(table->cellAt(3, 2).firstPosition(), 11); } -void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding_data() -{ - QTest::addColumn("rows"); - QTest::addColumn("columns"); - QTest::addColumn >("merge"); - QTest::addColumn >("insert"); - - QTest::newRow("2x3, merge two, insert one") << 2 << 3 << (QList() << 1 << 2 << 2) - << (QList() << 1 << 1) ; - QTest::newRow("3x4, merge three, insert one") << 3 << 4 << (QList() << 1 << 3 << 3) - << (QList() << 1 << 1) ; - QTest::newRow("4x3, merge two, insert two") << 4 << 3 << (QList() << 1 << 4 << 2) - << (QList() << 1 << 2) ; - QTest::newRow("4x4, merge middle two, insert one") << 4 << 4 << (QList() << 1 << 4 << 2) - << (QList() << 1 << 1) ; -} - -void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding() -{ - QFETCH(int, rows); - QFETCH(int, columns); - QFETCH(QList, merge); - QFETCH(QList, insert); - QTextTable *table = cursor.insertTable(rows, columns); - QTextEdit *textEdit = new QTextEdit; - textEdit->setDocument(doc); - textEdit->show(); - QTest::qWaitForWindowShown(textEdit); - table->mergeCells(0,merge.at(0), merge.at(1), merge.at(2)); - //Don't crash ! - table->insertColumns(insert.at(0), insert.at(1)); - //Check that the final size is what we expected - QCOMPARE(table->rows(), rows); - QCOMPARE(table->columns(), columns + insert.at(1)); -} - QTEST_MAIN(tst_QTextTable) #include "tst_qtexttable.moc" -- cgit v0.12 From d7a1e01e9970bef56f647873bb2a3496893b775a Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 14 Jul 2010 15:02:33 +1000 Subject: Distinguish Qt Quick, Qt Declarative and QML on the landing page Task-number: QTBUG-11916 --- doc/src/declarative/declarativeui.qdoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/src/declarative/declarativeui.qdoc b/doc/src/declarative/declarativeui.qdoc index cd27c40..217e372 100644 --- a/doc/src/declarative/declarativeui.qdoc +++ b/doc/src/declarative/declarativeui.qdoc @@ -37,7 +37,9 @@ custom user interfaces from a rich set of \l {QML Elements}{QML elements}. Qt Quick helps programmers and designers collaborate to build the fluid user interfaces that are becoming common in portable consumer devices, such as mobile phones, media players, set-top boxes -and netbooks. +and netbooks. Qt Quick consists of the QtDeclarative C++ module, QML, and +the integration of both of these into the Qt Creator IDE. Using the QtDeclarative +C++ module, you can load and interact with QML files from your Qt application. QML is an extension to \l {http://www.ecma-international.org/publications/standards/Ecma-262.htm} @@ -58,7 +60,7 @@ complete internet-enabled applications like a \l Qt Quick builds on \l {QML for Qt programmers}{Qt's existing strengths}. QML can be be used to incrementally extend an existing application or to build completely new applications. QML is fully \l -{Extending QML in C++}{extensible from C++}. +{Extending QML in C++}{extensible from C++} through the QtDeclarative Module. \section1 Getting Started -- cgit v0.12 From 2ba0dfd82a3d82e98a70aeda3b142e0a870eeb0d Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 14 Jul 2010 15:03:35 +1000 Subject: Finish QML for Qt Programmers section I don't think I kept the same style as the rest of the section, so this may need to be refactored a little. But it's not incomplete anymore, content-wise. Task-number: QTBUG-11918 --- doc/src/declarative/qtprogrammers.qdoc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/src/declarative/qtprogrammers.qdoc b/doc/src/declarative/qtprogrammers.qdoc index ae54d58..68d56bf 100644 --- a/doc/src/declarative/qtprogrammers.qdoc +++ b/doc/src/declarative/qtprogrammers.qdoc @@ -27,8 +27,6 @@ /*! - INCOMPLETE - \page qtprogrammers.html \target qtprogrammers \title QML for Qt programmers @@ -146,4 +144,14 @@ transition from an arbitrary Text item, or characters within a Text item, so you item would need to be sufficiently flexible to allow such animation. \section1 QML Items Compared With QGraphicsWidgets + +The main difference between QML items and QGraphicsWidgets is how they are intended to be used. The technical implementation details are much the same, but in practice they are different because QML items are made for declarative and compositional use, and QGraphicsWidgets are made for imperative and more integrated use. Both QML items and QGraphicsWidgets inherit from QGraphicsObject, and can co-exist. The differences are in the layouting system and the interfacing with other components. Note that, as QGraphicsWidgets tend more to be all-in-one packages, the equivalent of a QGraphicsWidget may be many QML items composed across several QML files, but it can still be loaded and used as a single QGraphicsObject from C++. + +QGraphicsWidgets are usually designed to be laid out with QGraphicsLayouts. QML does not use QGraphicsLayouts, as the Qt layouts do not mix well with animated and fluid UIs, so the geometry interface is one of the main differences. When writing QML elements, you allow the designers to place their bounding rectangle using absolute geometry, bindings or anchors (all setup for you when you inherit QDeclarativeItem) and you do not use layouts or size hints. If size hints are appropriate, then place them in the QML documentation so that the designers know how to use the item best, but still have complete control over the look and feel. + +The other main difference is that QGraphicsWidgets tend to follow the widget model, in that they are a self-contained bundle of UI and logic. In contrast, QML primitives are usually a single purpose item that does not fulfill a use case on its own, but is composed into the equivalent of the widget inside the QML file. So when writing QML Items, try to avoid doing UI logic or composing visual elements inside the items. Try instead to write more general purpose primitives, so that the look and feel (which involves the UI logic) can be written in QML. + +Both differences are caused by the different method of interaction. QGraphicsWidget is a QGraphicsObject subclass which makes fluid UI development from C++ easier, and QDeclarativeItem is a QGraphicsObject subclass which makes fluid UI development from QML easier. The difference therefore is primarily one of the interface exposed, and the design of the items that come with it (the Declarative primitives for QML and the nothing for QGraphicsWidget, because you need to write your own UI logic into the subclass). + +If you wish to use both QML and C++ to write the UI, for example to ease the transition period, it is recommended to use QDeclarativeItem subclasses (although you can use QGraphicsWidgets as well). To allow for easier use from C++ make the root item of each C++ component a LayoutItem, and load individual 'widgets' of QML (possibly comprised of multiple files, and containing a self-contained bundle of UI and logic) into your scene to replace individual QGraphicsWidgets one at a time. */ -- cgit v0.12 From 2d4876330e292253a9133b0197e573097ecfa5bb Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 14 Jul 2010 15:05:02 +1000 Subject: Clean up particle motion documentation Task-number: QTBUG-11917 --- src/imports/particles/qdeclarativeparticles.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/imports/particles/qdeclarativeparticles.cpp b/src/imports/particles/qdeclarativeparticles.cpp index e95dfc7..8fe8a9f 100644 --- a/src/imports/particles/qdeclarativeparticles.cpp +++ b/src/imports/particles/qdeclarativeparticles.cpp @@ -158,6 +158,11 @@ void QDeclarativeParticleMotion::destroy(QDeclarativeParticle &particle) \brief The ParticleMotionLinear object moves particles linearly. \sa Particles + + This is the default motion, and moves the particles according to the + properties specified in the Particles element. + + It has no further properties. */ /*! @@ -178,6 +183,13 @@ void QDeclarativeParticleMotionLinear::advance(QDeclarativeParticle &p, int inte \since 4.7 \brief The ParticleMotionGravity object moves particles towards a point. + This motion attracts the particles to the specified point with the specified acceleration. + To mimic earth gravity, set yattractor to -6360000 and acceleration to 9.8. + + The defaults are all 0, not earth gravity, and so no motion will occur without setting + at least the acceleration property. + + \sa Particles */ @@ -186,6 +198,7 @@ void QDeclarativeParticleMotionLinear::advance(QDeclarativeParticle &p, int inte \class QDeclarativeParticleMotionGravity \ingroup group_effects \brief The QDeclarativeParticleMotionGravity class moves the particles towards a point. + */ /*! @@ -305,14 +318,14 @@ Rectangle { */ /*! - \qmlproperty real QDeclarativeParticleMotionWander::xvariance - \qmlproperty real QDeclarativeParticleMotionWander::yvariance + \qmlproperty real ParticleMotionWander::xvariance + \qmlproperty real ParticleMotionWander::yvariance These properties set the amount to wander in the x and y directions. */ /*! - \qmlproperty real QDeclarativeParticleMotionWander::pace + \qmlproperty real ParticleMotionWander::pace This property holds how quickly the paricles will move from side to side. */ -- cgit v0.12 From 9adc85fdfa0af2b6948408932188ee1b79247fa6 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 14 Jul 2010 15:32:32 +1000 Subject: Position GridView and ListView footer correctly when model cleared. Task-number: QTBUG-12167 --- .../graphicsitems/qdeclarativegridview.cpp | 5 ++- .../graphicsitems/qdeclarativelistview.cpp | 7 ++-- .../qdeclarativegridview/data/footer.qml | 32 +++++++++++++++++ .../tst_qdeclarativegridview.cpp | 41 ++++++++++++++++++++++ .../qdeclarativelistview/data/footer.qml | 30 ++++++++++++++++ .../tst_qdeclarativelistview.cpp | 32 +++++++++++++++++ 6 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativegridview/data/footer.qml create mode 100644 tests/auto/declarative/qdeclarativelistview/data/footer.qml diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index dce6f0e..14a4f08 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -2438,8 +2438,11 @@ void QDeclarativeGridView::itemsRemoved(int modelIndex, int count) if (removedVisible && d->visibleItems.isEmpty()) { d->timeline.clear(); d->setPosition(0); - if (d->itemCount == 0) + if (d->itemCount == 0) { + d->updateHeader(); + d->updateFooter(); update(); + } } emit countChanged(); diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index cd26472..110c970 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -1077,7 +1077,7 @@ void QDeclarativeListViewPrivate::updateFooter() } if (footer) { if (visibleItems.count()) { - qreal endPos = endPosition(); + qreal endPos = endPosition() + 1; if (lastVisibleIndex() == model->count()-1) { footer->setPosition(endPos); } else { @@ -2893,8 +2893,11 @@ void QDeclarativeListView::itemsRemoved(int modelIndex, int count) d->visiblePos = d->header ? d->header->size() : 0; d->timeline.clear(); d->setPosition(0); - if (d->itemCount == 0) + if (d->itemCount == 0) { + d->updateHeader(); + d->updateFooter(); update(); + } } emit countChanged(); diff --git a/tests/auto/declarative/qdeclarativegridview/data/footer.qml b/tests/auto/declarative/qdeclarativegridview/data/footer.qml new file mode 100644 index 0000000..170b2b5 --- /dev/null +++ b/tests/auto/declarative/qdeclarativegridview/data/footer.qml @@ -0,0 +1,32 @@ +import Qt 4.7 + +Rectangle { + width: 240 + height: 320 + color: "#ffffff" + Component { + id: myDelegate + Rectangle { + id: wrapper + objectName: "wrapper" + width: 80 + height: 60 + border.color: "blue" + Text { + text: index + } + color: GridView.isCurrentItem ? "lightsteelblue" : "white" + } + } + GridView { + id: grid + objectName: "grid" + width: 240 + height: 320 + cellWidth: 80 + cellHeight: 60 + model: testModel + delegate: myDelegate + footer: Text { objectName: "footer"; text: "Footer"; height: 30 } + } +} diff --git a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp index a67c56f..1a28b71 100644 --- a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp +++ b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp @@ -81,6 +81,7 @@ private slots: void enforceRange(); void QTBUG_8456(); void manualHighlight(); + void footer(); private: QDeclarativeView *createView(); @@ -147,6 +148,14 @@ public: emit dataChanged(index(idx,0), index(idx,0)); } + void clear() { + int count = list.count(); + emit beginRemoveRows(QModelIndex(), 0, count-1); + list.clear(); + emit endRemoveRows(); + } + + private: QList > list; }; @@ -1162,6 +1171,38 @@ void tst_QDeclarativeGridView::manualHighlight() QTRY_COMPARE(gridview->highlightItem()->x(), gridview->currentItem()->x()); } +void tst_QDeclarativeGridView::footer() +{ + QDeclarativeView *canvas = createView(); + + TestModel model; + for (int i = 0; i < 7; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/footer.qml")); + qApp->processEvents(); + + QDeclarativeGridView *gridview = findItem(canvas->rootObject(), "grid"); + QTRY_VERIFY(gridview != 0); + + QDeclarativeItem *contentItem = gridview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QDeclarativeText *footer = findItem(contentItem, "footer"); + QVERIFY(footer); + + QCOMPARE(footer->y(), 180.0); + + model.removeItem(2); + QTRY_COMPARE(footer->y(), 120.0); + + model.clear(); + QTRY_COMPARE(footer->y(), 0.0); +} + QDeclarativeView *tst_QDeclarativeGridView::createView() { diff --git a/tests/auto/declarative/qdeclarativelistview/data/footer.qml b/tests/auto/declarative/qdeclarativelistview/data/footer.qml new file mode 100644 index 0000000..11cbe16 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistview/data/footer.qml @@ -0,0 +1,30 @@ +import Qt 4.7 + +Rectangle { + width: 240 + height: 320 + color: "#ffffff" + Component { + id: myDelegate + Rectangle { + id: wrapper + objectName: "wrapper" + height: 20 + width: 240 + Text { + text: index + } + color: ListView.isCurrentItem ? "lightsteelblue" : "white" + } + } + ListView { + id: list + objectName: "list" + focus: true + width: 240 + height: 320 + model: testModel + delegate: myDelegate + footer: Text { objectName: "footer"; text: "Footer"; height: 30 } + } +} diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp index e13bd94..9c24e03 100644 --- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp +++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp @@ -97,6 +97,7 @@ private slots: void QTBUG_9791(); void manualHighlight(); void QTBUG_11105(); + void footer(); private: template void items(); @@ -1558,6 +1559,37 @@ void tst_QDeclarativeListView::QTBUG_11105() delete canvas; } +void tst_QDeclarativeListView::footer() +{ + QDeclarativeView *canvas = createView(); + + TestModel model; + for (int i = 0; i < 3; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/footer.qml")); + qApp->processEvents(); + + QDeclarativeListView *listview = findItem(canvas->rootObject(), "list"); + QTRY_VERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QDeclarativeText *footer = findItem(contentItem, "footer"); + QVERIFY(footer); + QCOMPARE(footer->y(), 60.0); + + model.removeItem(1); + QTRY_COMPARE(footer->y(), 40.0); + + model.clear(); + QTRY_COMPARE(footer->y(), 0.0); +} + void tst_QDeclarativeListView::qListModelInterface_items() { items(); -- cgit v0.12 From bf40668cf05e6bb09ee0c7eca26c59f84fa14437 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 14 Jul 2010 16:23:10 +1000 Subject: Check for binding having been deleted in more places --- src/declarative/qml/qdeclarativebinding.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index e3b33c0..e096305 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -205,6 +205,9 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) } else if (d->property.object() && !QDeclarativePropertyPrivate::write(d->property, value, flags)) { + if (wasDeleted) + return; + QUrl url = QUrl(d->url); int line = d->line; if (url.isEmpty()) url = QUrl(QLatin1String("")); @@ -222,6 +225,9 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) QLatin1String(QMetaType::typeName(d->property.propertyType()))); } + if (wasDeleted) + return; + if (d->error.isValid()) { if (!d->addError(ep)) ep->warning(this->error()); } else { -- cgit v0.12 From d3a6f124dde7732311ad9312ebf41997712fc6bb Mon Sep 17 00:00:00 2001 From: Pierre Rossi Date: Fri, 2 Jul 2010 19:31:51 +0200 Subject: Fix an Assert in QTextTable The problem was caused by the fragment id being inserted in front of a cell spanning over several rows instead of the next logical cell (or fragment_end) in the cells structure. Task-number: QTBUG-11282 Reviewed-by: Simon Hausmann --- src/gui/text/qtexttable.cpp | 28 +++++++++++++--- tests/auto/qtexttable/tst_qtexttable.cpp | 55 ++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp index 5100176..e3985ce 100644 --- a/src/gui/text/qtexttable.cpp +++ b/src/gui/text/qtexttable.cpp @@ -754,19 +754,39 @@ void QTextTable::insertColumns(int pos, int num) QTextFormatCollection *c = p->formatCollection(); p->beginEditBlock(); + QList extendedSpans; for (int i = 0; i < d->nRows; ++i) { int cell; if (i == d->nRows - 1 && pos == d->nCols) cell = d->fragment_end; else cell = d->grid[i*d->nCols + pos]; - QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell); - QTextCharFormat fmt = c->charFormat(it->format); if (pos > 0 && pos < d->nCols && cell == d->grid[i*d->nCols + pos - 1]) { // cell spans the insertion place, extend it - fmt.setTableCellColumnSpan(fmt.tableCellColumnSpan() + num); - p->setCharFormat(it.position(), 1, fmt); + if (!extendedSpans.contains(cell)) { + QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell); + QTextCharFormat fmt = c->charFormat(it->format); + fmt.setTableCellColumnSpan(fmt.tableCellColumnSpan() + num); + p->setCharFormat(it.position(), 1, fmt); + d->dirty = true; + extendedSpans << cell; + } } else { + /* If the next cell is spanned from the row above, we need to find the right position + to insert to */ + if (i > 0 && pos < d->nCols && cell == d->grid[(i-1) * d->nCols + pos]) { + int gridIndex = i*d->nCols + pos; + const int gridEnd = d->nRows * d->nCols - 1; + while (gridIndex < gridEnd && cell == d->grid[gridIndex]) { + ++gridIndex; + } + if (gridIndex == gridEnd) + cell = d->fragment_end; + else + cell = d->grid[gridIndex]; + } + QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell); + QTextCharFormat fmt = c->charFormat(it->format); fmt.setTableCellRowSpan(1); fmt.setTableCellColumnSpan(1); Q_ASSERT(fmt.objectIndex() == objectIndex()); diff --git a/tests/auto/qtexttable/tst_qtexttable.cpp b/tests/auto/qtexttable/tst_qtexttable.cpp index 2e6007e..9dcc369 100644 --- a/tests/auto/qtexttable/tst_qtexttable.cpp +++ b/tests/auto/qtexttable/tst_qtexttable.cpp @@ -48,9 +48,14 @@ #include #include #include +#include +#include //TESTED_FILES= +typedef QList IntList; +Q_DECLARE_METATYPE(IntList) + QT_FORWARD_DECLARE_CLASS(QTextDocument) class tst_QTextTable : public QObject @@ -78,6 +83,7 @@ private slots: void insertRows(); void deleteInTable(); void mergeCells(); + void mergeAndInsert(); void splitCells(); void blocksForTableShouldHaveEmptyFormat(); void removeTableByRemoveRows(); @@ -93,6 +99,8 @@ private slots: void removeColumns3(); void removeColumns4(); void removeColumns5(); + void QTBUG11282_insertBeforeMergedEnding_data(); + void QTBUG11282_insertBeforeMergedEnding(); private: QTextTable *create2x2Table(); @@ -586,6 +594,16 @@ void tst_QTextTable::mergeCells() QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1)); } +void tst_QTextTable::mergeAndInsert() +{ + QTextTable *table = cursor.insertTable(4,3); + table->mergeCells(0,1,3,2); + table->mergeCells(3,0,1,3); + //Don't crash ! + table->insertColumns(1,2); + QCOMPARE(table->columns(), 5); +} + void tst_QTextTable::splitCells() { QTextTable *table = create4x4Table(); @@ -931,5 +949,42 @@ void tst_QTextTable::removeColumns5() QCOMPARE(table->cellAt(3, 2).firstPosition(), 11); } +void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding_data() +{ + QTest::addColumn("rows"); + QTest::addColumn("columns"); + QTest::addColumn >("merge"); + QTest::addColumn >("insert"); + + QTest::newRow("2x3, merge two, insert one") << 2 << 3 << (QList() << 1 << 2 << 2) + << (QList() << 1 << 1) ; + QTest::newRow("3x4, merge three, insert one") << 3 << 4 << (QList() << 1 << 3 << 3) + << (QList() << 1 << 1) ; + QTest::newRow("4x3, merge two, insert two") << 4 << 3 << (QList() << 1 << 4 << 2) + << (QList() << 1 << 2) ; + QTest::newRow("4x4, merge middle two, insert one") << 4 << 4 << (QList() << 1 << 4 << 2) + << (QList() << 1 << 1) ; +} + +void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(QList, merge); + QFETCH(QList, insert); + QTextTable *table = cursor.insertTable(rows, columns); + QTextEdit *textEdit = new QTextEdit; + textEdit->setDocument(doc); + textEdit->show(); + QTest::qWaitForWindowShown(textEdit); + table->mergeCells(0,merge.at(0), merge.at(1), merge.at(2)); + //Don't crash ! + table->insertColumns(insert.at(0), insert.at(1)); + //Check that the final size is what we expected + QCOMPARE(table->rows(), rows); + QCOMPARE(table->columns(), columns + insert.at(1)); + delete textEdit; +} + QTEST_MAIN(tst_QTextTable) #include "tst_qtexttable.moc" -- cgit v0.12 From 852ba9a62f65a27e42648d4b28b68c76b1589e75 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 14 Jul 2010 10:46:46 +0200 Subject: Silence warning when building with MSVC 2005 Reviewed-by: Eskil --- src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index ee49a3d..d3f6a29 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1128,7 +1128,7 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush) d->fill(path); } -extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp +extern Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) -- cgit v0.12 From d3f67bfe7cd1cc39d25e6a7371b2b185591008c4 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 14 Jul 2010 10:47:58 +0200 Subject: qdoc: Removed navigation arrow that was causing display problems. Task-number: QTBUG-12157, QTBUG-12148, QTBUG-12146 --- tools/qdoc3/htmlgenerator.cpp | 30 ++++++++++++++++++------------ tools/qdoc3/htmlgenerator.h | 1 + 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 8699cb2..f281fd4 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -63,6 +63,12 @@ QT_BEGIN_NAMESPACE int HtmlGenerator::id = 0; bool HtmlGenerator::debugging_on = false; +#if 0 +QString HtmlGenerator::divNavTop = "
"; +#endif + +QString HtmlGenerator::divNavTop = ""; + QString HtmlGenerator::sinceTitles[] = { " New Namespaces", @@ -1055,11 +1061,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, } sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1); } - out() << "
\n"; + out() << "" << divNavTop << "\n"; } #else out() << "
\n"; + << "\">" << divNavTop << "\n"; #endif break; case Atom::SectionRight: @@ -1307,7 +1313,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, // out() << "
\n"; out() << "
\n"; + << "\">" << divNavTop << "\n"; out() << "

" << protectEnc((*s).name) << "

\n"; generateSection(s->members, inner, marker, CodeMarker::Summary); } @@ -1316,7 +1322,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, // out() << "
\n"; out() << "
\n"; + << "\">" << divNavTop << "\n"; out() << "

" << protectEnc(name) << "

\n"; generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary); } @@ -1343,7 +1349,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, out() << "\n"; } - out() << "
\n"; + out() << "" << divNavTop << "\n"; if (!inner->doc().isEmpty()) { //out() << "
\n" @@ -1483,12 +1489,12 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) generateStatus(fake, marker); if (moduleNamespaceMap.contains(fake->name())) { - out() << "
\n"; + out() << "" << divNavTop << "\n"; out() << "

Namespaces

\n"; generateAnnotatedList(fake, marker, moduleNamespaceMap[fake->name()]); } if (moduleClassMap.contains(fake->name())) { - out() << "
\n"; + out() << "" << divNavTop << "\n"; out() << "

Classes

\n"; generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]); } @@ -1551,13 +1557,13 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) sections = marker->qmlSections(qml_cn,CodeMarker::Summary); s = sections.begin(); while (s != sections.end()) { - out() << "
\n"; + out() << "" << divNavTop << "\n"; out() << "

" << protectEnc((*s).name) << "

\n"; generateQmlSummary(*s,fake,marker); ++s; } - out() << "
\n"; + out() << "" << divNavTop << "\n"; out() << "

" << "Detailed Description" << "

\n"; generateBody(fake, marker); if (cn) @@ -1587,7 +1593,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) sections = marker->sections(fake, CodeMarker::Summary, CodeMarker::Okay); s = sections.begin(); while (s != sections.end()) { - out() << "
\n"; + out() << "" << divNavTop << "\n"; out() << "

" << protectEnc((*s).name) << "

\n"; generateSectionList(*s, fake, marker, CodeMarker::Summary); ++s; @@ -1595,7 +1601,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) Text brief = fake->doc().briefText(); if (fake->subType() == Node::Module && !brief.isEmpty()) { - out() << "
\n"; + out() << "" << divNavTop << "\n"; out() << "
\n"; // QTBUG-9504 out() << "

" << "Detailed Description" << "

\n"; } @@ -3481,7 +3487,7 @@ void HtmlGenerator::generateDetailedMember(const Node *node, out() << "

"; out() << ""; generateSynopsis(node, relative, marker, CodeMarker::Detailed); - out() << "

\n"; + out() << "" << divNavTop << "\n"; } generateStatus(node, marker); diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h index abfca60..54032d3 100644 --- a/tools/qdoc3/htmlgenerator.h +++ b/tools/qdoc3/htmlgenerator.h @@ -324,6 +324,7 @@ class HtmlGenerator : public PageGenerator static int id; public: static bool debugging_on; + static QString divNavTop; }; #define HTMLGENERATOR_ADDRESS "address" -- cgit v0.12 From b7f55ac9c1c6b87083c9dca3b5cbca211fdecaef Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 14 Jul 2010 11:53:07 +0200 Subject: fix warning directive on gnuc --- bin/syncqt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/syncqt b/bin/syncqt index 11b1d72..c8cba30 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -843,7 +843,7 @@ foreach (@modules_to_sync) { my $warning_msg = 'Inclusion of header files from include/Qt is deprecated.'; $header_content = "#ifndef QT_NO_QT_INCLUDE_WARN\n" . " #if defined(__GNUC__)\n" . - " #pragma warning \"$warning_msg\"\n" . + " #warning \"$warning_msg\"\n" . " #elif defined(_MSC_VER)\n" . " #pragma message \"WARNING: $warning_msg\"\n" . " #endif\n". -- cgit v0.12 From 74d0482c1690211a20bdfc996aa0ad30fdb9bb28 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 14 Jul 2010 11:55:27 +0200 Subject: fix qconfig.h aliased header creation don't have configure create the forwarding headers (or symlinks on unix) for qconfig.h, but instead have syncqt create forwarding headers for not yet existing files. Reviewed-by: joerg --- bin/syncqt | 2 ++ configure | 5 ----- tools/configure/configureapp.cpp | 10 ---------- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/bin/syncqt b/bin/syncqt index c8cba30..fb5c8d8 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -691,6 +691,7 @@ my @ignore_for_qt_begin_header_check = ( "qiconset.h", "qconfig.h", "qconfig-dis my @ignore_for_qt_begin_namespace_check = ( "qconfig.h", "qconfig-dist.h", "qconfig-large.h", "qconfig-medium.h", "qconfig-minimal.h", "qconfig-small.h", "qfeatures.h", "qatomic_arch.h", "qatomic_windowsce.h", "qt_windows.h", "qatomic_macosx.h" ); my @ignore_for_qt_module_check = ( "$modules{QtCore}/arch", "$modules{QtCore}/global", "$modules{QtSql}/drivers", "$modules{QtTest}", "$modules{QtDesigner}", "$modules{QtUiTools}", "$modules{QtDBus}", "$modules{phonon}" ); my %colliding_headers = (); +my %inject_headers = ( "$basedir/src/corelib/global" => ( "qconfig.h" ) ); foreach (@modules_to_sync) { #iteration info @@ -800,6 +801,7 @@ foreach (@modules_to_sync) { foreach (@subdirs) { my $subdir = "$_"; my @headers = findFiles("$subdir", "^[-a-z0-9_]*\\.h\$" , 0); + push @headers, $inject_headers{$subdir} if (defined $inject_headers{$subdir}); foreach (@headers) { my $header = "$_"; $header = 0 if("$header" =~ /^ui_.*.h/); diff --git a/configure b/configure index 166f201..62e0863 100755 --- a/configure +++ b/configure @@ -4481,11 +4481,6 @@ if true; then ###[ '!' -f "$outpath/bin/qmake" ]; fi mv -f "$QMAKE_QCONFIG_H" "$QCONFIG_H" - for conf in "$outpath/include/QtCore/qconfig.h" "$outpath/include/Qt/qconfig.h"; do - if [ '!' -f "$conf" ]; then - ln -s "$QCONFIG_H" "$conf" - fi - done #mkspecs/default is used as a (gasp!) default mkspec so QMAKESPEC needn't be set once configured rm -f mkspecs/default diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index d3dec3c..7f2d53b 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -3164,16 +3164,6 @@ void Configure::generateConfigfiles() QFile::remove(outName); tmpFile.copy(outName); tmpFile.close(); - - if (!QFile::exists(buildPath + "/include/QtCore/qconfig.h")) { - if (!writeToFile("#include \"../../src/corelib/global/qconfig.h\"\n", - buildPath + "/include/QtCore/qconfig.h") - || !writeToFile("#include \"../../src/corelib/global/qconfig.h\"\n", - buildPath + "/include/Qt/qconfig.h")) { - dictionary["DONE"] = "error"; - return; - } - } } // Copy configured mkspec to default directory, but remove the old one first, if there is any -- cgit v0.12 From 56e24c99ee7a1b5b127b93cbab98f88e008ec9b8 Mon Sep 17 00:00:00 2001 From: Prasanth Ullattil Date: Wed, 14 Jul 2010 13:03:48 +0200 Subject: Crash while runnig tst_QMdiSubWindow::emittingOfSignals test on Cocoa We were assuming that the native windows we create will always have a corresponding QWidget. This is not the case for qt_root_win. Reviewed-by: Carlos Duclos --- src/gui/kernel/qcocoasharedwindowmethods_mac_p.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h index 8652816..6795149 100644 --- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h +++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h @@ -85,6 +85,8 @@ QT_END_NAMESPACE - (BOOL)canBecomeKeyWindow { QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)]; + if (!widget) + return NO; // This should happen only for qt_root_win bool isToolTip = (widget->windowType() == Qt::ToolTip); bool isPopup = (widget->windowType() == Qt::Popup); @@ -94,6 +96,8 @@ QT_END_NAMESPACE - (BOOL)canBecomeMainWindow { QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)]; + if (!widget) + return NO; // This should happen only for qt_root_win bool isToolTip = (widget->windowType() == Qt::ToolTip); bool isPopup = (widget->windowType() == Qt::Popup); -- cgit v0.12 From 247e3637c41cc14d174a1170957274fb8a9400b4 Mon Sep 17 00:00:00 2001 From: Prasanth Ullattil Date: Wed, 14 Jul 2010 13:52:39 +0200 Subject: Drag and drop cursor doesnot change on invalid drop areas (Cocoa) Previos versions of Mac OS X (< 10.6) didn't have support for such 'Not Allowed' cursors. 10.6 introduced a new method for NSCursor called operationNotAllowedCursor. This fix uses the new cusor on available platforms. Task-number: QTBUG-5186 Reviewed-by: Denis --- src/gui/kernel/qcocoaview_mac.mm | 38 +++++++++++++++++++++++++++++++++++--- src/gui/kernel/qcocoaview_mac_p.h | 1 + 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 5c90e2e..1935531 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -269,6 +269,28 @@ static int qCocoaViewCount = 0; dropData = new QCocoaDropData(dropPasteboard); } +- (void)changeDraggingCursor:(NSDragOperation)newOperation +{ + static SEL action = nil; + static bool operationSupported = false; + if (action == nil) { + action = NSSelectorFromString(@"operationNotAllowedCursor"); + if ([NSCursor respondsToSelector:action]) { + operationSupported = true; + } + } + if (operationSupported) { + NSCursor *notAllowedCursor = [NSCursor performSelector:action]; + bool isNotAllowedCursor = ([NSCursor currentCursor] == notAllowedCursor); + if (newOperation == NSDragOperationNone && !isNotAllowedCursor) { + [notAllowedCursor push]; + } else if (newOperation != NSDragOperationNone && isNotAllowedCursor) { + [notAllowedCursor pop]; + } + + } +} + - (NSDragOperation)draggingEntered:(id )sender { // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly @@ -300,6 +322,7 @@ static int qCocoaViewCount = 0; if (!qDEEvent.isAccepted()) { // widget is not interested in this drag, so ignore this drop data. [self removeDropData]; + [self changeDraggingCursor:NSDragOperationNone]; return NSDragOperationNone; } else { // save the mouse position, used by draggingExited handler. @@ -321,6 +344,7 @@ static int qCocoaViewCount = 0; nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDMEvent.dropAction()); } QT_PREPEND_NAMESPACE(qt_mac_copy_answer_rect)(qDMEvent); + [self changeDraggingCursor:nsActions]; return nsActions; } } @@ -335,16 +359,21 @@ static int qCocoaViewCount = 0; if (dragEnterSequence != [sender draggingSequenceNumber]) [self draggingEntered:sender]; // drag enter event was rejected, so ignore the move event. - if (dropData == 0) + if (dropData == 0) { + [self changeDraggingCursor:NSDragOperationNone]; return NSDragOperationNone; + } // return last value, if we are still in the answerRect. NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint]; NSPoint localPoint = [self convertPoint:windowPoint fromView:nil]; NSDragOperation nsActions = [sender draggingSourceOperationMask]; QPoint posDrag(localPoint.x, localPoint.y); if (qt_mac_mouse_inside_answer_rect(posDrag) - && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) == nsActions) - return QT_PREPEND_NAMESPACE(qt_mac_mapDropActions)(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastAction)); + && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) == nsActions) { + NSDragOperation operation = QT_PREPEND_NAMESPACE(qt_mac_mapDropActions)(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastAction)); + [self changeDraggingCursor:operation]; + return operation; + } // send drag move event to the widget QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions; Qt::DropActions qtAllowed = QT_PREPEND_NAMESPACE(qt_mac_mapNSDragOperations)(nsActions); @@ -373,6 +402,7 @@ static int qCocoaViewCount = 0; qDMEvent.setDropAction(Qt::IgnoreAction); } qt_mac_copy_answer_rect(qDMEvent); + [self changeDraggingCursor:operation]; return operation; } @@ -388,6 +418,8 @@ static int qCocoaViewCount = 0; QApplication::sendEvent(qwidget, &de); [self removeDropData]; } + [self changeDraggingCursor:NSDragOperationEvery]; + } - (BOOL)performDragOperation:(id )sender diff --git a/src/gui/kernel/qcocoaview_mac_p.h b/src/gui/kernel/qcocoaview_mac_p.h index 33aaa24..b6b63ca 100644 --- a/src/gui/kernel/qcocoaview_mac_p.h +++ b/src/gui/kernel/qcocoaview_mac_p.h @@ -106,6 +106,7 @@ Q_GUI_EXPORT - (void) qt_clearQWidget; - (BOOL)qt_leftButtonIsRightButton; - (void)qt_setLeftButtonIsRightButton:(BOOL)isSwapped; +- (void)changeDraggingCursor:(NSDragOperation)newOperation; + (DnDParams*)currentMouseEvent; @end -- cgit v0.12 From 00b7befbc003682a351c18d90436010efd26ece5 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 14 Jul 2010 16:26:19 +0200 Subject: fix qconfig.h reference for shadow builds Reviewed-by: joerg --- bin/syncqt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/syncqt b/bin/syncqt index fb5c8d8..03659d3 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -691,7 +691,7 @@ my @ignore_for_qt_begin_header_check = ( "qiconset.h", "qconfig.h", "qconfig-dis my @ignore_for_qt_begin_namespace_check = ( "qconfig.h", "qconfig-dist.h", "qconfig-large.h", "qconfig-medium.h", "qconfig-minimal.h", "qconfig-small.h", "qfeatures.h", "qatomic_arch.h", "qatomic_windowsce.h", "qt_windows.h", "qatomic_macosx.h" ); my @ignore_for_qt_module_check = ( "$modules{QtCore}/arch", "$modules{QtCore}/global", "$modules{QtSql}/drivers", "$modules{QtTest}", "$modules{QtDesigner}", "$modules{QtUiTools}", "$modules{QtDBus}", "$modules{phonon}" ); my %colliding_headers = (); -my %inject_headers = ( "$basedir/src/corelib/global" => ( "qconfig.h" ) ); +my %inject_headers = ( "$basedir/src/corelib/global" => ( "*qconfig.h" ) ); foreach (@modules_to_sync) { #iteration info @@ -804,6 +804,7 @@ foreach (@modules_to_sync) { push @headers, $inject_headers{$subdir} if (defined $inject_headers{$subdir}); foreach (@headers) { my $header = "$_"; + my $shadow = ($header =~ s/^\*//); $header = 0 if("$header" =~ /^ui_.*.h/); foreach (@ignore_headers) { $header = 0 if("$header" eq "$_"); @@ -821,6 +822,7 @@ foreach (@modules_to_sync) { } my $iheader = $subdir . "/" . $header; + $iheader =~ s/^\Q$basedir\E/$out_basedir/ if ($shadow); my @classes = $public_header ? classNames($iheader) : (); if($showonly) { print "$header [$lib]\n"; -- cgit v0.12 From 6536b6f16ff26579f191543e5d468a6382211a29 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Wed, 14 Jul 2010 23:43:58 +0200 Subject: Add unit tests for QMimeData. Merge-request: 2428 Reviewed-by: Andreas Kling --- tests/auto/gui.pro | 1 + tests/auto/qmimedata/qmimedata.pro | 4 + tests/auto/qmimedata/tst_qmimedata.cpp | 343 +++++++++++++++++++++++++++++++++ 3 files changed, 348 insertions(+) create mode 100644 tests/auto/qmimedata/qmimedata.pro create mode 100644 tests/auto/qmimedata/tst_qmimedata.cpp diff --git a/tests/auto/gui.pro b/tests/auto/gui.pro index cfaa3fa..2d9ea93 100644 --- a/tests/auto/gui.pro +++ b/tests/auto/gui.pro @@ -112,6 +112,7 @@ SUBDIRS=\ qmdisubwindow \ qmessagebox \ qmetaobject \ + qmimedata \ qmouseevent_modal \ qmovie \ qnetworkaccessmanager_and_qprogressdialog \ diff --git a/tests/auto/qmimedata/qmimedata.pro b/tests/auto/qmimedata/qmimedata.pro new file mode 100644 index 0000000..13fbe65 --- /dev/null +++ b/tests/auto/qmimedata/qmimedata.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qmimedata.cpp + + diff --git a/tests/auto/qmimedata/tst_qmimedata.cpp b/tests/auto/qmimedata/tst_qmimedata.cpp new file mode 100644 index 0000000..be7a654 --- /dev/null +++ b/tests/auto/qmimedata/tst_qmimedata.cpp @@ -0,0 +1,343 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include + +class tst_QMimeData : public QObject +{ + Q_OBJECT +public: + tst_QMimeData() + { + } + +private slots: + void clear() const; + void colorData() const; + void data() const; + void formats() const; + void hasColor() const; + void hasFormat() const; + void hasHtml() const; + void hasImage() const; + // hasText() covered by setText() + // hasUrls() covered by setUrls() + // html() covered by setHtml() + void imageData() const; + void removeFormat() const; + // setColorData() covered by hasColor() + // setData() covered in a few different tests + void setHtml() const; + // setImageData() covered in a few tests + void setText() const; + void setUrls() const; + // text() covered in setText() + // urls() covered by setUrls() +}; + +void tst_QMimeData::clear() const +{ + QMimeData mimeData; + + // set, clear, verify empty + mimeData.setData("text/plain", "pirates"); + QVERIFY(mimeData.hasText()); + mimeData.clear(); + QVERIFY(mimeData.hasText() == false); + + // repopulate, verify not empty + mimeData.setData("text/plain", "pirates"); + QVERIFY(mimeData.hasText()); +} + +void tst_QMimeData::colorData() const +{ + QMimeData mimeData; + QColor red = Qt::red; + QColor blue = Qt::blue; + + // set, verify + mimeData.setColorData(red); + QVERIFY(mimeData.hasColor()); + QCOMPARE(qvariant_cast(mimeData.colorData()), red); + + // change, verify + mimeData.setColorData(Qt::blue); + QVERIFY(mimeData.hasColor()); + QCOMPARE(qvariant_cast(mimeData.colorData()), blue); +} + +void tst_QMimeData::data() const +{ + QMimeData mimeData; + + // set text, verify + mimeData.setData("text/plain", "pirates"); + QCOMPARE(mimeData.data("text/plain"), QByteArray("pirates")); + QVERIFY(mimeData.data("text/html").length() == 0); + + // html time + mimeData.setData("text/html", "ninjas"); + QCOMPARE(mimeData.data("text/html"), QByteArray("ninjas")); + QCOMPARE(mimeData.data("text/plain"), QByteArray("pirates")); // make sure text not damaged + QCOMPARE(mimeData.data("text/html"), mimeData.html().toLatin1()); +} + +void tst_QMimeData::formats() const +{ + QMimeData mimeData; + + // set text, verify + mimeData.setData("text/plain", "pirates"); + QCOMPARE(mimeData.formats(), QStringList() << "text/plain"); + + // set html, verify + mimeData.setData("text/html", "ninjas"); + QCOMPARE(mimeData.formats(), QStringList() << "text/plain" << "text/html"); + + // clear, verify + mimeData.clear(); + QCOMPARE(mimeData.formats(), QStringList()); + + // set an odd format, verify + mimeData.setData("foo/bar", "somevalue"); + QCOMPARE(mimeData.formats(), QStringList() << "foo/bar"); +} + +void tst_QMimeData::hasColor() const +{ + QMimeData mimeData; + + // initial state + QVERIFY(mimeData.hasColor() == false); + + // set, verify + mimeData.setColorData(QColor(Qt::red)); + QVERIFY(mimeData.hasColor()); + + // clear, verify + mimeData.clear(); + QVERIFY(mimeData.hasColor() == false); + + // set something else, verify + mimeData.setData("text/plain", "pirates"); + QVERIFY(mimeData.hasColor() == false); +} + +void tst_QMimeData::hasFormat() const +{ + QMimeData mimeData; + + // initial state + QVERIFY(mimeData.hasFormat("text/plain") == false); + + // add, verify + mimeData.setData("text/plain", "pirates"); + QVERIFY(mimeData.hasFormat("text/plain")); + QVERIFY(mimeData.hasFormat("text/html") == false); + + // clear, verify + mimeData.clear(); + QVERIFY(mimeData.hasFormat("text/plain") == false); + QVERIFY(mimeData.hasFormat("text/html") == false); +} + +void tst_QMimeData::hasHtml() const +{ + QMimeData mimeData; + + // initial state + QVERIFY(mimeData.hasHtml() == false); + + // add plain, verify false + mimeData.setData("text/plain", "pirates"); + QVERIFY(mimeData.hasHtml() == false); + + // add html, verify + mimeData.setData("text/html", "ninjas"); + QVERIFY(mimeData.hasHtml()); + + // clear, verify + mimeData.clear(); + QVERIFY(mimeData.hasHtml() == false); + + // readd, verify + mimeData.setData("text/html", "ninjas"); + QVERIFY(mimeData.hasHtml()); +} + +void tst_QMimeData::hasImage() const +{ + QMimeData mimeData; + + // initial state + QVERIFY(mimeData.hasImage() == false); + + // add text, verify false + mimeData.setData("text/plain", "pirates"); + QVERIFY(mimeData.hasImage() == false); + + // add image + mimeData.setImageData(QImage()); + QVERIFY(mimeData.hasImage()); + + // clear, verify + mimeData.clear(); + QVERIFY(mimeData.hasImage() == false); +} + +void tst_QMimeData::imageData() const +{ + QMimeData mimeData; + + // initial state + QCOMPARE(mimeData.imageData(), QVariant()); + + // set, test + mimeData.setImageData(QImage()); + QVERIFY(mimeData.hasImage()); + QCOMPARE(mimeData.imageData(), QVariant(QImage())); + + // clear, verify + mimeData.clear(); + QCOMPARE(mimeData.imageData(), QVariant()); +} + +void tst_QMimeData::removeFormat() const +{ + QMimeData mimeData; + + // add, verify + mimeData.setData("text/plain", "pirates"); + QVERIFY(mimeData.hasFormat("text/plain")); + + // add another, verify + mimeData.setData("text/html", "ninjas"); + QVERIFY(mimeData.hasFormat("text/html")); + + // remove, verify + mimeData.removeFormat("text/plain"); + QVERIFY(mimeData.hasFormat("text/plain") == false); + QVERIFY(mimeData.hasFormat("text/html")); + + // remove, verify + mimeData.removeFormat("text/html"); + QVERIFY(mimeData.hasFormat("text/plain") == false); + QVERIFY(mimeData.hasFormat("text/html") == false); +} + +void tst_QMimeData::setHtml() const +{ + QMimeData mimeData; + + // initial state + QVERIFY(mimeData.hasHtml() == false); + + // add html, verify + mimeData.setHtml("ninjas"); + QVERIFY(mimeData.hasHtml()); + QCOMPARE(mimeData.html(), QLatin1String("ninjas")); + + // reset html + mimeData.setHtml("pirates"); + QVERIFY(mimeData.hasHtml()); + QCOMPARE(mimeData.html(), QLatin1String("pirates")); +} + +void tst_QMimeData::setText() const +{ + QMimeData mimeData; + + // verify initial state + QCOMPARE(mimeData.text(), QLatin1String("")); + QVERIFY(mimeData.hasText() == false); + + // set, verify + mimeData.setText("pirates"); + QVERIFY(mimeData.hasText()); + QCOMPARE(mimeData.text(), QLatin1String("pirates")); + QCOMPARE(mimeData.text().toLatin1(), mimeData.data("text/plain")); + + // reset, verify + mimeData.setText("ninjas"); + QVERIFY(mimeData.hasText()); + QCOMPARE(mimeData.text(), QLatin1String("ninjas")); + QCOMPARE(mimeData.text().toLatin1(), mimeData.data("text/plain")); + + // clear, verify + mimeData.clear(); + QCOMPARE(mimeData.text(), QLatin1String("")); + QVERIFY(mimeData.hasText() == false); +} + +void tst_QMimeData::setUrls() const +{ + QMimeData mimeData; + QList shortUrlList; + QList longUrlList; + + // set up + shortUrlList += QUrl("http://qt.nokia.com"); + longUrlList = shortUrlList; + longUrlList += QUrl("http://www.google.com"); + + // verify initial state + QVERIFY(mimeData.hasUrls() == false); + + // set a few, verify + mimeData.setUrls(shortUrlList); + QCOMPARE(mimeData.urls(), shortUrlList); + + // change them, verify + mimeData.setUrls(longUrlList); + QCOMPARE(mimeData.urls(), longUrlList); + + // clear, verify + mimeData.clear(); + QVERIFY(mimeData.hasUrls() == false); +} + + +QTEST_MAIN(tst_QMimeData) +#include "tst_qmimedata.moc" -- cgit v0.12