diff options
106 files changed, 1580 insertions, 606 deletions
diff --git a/demos/declarative/minehunt/minehunt.cpp b/demos/declarative/minehunt/minehunt.cpp index 9c82f30..709d945 100644 --- a/demos/declarative/minehunt/minehunt.cpp +++ b/demos/declarative/minehunt/minehunt.cpp @@ -195,6 +195,7 @@ bool MinehuntGame::flip(int row, int col) won = false; hasWonChanged(); setPlaying(false); + return true; } remaining--; @@ -202,6 +203,7 @@ bool MinehuntGame::flip(int row, int col) won = true; hasWonChanged(); setPlaying(false); + return true; } return true; } @@ -209,7 +211,7 @@ bool MinehuntGame::flip(int row, int col) bool MinehuntGame::flag(int row, int col) { TileData *t = tile(row, col); - if(!t) + if(!t || !playing) return false; t->setHasFlag(!t->hasFlag()); diff --git a/doc/src/declarative/basictypes.qdoc b/doc/src/declarative/basictypes.qdoc index e327d4a..e8aceb3 100644 --- a/doc/src/declarative/basictypes.qdoc +++ b/doc/src/declarative/basictypes.qdoc @@ -156,8 +156,10 @@ Example: \qml Rectangle { color: "steelblue" } + Rectangle { color: "transparent" } Rectangle { color: "#FF0000" } Rectangle { color: "#800000FF" } + Rectangle { color: "#00000000" } // ARGB fully transparent \endqml Or with the \l{QML:Qt::rgba()}{Qt.rgba()}, \l{QML:Qt::hsla()}{Qt.hsla()}, \l{QML:Qt::darker()}{Qt.darker()}, diff --git a/examples/declarative/animation/behaviors/wigglytext.qml b/examples/declarative/animation/behaviors/wigglytext.qml new file mode 100644 index 0000000..6cd93ab --- /dev/null +++ b/examples/declarative/animation/behaviors/wigglytext.qml @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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 examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 1.0 + +Rectangle { + id: container + + property string text: "Drag this text..." + property bool animated: true + + width: 640; height: 480; color: "#474747"; focus: true + + Keys.onPressed: { + if (event.key == Qt.Key_Delete || event.key == Qt.Key_Backspace) + container.remove() + else if (event.text != "") { + container.append(event.text) + } + } + + function append(text) { + container.animated = false + var lastLetter = container.children[container.children.length - 1] + var newLetter = letterComponent.createObject(container) + newLetter.text = text + newLetter.follow = lastLetter + container.animated = true + } + + function remove() { + if (container.children.length) + container.children[container.children.length - 1].destroy() + } + + function doLayout() { + var follow = null + for (var i = 0; i < container.text.length; ++i) { + var newLetter = letterComponent.createObject(container) + newLetter.text = container.text[i] + newLetter.follow = follow + follow = newLetter + } + } + + Component { + id: letterComponent + Text { + id: letter + property variant follow + + x: follow ? follow.x + follow.width : container.width / 3 + y: follow ? follow.y : container.height / 2 + + font.pixelSize: 40; font.bold: true + color: "#999999"; styleColor: "#222222"; style: Text.Raised + + MouseArea { + anchors.fill: parent + drag.target: letter; drag.axis: Drag.XandYAxis + onPressed: letter.color = "#dddddd" + onReleased: letter.color = "#999999" + } + + Behavior on x { enabled: container.animated; SpringAnimation { spring: 3; damping: 0.3; mass: 1.0 } } + Behavior on y { enabled: container.animated; SpringAnimation { spring: 3; damping: 0.3; mass: 1.0 } } + } + } + + Component.onCompleted: doLayout() +} diff --git a/examples/declarative/tutorials/samegame/samegame4/content/samegame.js b/examples/declarative/tutorials/samegame/samegame4/content/samegame.js index 79ff0c1..ccc3f9d 100755 --- a/examples/declarative/tutorials/samegame/samegame4/content/samegame.js +++ b/examples/declarative/tutorials/samegame/samegame4/content/samegame.js @@ -145,7 +145,7 @@ function shuffleDown() { obj = board[index(column, row)]; if (obj == null) continue; - obj.x = (fallDist - column) * gameCanvas.blockSize; + obj.x = (column - fallDist) * gameCanvas.blockSize; board[index(column - fallDist, row)] = obj; board[index(column, row)] = null; } diff --git a/mkspecs/symbian-sbsv2/flm/qt/qmake_emulator_deployment.flm b/mkspecs/symbian-sbsv2/flm/qt/qmake_emulator_deployment.flm index 3877edb..a557cbb 100644 --- a/mkspecs/symbian-sbsv2/flm/qt/qmake_emulator_deployment.flm +++ b/mkspecs/symbian-sbsv2/flm/qt/qmake_emulator_deployment.flm @@ -21,7 +21,7 @@ CLEAN_TARGET:=$(1) $(1): $(2) $(call startrule,qmake_emulator_deployment) \ - $(GNUCP) --no-preserve=mode $(2) "$$@" && \ + $(GNUCP) --remove-destination --no-preserve=mode $(2) "$$@" && \ $(GNUCHMOD) a+rw "$$@" \ $(call endrule,qmake_emulator_deployment) endef diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index ceffa66..573bb50 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -127,6 +127,7 @@ extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *) void (*QAbstractDeclarativeData::destroyed)(QAbstractDeclarativeData *, QObject *) = 0; void (*QAbstractDeclarativeData::parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *) = 0; +void (*QAbstractDeclarativeData::objectNameChanged)(QAbstractDeclarativeData *, QObject *) = 0; QObjectData::~QObjectData() {} @@ -1067,7 +1068,12 @@ QString QObject::objectName() const void QObject::setObjectName(const QString &name) { Q_D(QObject); + bool objectNameChanged = d->declarativeData && d->objectName != name; + d->objectName = name; + + if (objectNameChanged) + d->declarativeData->objectNameChanged(d->declarativeData, this); } diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 82023d4..effd3e6 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -90,6 +90,7 @@ class Q_CORE_EXPORT QAbstractDeclarativeData public: static void (*destroyed)(QAbstractDeclarativeData *, QObject *); static void (*parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *); + static void (*objectNameChanged)(QAbstractDeclarativeData *, QObject *); }; class Q_CORE_EXPORT QObjectPrivate : public QObjectData diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp index 7c43e5b..cdfdc58 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp +++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp @@ -466,7 +466,7 @@ QDeclarativeFlickable::~QDeclarativeFlickable() qreal QDeclarativeFlickable::contentX() const { Q_D(const QDeclarativeFlickable); - return -d->hData.move.value(); + return -d->contentItem->x(); } void QDeclarativeFlickable::setContentX(qreal pos) @@ -484,7 +484,7 @@ void QDeclarativeFlickable::setContentX(qreal pos) qreal QDeclarativeFlickable::contentY() const { Q_D(const QDeclarativeFlickable); - return -d->vData.move.value(); + return -d->contentItem->y(); } void QDeclarativeFlickable::setContentY(qreal pos) diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 8216ab7..6ee6b0d 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -218,7 +218,14 @@ public: return visibleItems.last()->rowPos() + rows * rowSize(); } } else { - return (modelIndex / columns) * rowSize(); + qreal pos = (modelIndex / columns) * rowSize(); + if (header) { + qreal headerSize = flow == QDeclarativeGridView::LeftToRight + ? header->item->height() + : header->item->width(); + pos += headerSize; + } + return pos; } return 0; } diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp index 02b4807..c3bac2d 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp @@ -46,8 +46,6 @@ #include <qdeclarativeinfo.h> #include <qdeclarativepixmapcache_p.h> -#include <QFile> - QT_BEGIN_NAMESPACE QDeclarativeImageBase::QDeclarativeImageBase(QDeclarativeImageBasePrivate &dd, QDeclarativeItem *parent) @@ -115,6 +113,7 @@ void QDeclarativeImageBase::setSourceSize(const QSize& size) return; d->sourcesize = size; + d->explicitSourceSize = true; emit sourceSizeChanged(); if (isComponentComplete()) load(); @@ -123,7 +122,10 @@ void QDeclarativeImageBase::setSourceSize(const QSize& size) QSize QDeclarativeImageBase::sourceSize() const { Q_D(const QDeclarativeImageBase); - return d->sourcesize.isValid() ? d->sourcesize : QSize(implicitWidth(),implicitHeight()); + + int width = d->sourcesize.width(); + int height = d->sourcesize.height(); + return QSize(width != -1 ? width : implicitWidth(), height != -1 ? height : implicitHeight()); } void QDeclarativeImageBase::load() @@ -141,7 +143,7 @@ void QDeclarativeImageBase::load() pixmapChange(); update(); } else { - d->pix.load(qmlEngine(this), d->url, d->sourcesize, d->async); + d->pix.load(qmlEngine(this), d->url, d->explicitSourceSize ? sourceSize() : QSize(), d->async); if (d->pix.isLoading()) { d->progress = 0.0; @@ -186,11 +188,8 @@ void QDeclarativeImageBase::requestFinished() setImplicitWidth(d->pix.width()); setImplicitHeight(d->pix.height()); - if (d->sourcesize.width() != d->pix.width() || d->sourcesize.height() != d->pix.height()) { - d->sourcesize.setWidth(d->pix.width()); - d->sourcesize.setHeight(d->pix.height()); + if (d->sourcesize.width() != d->pix.width() || d->sourcesize.height() != d->pix.height()) emit sourceSizeChanged(); - } if (d->status != oldStatus) emit statusChanged(d->status); diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h index aee8b28..3d23ba9 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h @@ -69,6 +69,7 @@ public: QDeclarativeImageBasePrivate() : status(QDeclarativeImageBase::Null), progress(0.0), + explicitSourceSize(false), async(false) { QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents; @@ -79,6 +80,7 @@ public: QUrl url; qreal progress; QSize sourcesize; + bool explicitSourceSize : 1; bool async : 1; }; diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp index 250a43b..51eb5f2 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp @@ -56,7 +56,6 @@ #include <QDebug> #include <QPen> -#include <QFile> #include <QEvent> #include <QGraphicsSceneMouseEvent> #include <QtCore/qnumeric.h> @@ -1181,7 +1180,7 @@ void QDeclarativeKeysAttached::keyPressed(QKeyEvent *event, bool post) d->inPress = true; for (int ii = 0; ii < d->targets.count(); ++ii) { QGraphicsItem *i = d->finalFocusProxy(d->targets.at(ii)); - if (i) { + if (i && i->isVisible()) { d->item->scene()->sendEvent(i, event); if (event->isAccepted()) { d->inPress = false; @@ -1223,7 +1222,7 @@ void QDeclarativeKeysAttached::keyReleased(QKeyEvent *event, bool post) d->inRelease = true; for (int ii = 0; ii < d->targets.count(); ++ii) { QGraphicsItem *i = d->finalFocusProxy(d->targets.at(ii)); - if (i) { + if (i && i->isVisible()) { d->item->scene()->sendEvent(i, event); if (event->isAccepted()) { d->inRelease = false; @@ -1248,7 +1247,7 @@ void QDeclarativeKeysAttached::inputMethodEvent(QInputMethodEvent *event, bool p d->inIM = true; for (int ii = 0; ii < d->targets.count(); ++ii) { QGraphicsItem *i = d->finalFocusProxy(d->targets.at(ii)); - if (i && (i->flags() & QGraphicsItem::ItemAcceptsInputMethod)) { + if (i && i->isVisible() && (i->flags() & QGraphicsItem::ItemAcceptsInputMethod)) { d->item->scene()->sendEvent(i, event); if (event->isAccepted()) { d->imeItem = i; @@ -1276,7 +1275,7 @@ QVariant QDeclarativeKeysAttached::inputMethodQuery(Qt::InputMethodQuery query) if (d->item) { for (int ii = 0; ii < d->targets.count(); ++ii) { QGraphicsItem *i = d->finalFocusProxy(d->targets.at(ii)); - if (i && (i->flags() & QGraphicsItem::ItemAcceptsInputMethod) && i == d->imeItem) { //### how robust is i == d->imeItem check? + if (i && i->isVisible() && (i->flags() & QGraphicsItem::ItemAcceptsInputMethod) && i == d->imeItem) { //### how robust is i == d->imeItem check? QVariant v = static_cast<QDeclarativeItemAccessor *>(i)->doInputMethodQuery(query); if (v.userType() == QVariant::RectF) v = d->item->mapRectFromItem(i, v.toRectF()); //### cost? diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index 6b46bc5..6fd3b71 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -775,7 +775,6 @@ void QDeclarativeListViewPrivate::layout() setPosition(0); return; } - updateSections(); if (!visibleItems.isEmpty()) { qreal oldEnd = visibleItems.last()->endPosition(); qreal pos = visibleItems.first()->endPosition() + spacing + 1; @@ -934,6 +933,7 @@ void QDeclarativeListViewPrivate::createSection(FxListItem *listItem) return; if (listItem->attached->m_prevSection != listItem->attached->m_section) { if (!listItem->section) { + qreal pos = listItem->position(); int i = sectionCacheSize-1; while (i >= 0 && !sectionCache[i]) --i; @@ -961,8 +961,10 @@ void QDeclarativeListViewPrivate::createSection(FxListItem *listItem) delete context; } } + listItem->setPosition(pos); } } else if (listItem->section) { + qreal pos = listItem->position(); int i = 0; do { if (!sectionCache[i]) { @@ -975,12 +977,13 @@ void QDeclarativeListViewPrivate::createSection(FxListItem *listItem) } while (i < sectionCacheSize); delete listItem->section; listItem->section = 0; + listItem->setPosition(pos); } } void QDeclarativeListViewPrivate::updateSections() { - if (sectionCriteria) { + if (sectionCriteria && !visibleItems.isEmpty()) { QString prevSection; if (visibleIndex > 0) prevSection = sectionAt(visibleIndex-1); @@ -990,6 +993,8 @@ void QDeclarativeListViewPrivate::updateSections() if (visibleItems.at(i)->index != -1) { QDeclarativeListViewAttached *attached = visibleItems.at(i)->attached; attached->setPrevSection(prevSection); + QString propValue = model->stringValue(visibleItems.at(i)->index, sectionCriteria->property()); + attached->setSection(sectionCriteria->sectionString(propValue)); if (prevAtt) prevAtt->setNextSection(attached->section()); createSection(visibleItems.at(i)); @@ -1009,18 +1014,27 @@ void QDeclarativeListViewPrivate::updateSections() void QDeclarativeListViewPrivate::updateCurrentSection() { + Q_Q(QDeclarativeListView); if (!sectionCriteria || visibleItems.isEmpty()) { - currentSection.clear(); + if (!currentSection.isEmpty()) { + currentSection.clear(); + emit q->currentSectionChanged(); + } return; } int index = 0; while (index < visibleItems.count() && visibleItems.at(index)->endPosition() < position()) ++index; + QString newSection = currentSection; if (index < visibleItems.count()) - currentSection = visibleItems.at(index)->attached->section(); + newSection = visibleItems.at(index)->attached->section(); else - currentSection = visibleItems.first()->attached->section(); + newSection = visibleItems.first()->attached->section(); + if (newSection != currentSection) { + currentSection = newSection; + emit q->currentSectionChanged(); + } } void QDeclarativeListViewPrivate::updateCurrent(int modelIndex) @@ -1551,6 +1565,7 @@ void QDeclarativeListView::setModel(const QVariant &model) disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int))); + disconnect(d->model, SIGNAL(itemsChanged(int,int)), this, SLOT(itemsChanged(int,int))); disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset())); disconnect(d->model, SIGNAL(createdItem(int, QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*))); disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*))); @@ -1581,6 +1596,7 @@ void QDeclarativeListView::setModel(const QVariant &model) if (d->model) { d->bufferMode = QDeclarativeListViewPrivate::BufferBefore | QDeclarativeListViewPrivate::BufferAfter; if (isComponentComplete()) { + updateSections(); refill(); if (d->currentIndex >= d->model->count() || d->currentIndex < 0) { setCurrentIndex(0); @@ -1596,6 +1612,7 @@ void QDeclarativeListView::setModel(const QVariant &model) connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int))); connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int))); connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int))); + connect(d->model, SIGNAL(itemsChanged(int,int)), this, SLOT(itemsChanged(int,int))); connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset())); connect(d->model, SIGNAL(createdItem(int, QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*))); connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*))); @@ -1653,6 +1670,7 @@ void QDeclarativeListView::setDelegate(QDeclarativeComponent *delegate) d->visibleItems.clear(); d->releaseItem(d->currentItem); d->currentItem = 0; + updateSections(); refill(); d->moveReason = QDeclarativeListViewPrivate::SetIndex; d->updateCurrent(d->currentIndex); @@ -2066,8 +2084,10 @@ void QDeclarativeListView::setCacheBuffer(int b) QDeclarativeViewSection *QDeclarativeListView::sectionCriteria() { Q_D(QDeclarativeListView); - if (!d->sectionCriteria) + if (!d->sectionCriteria) { d->sectionCriteria = new QDeclarativeViewSection(this); + connect(d->sectionCriteria, SIGNAL(propertyChanged()), this, SLOT(updateSections())); + } return d->sectionCriteria; } @@ -2660,6 +2680,7 @@ void QDeclarativeListView::componentComplete() { Q_D(QDeclarativeListView); QDeclarativeFlickable::componentComplete(); + updateSections(); if (d->isValid()) { refill(); d->moveReason = QDeclarativeListViewPrivate::SetIndex; @@ -2676,6 +2697,18 @@ void QDeclarativeListView::componentComplete() } } +void QDeclarativeListView::updateSections() +{ + Q_D(QDeclarativeListView); + if (isComponentComplete() && d->model) { + QList<QByteArray> roles; + if (d->sectionCriteria && !d->sectionCriteria->property().isEmpty()) + roles << d->sectionCriteria->property().toUtf8(); + d->model->setWatchedRoles(roles); + d->updateSections(); + } +} + void QDeclarativeListView::refill() { Q_D(QDeclarativeListView); @@ -2885,6 +2918,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) for (int j = 0; j < added.count(); ++j) added.at(j)->attached->emitAdd(); + d->updateSections(); d->itemCount += count; emit countChanged(); } @@ -2977,6 +3011,7 @@ void QDeclarativeListView::itemsRemoved(int modelIndex, int count) } } + d->updateSections(); emit countChanged(); } @@ -3098,6 +3133,14 @@ void QDeclarativeListView::itemsMoved(int from, int to, int count) // Ensure we don't cause an ugly list scroll. d->visibleItems.first()->setPosition(d->visibleItems.first()->position() + moveBy); + d->updateSections(); + d->layout(); +} + +void QDeclarativeListView::itemsChanged(int, int) +{ + Q_D(QDeclarativeListView); + d->updateSections(); d->layout(); } diff --git a/src/declarative/graphicsitems/qdeclarativelistview_p.h b/src/declarative/graphicsitems/qdeclarativelistview_p.h index 735b248..2678b90 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview_p.h +++ b/src/declarative/graphicsitems/qdeclarativelistview_p.h @@ -250,11 +250,13 @@ protected: virtual void componentComplete(); private Q_SLOTS: + void updateSections(); void refill(); void trackedPositionChanged(); void itemsInserted(int index, int count); void itemsRemoved(int index, int count); void itemsMoved(int from, int to, int count); + void itemsChanged(int index, int count); void modelReset(); void destroyRemoved(); void createdItem(int index, QDeclarativeItem *item); diff --git a/src/declarative/graphicsitems/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp index a0208ef..1533d55 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea.cpp +++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp @@ -557,6 +557,7 @@ void QDeclarativeMouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) ungrabMouse(); setKeepMouseGrab(false); } + d->doubleClick = false; } void QDeclarativeMouseArea::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) @@ -565,14 +566,12 @@ void QDeclarativeMouseArea::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *even if (!d->absorb) { QDeclarativeItem::mouseDoubleClickEvent(event); } else { + d->doubleClick = true; d->saveEvent(event); QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false); me.setAccepted(d->isDoubleClickConnected()); emit this->doubleClicked(&me); - if (!me.isAccepted()) { - // Only deliver the press event if we haven't accepted the double click. - QDeclarativeItem::mouseDoubleClickEvent(event); - } + QDeclarativeItem::mouseDoubleClickEvent(event); } } @@ -841,7 +840,8 @@ bool QDeclarativeMouseArea::setPressed(bool p) d->pressed = p; QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress); if (d->pressed) { - emit pressed(&me); + if (!d->doubleClick) + emit pressed(&me); me.setX(d->lastPos.x()); me.setY(d->lastPos.y()); emit mousePositionChanged(&me); @@ -849,7 +849,7 @@ bool QDeclarativeMouseArea::setPressed(bool p) emit released(&me); me.setX(d->lastPos.x()); me.setY(d->lastPos.y()); - if (isclick && !d->longPress) + if (isclick && !d->longPress && !d->doubleClick) emit clicked(&me); } diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h index 48a56d9..06a01d3 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h @@ -68,7 +68,7 @@ class QDeclarativeMouseAreaPrivate : public QDeclarativeItemPrivate public: QDeclarativeMouseAreaPrivate() : absorb(true), hovered(false), pressed(false), longPress(false), - moved(false), stealMouse(false), drag(0) + moved(false), stealMouse(false), doubleClick(false), drag(0) { } @@ -109,6 +109,7 @@ public: bool dragX : 1; bool dragY : 1; bool stealMouse : 1; + bool doubleClick : 1; QDeclarativeDrag *drag; QPointF startScene; qreal startX; diff --git a/src/declarative/graphicsitems/qdeclarativepainteditem.cpp b/src/declarative/graphicsitems/qdeclarativepainteditem.cpp index a6db1fa..b470b3a 100644 --- a/src/declarative/graphicsitems/qdeclarativepainteditem.cpp +++ b/src/declarative/graphicsitems/qdeclarativepainteditem.cpp @@ -44,7 +44,6 @@ #include <QDebug> #include <QPen> -#include <QFile> #include <QEvent> #include <QApplication> #include <QGraphicsSceneMouseEvent> diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp index 31943b2..81c84f5 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview.cpp +++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp @@ -1112,16 +1112,16 @@ void QDeclarativePathViewPrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent if (!interactive || !lastPosTime.isValid()) return; + qreal newPc; + QPointF pathPoint = pointNear(event->pos(), &newPc); if (!stealMouse) { - QPointF delta = event->pos() - startPoint; + QPointF delta = pathPoint - startPoint; if (qAbs(delta.x()) > QApplication::startDragDistance() || qAbs(delta.y()) > QApplication::startDragDistance()) stealMouse = true; } if (stealMouse) { moveReason = QDeclarativePathViewPrivate::Mouse; - qreal newPc; - pointNear(event->pos(), &newPc); qreal diff = (newPc - startPc)*modelCount*mappedRange; if (diff) { setOffset(offset + diff); diff --git a/src/declarative/graphicsitems/qdeclarativetext.cpp b/src/declarative/graphicsitems/qdeclarativetext.cpp index 65f1564..308aefa 100644 --- a/src/declarative/graphicsitems/qdeclarativetext.cpp +++ b/src/declarative/graphicsitems/qdeclarativetext.cpp @@ -82,15 +82,16 @@ private: static QSet<QUrl> errors; }; -DEFINE_BOOL_CONFIG_OPTION(disableImageCache, QML_DISABLE_IMAGE_CACHE); +DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE); QDeclarativeTextPrivate::QDeclarativeTextPrivate() -: color((QRgb)0), style(QDeclarativeText::Normal), - hAlign(QDeclarativeText::AlignLeft), vAlign(QDeclarativeText::AlignTop), elideMode(QDeclarativeText::ElideNone), - imgDirty(true), dirty(true), richText(false), singleline(false), cache(true), internalWidthUpdate(false), doc(0), - format(QDeclarativeText::AutoText), wrapMode(QDeclarativeText::NoWrap) +: color((QRgb)0), style(QDeclarativeText::Normal), hAlign(QDeclarativeText::AlignLeft), + vAlign(QDeclarativeText::AlignTop), elideMode(QDeclarativeText::ElideNone), + format(QDeclarativeText::AutoText), wrapMode(QDeclarativeText::NoWrap), imageCacheDirty(true), + updateOnComponentComplete(true), richText(false), singleline(false), cacheAllTextAsImage(true), + internalWidthUpdate(false), doc(0) { - cache = !disableImageCache(); + cacheAllTextAsImage = enableImageCache(); QGraphicsItemPrivate::acceptedMouseButtons = Qt::LeftButton; QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents; } @@ -151,7 +152,6 @@ void QTextDocumentWithImageResources::requestFinished() #endif QDeclarativeTextPrivate *d = QDeclarativeTextPrivate::get(textItem); d->updateLayout(); - d->markImgDirty(); } } @@ -172,6 +172,382 @@ void QTextDocumentWithImageResources::setText(const QString &text) QSet<QUrl> QTextDocumentWithImageResources::errors; +QDeclarativeTextPrivate::~QDeclarativeTextPrivate() +{ +} + +void QDeclarativeTextPrivate::updateLayout() +{ + Q_Q(QDeclarativeText); + if (!q->isComponentComplete()) { + updateOnComponentComplete = true; + return; + } + + // Setup instance of QTextLayout for all cases other than richtext + if (!richText) { + layout.clearLayout(); + layout.setFont(font); + if (format != QDeclarativeText::StyledText) { + QString tmp = text; + tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); + singleline = !tmp.contains(QChar::LineSeparator); + if (singleline && elideMode != QDeclarativeText::ElideNone && q->widthValid()) { + QFontMetrics fm(font); + tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width()); // XXX still worth layout...? + } + layout.setText(tmp); + } else { + singleline = false; + QDeclarativeStyledText::parse(text, layout); + } + } + + updateSize(); +} + +void QDeclarativeTextPrivate::updateSize() +{ + Q_Q(QDeclarativeText); + + if (!q->isComponentComplete()) { + updateOnComponentComplete = true; + return; + } + + invalidateImageCache(); + + QFontMetrics fm(font); + if (text.isEmpty()) { + q->setImplicitHeight(fm.height()); + emit q->paintedSizeChanged(); + return; + } + + int dy = q->height(); + QSize size(0, 0); + + //setup instance of QTextLayout for all cases other than richtext + if (!richText) { + size = setupTextLayout(); + if (layedOutTextSize != size) { + q->prepareGeometryChange(); + layedOutTextSize = size; + } + dy -= size.height(); + } else { + singleline = false; // richtext can't elide or be optimized for single-line case + ensureDoc(); + doc->setDefaultFont(font); + QTextOption option((Qt::Alignment)int(hAlign | vAlign)); + option.setWrapMode(QTextOption::WrapMode(wrapMode)); + doc->setDefaultTextOption(option); + if (wrapMode != QDeclarativeText::NoWrap && q->widthValid()) + doc->setTextWidth(q->width()); + else + doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug) + dy -= (int)doc->size().height(); + QSize dsize = doc->size().toSize(); + if (dsize != layedOutTextSize) { + q->prepareGeometryChange(); + layedOutTextSize = dsize; + } + size = QSize(int(doc->idealWidth()),dsize.height()); + } + int yoff = 0; + + if (q->heightValid()) { + if (vAlign == QDeclarativeText::AlignBottom) + yoff = dy; + else if (vAlign == QDeclarativeText::AlignVCenter) + yoff = dy/2; + } + q->setBaselineOffset(fm.ascent() + yoff); + + //### need to comfirm cost of always setting these for richText + internalWidthUpdate = true; + q->setImplicitWidth(size.width()); + internalWidthUpdate = false; + q->setImplicitHeight(size.height()); + emit q->paintedSizeChanged(); +} + +/*! + Lays out the QDeclarativeTextPrivate::layout QTextLayout in the constraints of the QDeclarativeText. + + Returns the size of the final text. This can be used to position the text vertically (the text is + already absolutely positioned horizontally). +*/ +QSize QDeclarativeTextPrivate::setupTextLayout() +{ + // ### text layout handling should be profiled and optimized as needed + // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine); + + Q_Q(QDeclarativeText); + layout.setCacheEnabled(true); + + int height = 0; + qreal widthUsed = 0; + qreal lineWidth = 0; + + //set manual width + if ((wrapMode != QDeclarativeText::NoWrap || elideMode != QDeclarativeText::ElideNone) && q->widthValid()) + lineWidth = q->width(); + + QTextOption textOption = layout.textOption(); + textOption.setWrapMode(QTextOption::WrapMode(wrapMode)); + layout.setTextOption(textOption); + + layout.beginLayout(); + while (1) { + QTextLine line = layout.createLine(); + if (!line.isValid()) + break; + + if ((wrapMode != QDeclarativeText::NoWrap || elideMode != QDeclarativeText::ElideNone) && q->widthValid()) + line.setLineWidth(lineWidth); + } + layout.endLayout(); + + for (int i = 0; i < layout.lineCount(); ++i) { + QTextLine line = layout.lineAt(i); + widthUsed = qMax(widthUsed, line.naturalTextWidth()); + } + + qreal layoutWidth = q->widthValid()?q->width():widthUsed; + + int x = 0; + for (int i = 0; i < layout.lineCount(); ++i) { + QTextLine line = layout.lineAt(i); + line.setPosition(QPointF(0, height)); + height += int(line.height()); + + if (!cacheAllTextAsImage) { + if (hAlign == QDeclarativeText::AlignLeft) { + x = 0; + } else if (hAlign == QDeclarativeText::AlignRight) { + x = layoutWidth - (int)line.naturalTextWidth(); + } else if (hAlign == QDeclarativeText::AlignHCenter) { + x = (layoutWidth - (int)line.naturalTextWidth()) / 2; + } + line.setPosition(QPoint(x, (int)line.y())); + } + } + + return QSize(qCeil(widthUsed), height); +} + +/*! + Returns a painted version of the QDeclarativeTextPrivate::layout QTextLayout. + If \a drawStyle is true, the style color overrides all colors in the document. +*/ +QPixmap QDeclarativeTextPrivate::textLayoutImage(bool drawStyle) +{ + //do layout + QSize size = layedOutTextSize; + + int x = 0; + for (int i = 0; i < layout.lineCount(); ++i) { + QTextLine line = layout.lineAt(i); + if (hAlign == QDeclarativeText::AlignLeft) { + x = 0; + } else if (hAlign == QDeclarativeText::AlignRight) { + x = size.width() - (int)line.naturalTextWidth(); + } else if (hAlign == QDeclarativeText::AlignHCenter) { + x = (size.width() - (int)line.naturalTextWidth()) / 2; + } + line.setPosition(QPoint(x, (int)line.y())); + } + + //paint text + QPixmap img(size); + if (!size.isEmpty()) { + img.fill(Qt::transparent); +#ifdef Q_WS_MAC + bool oldSmooth = qt_applefontsmoothing_enabled; + qt_applefontsmoothing_enabled = false; +#endif + QPainter p(&img); +#ifdef Q_WS_MAC + qt_applefontsmoothing_enabled = oldSmooth; +#endif + drawTextLayout(&p, QPointF(0,0), drawStyle); + } + return img; +} + +/*! + Paints the QDeclarativeTextPrivate::layout QTextLayout into \a painter at \a pos. If + \a drawStyle is true, the style color overrides all colors in the document. +*/ +void QDeclarativeTextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle) +{ + if (drawStyle) + painter->setPen(styleColor); + else + painter->setPen(color); + painter->setFont(font); + layout.draw(painter, pos); +} + +/*! + Returns a painted version of the QDeclarativeTextPrivate::doc QTextDocument. + If \a drawStyle is true, the style color overrides all colors in the document. +*/ +QPixmap QDeclarativeTextPrivate::textDocumentImage(bool drawStyle) +{ + QSize size = doc->size().toSize(); + + //paint text + QPixmap img(size); + img.fill(Qt::transparent); +#ifdef Q_WS_MAC + bool oldSmooth = qt_applefontsmoothing_enabled; + qt_applefontsmoothing_enabled = false; +#endif + QPainter p(&img); +#ifdef Q_WS_MAC + qt_applefontsmoothing_enabled = oldSmooth; +#endif + + QAbstractTextDocumentLayout::PaintContext context; + + QTextOption oldOption(doc->defaultTextOption()); + if (drawStyle) { + context.palette.setColor(QPalette::Text, styleColor); + QTextOption colorOption(doc->defaultTextOption()); + colorOption.setFlags(QTextOption::SuppressColors); + doc->setDefaultTextOption(colorOption); + } else { + context.palette.setColor(QPalette::Text, color); + } + doc->documentLayout()->draw(&p, context); + if (drawStyle) + doc->setDefaultTextOption(oldOption); + return img; +} + +/*! + Mark the image cache as dirty. +*/ +void QDeclarativeTextPrivate::invalidateImageCache() +{ + Q_Q(QDeclarativeText); + + if (imageCacheDirty) + return; + + imageCacheDirty = true; + imageCache = QPixmap(); + + if (q->isComponentComplete()) + q->update(); +} + +/*! + Tests if the image cache is dirty, and repaints it if it is. +*/ +void QDeclarativeTextPrivate::checkImageCache() +{ + if (!imageCacheDirty) + return; + + if (text.isEmpty()) { + + imageCache = QPixmap(); + + } else { + + QPixmap textImage; + QPixmap styledImage; + + if (richText) { + textImage = textDocumentImage(false); + if (style != QDeclarativeText::Normal) + styledImage = textDocumentImage(true); //### should use styleColor + } else { + textImage = textLayoutImage(false); + if (style != QDeclarativeText::Normal) + styledImage = textLayoutImage(true); //### should use styleColor + } + + switch (style) { + case QDeclarativeText::Outline: + imageCache = drawOutline(textImage, styledImage); + break; + case QDeclarativeText::Sunken: + imageCache = drawOutline(textImage, styledImage, -1); + break; + case QDeclarativeText::Raised: + imageCache = drawOutline(textImage, styledImage, 1); + break; + default: + imageCache = textImage; + break; + } + + } + + imageCacheDirty = false; +} + +/*! + Ensures the QDeclarativeTextPrivate::doc variable is set to a valid text document +*/ +void QDeclarativeTextPrivate::ensureDoc() +{ + if (!doc) { + Q_Q(QDeclarativeText); + doc = new QTextDocumentWithImageResources(q); + doc->setDocumentMargin(0); + } +} + +/*! + Draw \a styleSource as an outline around \a source and return the new image. +*/ +QPixmap QDeclarativeTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource) +{ + QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2); + img.fill(Qt::transparent); + + QPainter ppm(&img); + + QPoint pos(0, 0); + pos += QPoint(-1, 0); + ppm.drawPixmap(pos, styleSource); + pos += QPoint(2, 0); + ppm.drawPixmap(pos, styleSource); + pos += QPoint(-1, -1); + ppm.drawPixmap(pos, styleSource); + pos += QPoint(0, 2); + ppm.drawPixmap(pos, styleSource); + + pos += QPoint(0, -1); + ppm.drawPixmap(pos, source); + ppm.end(); + + return img; +} + +/*! + Draw \a styleSource below \a source at \a yOffset and return the new image. +*/ +QPixmap QDeclarativeTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset) +{ + QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2); + img.fill(Qt::transparent); + + QPainter ppm(&img); + + ppm.drawPixmap(QPoint(0, yOffset), styleSource); + ppm.drawPixmap(0, 0, source); + + ppm.end(); + + return img; +} + /*! \qmlclass Text QDeclarativeText \ingroup qml-basic-visual-elements @@ -211,10 +587,44 @@ QDeclarativeText::~QDeclarativeText() { } +/*! + \qmlproperty bool Text::clip + This property holds whether the text is clipped. -QDeclarativeTextPrivate::~QDeclarativeTextPrivate() -{ -} + Note that if the text does not fit in the bounding rectangle it will be abruptly chopped. + + If you want to display potentially long text in a limited space, you probably want to use \c elide instead. +*/ + +/*! + \qmlproperty bool Text::smooth + + This property holds whether the text is smoothly scaled or transformed. + + Smooth filtering gives better visual quality, but is slower. If + the item is displayed at its natural size, this property has no visual or + performance effect. + + \note Generally scaling artifacts are only visible if the item is stationary on + the screen. A common pattern when animating an item is to disable smooth + filtering at the beginning of the animation and reenable it at the conclusion. +*/ + +/*! + \qmlsignal Text::onLinkActivated(string link) + + This handler is called when the user clicks on a link embedded in the text. + The link must be in rich text or HTML format and the + \a link string provides access to the particular link. + + \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0 + + The example code will display the text + "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}." + + Clicking on the highlighted link will output + \tt{http://qt.nokia.com link activated} to the console. +*/ /*! \qmlproperty string Text::font.family @@ -320,7 +730,6 @@ QDeclarativeTextPrivate::~QDeclarativeTextPrivate() Text { text: "Hello"; font.capitalization: Font.AllLowercase } \endqml */ - QFont QDeclarativeText::font() const { Q_D(const QDeclarativeText); @@ -334,30 +743,9 @@ void QDeclarativeText::setFont(const QFont &font) return; d->font = font; - d->updateLayout(); - d->markImgDirty(); - emit fontChanged(d->font); -} - -void QDeclarativeText::setText(const QString &n) -{ - Q_D(QDeclarativeText); - if (d->text == n) - return; - d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n)); - if (d->richText) { - if (isComponentComplete()) { - d->ensureDoc(); - d->doc->setText(n); - } - } - - d->text = n; - d->updateLayout(); - d->markImgDirty(); - emit textChanged(d->text); + emit fontChanged(d->font); } /*! @@ -374,17 +762,25 @@ QString QDeclarativeText::text() const return d->text; } -void QDeclarativeText::setColor(const QColor &color) +void QDeclarativeText::setText(const QString &n) { Q_D(QDeclarativeText); - if (d->color == color) + if (d->text == n) return; - d->color = color; - d->markImgDirty(); - emit colorChanged(d->color); + d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n)); + if (d->richText && isComponentComplete()) { + d->ensureDoc(); + d->doc->setText(n); + } + + d->text = n; + d->updateLayout(); + + emit textChanged(d->text); } + /*! \qmlproperty color Text::color @@ -398,13 +794,23 @@ void QDeclarativeText::setColor(const QColor &color) Text { color: "steelblue"; ... } \endqml */ - QColor QDeclarativeText::color() const { Q_D(const QDeclarativeText); return d->color; } +void QDeclarativeText::setColor(const QColor &color) +{ + Q_D(QDeclarativeText); + if (d->color == color) + return; + + d->color = color; + d->invalidateImageCache(); + emit colorChanged(d->color); +} + /*! \qmlproperty enumeration Text::style @@ -445,21 +851,10 @@ void QDeclarativeText::setStyle(QDeclarativeText::TextStyle style) if (isComponentComplete() && (d->style == Normal || style == Normal)) prepareGeometryChange(); d->style = style; - d->markImgDirty(); + d->invalidateImageCache(); emit styleChanged(d->style); } -void QDeclarativeText::setStyleColor(const QColor &color) -{ - Q_D(QDeclarativeText); - if (d->styleColor == color) - return; - - d->styleColor = color; - d->markImgDirty(); - emit styleColorChanged(d->styleColor); -} - /*! \qmlproperty color Text::styleColor @@ -481,6 +876,18 @@ QColor QDeclarativeText::styleColor() const return d->styleColor; } +void QDeclarativeText::setStyleColor(const QColor &color) +{ + Q_D(QDeclarativeText); + if (d->styleColor == color) + return; + + d->styleColor = color; + d->invalidateImageCache(); + emit styleColorChanged(d->styleColor); +} + + /*! \qmlproperty enumeration Text::horizontalAlignment \qmlproperty enumeration Text::verticalAlignment @@ -511,7 +918,10 @@ void QDeclarativeText::setHAlign(HAlignment align) if (isComponentComplete()) prepareGeometryChange(); + d->hAlign = align; + d->updateLayout(); + emit horizontalAlignmentChanged(align); } @@ -559,9 +969,8 @@ void QDeclarativeText::setWrapMode(WrapMode mode) return; d->wrapMode = mode; - d->updateLayout(); - d->markImgDirty(); + emit wrapModeChanged(); } @@ -621,7 +1030,6 @@ Column { \o \image declarative-textformat.png \endtable */ - QDeclarativeText::TextFormat QDeclarativeText::textFormat() const { Q_D(const QDeclarativeText); @@ -637,19 +1045,13 @@ void QDeclarativeText::setTextFormat(TextFormat format) bool wasRich = d->richText; d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text)); - if (wasRich && !d->richText) { - //### delete control? (and vice-versa below) - d->updateLayout(); - d->markImgDirty(); - } else if (!wasRich && d->richText) { - if (isComponentComplete()) { - d->ensureDoc(); - d->doc->setText(d->text); - } - d->updateLayout(); - d->markImgDirty(); + if (!wasRich && d->richText && isComponentComplete()) { + d->ensureDoc(); + d->doc->setText(d->text); } + d->updateLayout(); + emit textFormatChanged(d->format); } @@ -688,12 +1090,12 @@ void QDeclarativeText::setElideMode(QDeclarativeText::TextElideMode mode) return; d->elideMode = mode; - d->updateLayout(); - d->markImgDirty(); + emit elideModeChanged(d->elideMode); } +/*! \internal */ QRectF QDeclarativeText::boundingRect() const { Q_D(const QDeclarativeText); @@ -704,7 +1106,7 @@ QRectF QDeclarativeText::boundingRect() const int x = 0; int y = 0; - QSize size = d->cachedLayoutSize; + QSize size = d->layedOutTextSize; if (d->style != Normal) size += QSize(2,2); @@ -737,117 +1139,23 @@ QRectF QDeclarativeText::boundingRect() const return QRectF(x,y,size.width(),size.height()); } -void QDeclarativeText::geometryChanged(const QRectF &newGeometry, - const QRectF &oldGeometry) +/*! \internal */ +void QDeclarativeText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { Q_D(QDeclarativeText); - if (!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width()) { - if (d->wrapMode != QDeclarativeText::NoWrap || d->elideMode != QDeclarativeText::ElideNone) { - //re-elide if needed - if (d->singleline && d->elideMode != QDeclarativeText::ElideNone && - isComponentComplete() && widthValid()) { - - QFontMetrics fm(d->font); - QString tmp = fm.elidedText(d->text,(Qt::TextElideMode)d->elideMode,width()); // XXX still worth layout...? - d->layout.setText(tmp); - } + if (!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width() && + (d->wrapMode != QDeclarativeText::NoWrap || d->elideMode != QDeclarativeText::ElideNone)) { - d->imgDirty = true; + if (d->singleline && d->elideMode != QDeclarativeText::ElideNone && widthValid()) { + // We need to re-elide + d->updateLayout(); + } else { + // We just need to re-layout d->updateSize(); } } - QDeclarativeItem::geometryChanged(newGeometry, oldGeometry); -} - -void QDeclarativeTextPrivate::updateLayout() -{ - Q_Q(QDeclarativeText); - if (q->isComponentComplete()) { - //setup instance of QTextLayout for all cases other than richtext - if (!richText) { - layout.clearLayout(); - layout.setFont(font); - if (format != QDeclarativeText::StyledText) { - QString tmp = text; - tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); - singleline = !tmp.contains(QChar::LineSeparator); - if (singleline && elideMode != QDeclarativeText::ElideNone && q->widthValid()) { - QFontMetrics fm(font); - tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width()); // XXX still worth layout...? - } - layout.setText(tmp); - } else { - singleline = false; - QDeclarativeStyledText::parse(text, layout); - } - } - updateSize(); - } else { - dirty = true; - } -} - - -void QDeclarativeTextPrivate::updateSize() -{ - Q_Q(QDeclarativeText); - if (q->isComponentComplete()) { - QFontMetrics fm(font); - if (text.isEmpty()) { - q->setImplicitHeight(fm.height()); - emit q->paintedSizeChanged(); - return; - } - - int dy = q->height(); - QSize size(0, 0); - - //setup instance of QTextLayout for all cases other than richtext - if (!richText) { - size = setupTextLayout(); - if (cachedLayoutSize != size) { - q->prepareGeometryChange(); - cachedLayoutSize = size; - } - dy -= size.height(); - } else { - singleline = false; // richtext can't elide or be optimized for single-line case - ensureDoc(); - doc->setDefaultFont(font); - QTextOption option((Qt::Alignment)int(hAlign | vAlign)); - option.setWrapMode(QTextOption::WrapMode(wrapMode)); - doc->setDefaultTextOption(option); - if (wrapMode != QDeclarativeText::NoWrap && q->widthValid()) - doc->setTextWidth(q->width()); - else - doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug) - dy -= (int)doc->size().height(); - QSize dsize = doc->size().toSize(); - if (dsize != cachedLayoutSize) { - q->prepareGeometryChange(); - cachedLayoutSize = dsize; - } - size = QSize(int(doc->idealWidth()),dsize.height()); - } - int yoff = 0; - if (q->heightValid()) { - if (vAlign == QDeclarativeText::AlignBottom) - yoff = dy; - else if (vAlign == QDeclarativeText::AlignVCenter) - yoff = dy/2; - } - q->setBaselineOffset(fm.ascent() + yoff); - - //### need to comfirm cost of always setting these for richText - internalWidthUpdate = true; - q->setImplicitWidth(size.width()); - internalWidthUpdate = false; - q->setImplicitHeight(size.height()); - emit q->paintedSizeChanged(); - } else { - dirty = true; - } + QDeclarativeItem::geometryChanged(newGeometry, oldGeometry); } /*! @@ -872,228 +1180,6 @@ qreal QDeclarativeText::paintedHeight() const return implicitHeight(); } - - -// ### text layout handling should be profiled and optimized as needed -// what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine); - -void QDeclarativeTextPrivate::drawOutline() -{ - QPixmap img = QPixmap(imgStyleCache.width()+2,imgStyleCache.height()+2); - img.fill(Qt::transparent); - - QPainter ppm(&img); - - QPoint pos(imgCache.rect().topLeft()); - pos += QPoint(-1, 0); - ppm.drawPixmap(pos, imgStyleCache); - pos += QPoint(2, 0); - ppm.drawPixmap(pos, imgStyleCache); - pos += QPoint(-1, -1); - ppm.drawPixmap(pos, imgStyleCache); - pos += QPoint(0, 2); - ppm.drawPixmap(pos, imgStyleCache); - - pos += QPoint(0, -1); - ppm.drawPixmap(pos, imgCache); - ppm.end(); - - imgCache = img; -} - -void QDeclarativeTextPrivate::drawOutline(int yOffset) -{ - QPixmap img = QPixmap(imgStyleCache.width()+2,imgStyleCache.height()+2); - img.fill(Qt::transparent); - - QPainter ppm(&img); - - QPoint pos(imgCache.rect().topLeft()); - pos += QPoint(0, yOffset); - ppm.drawPixmap(pos, imgStyleCache); - - pos += QPoint(0, -yOffset); - ppm.drawPixmap(pos, imgCache); - ppm.end(); - - imgCache = img; -} - -QSize QDeclarativeTextPrivate::setupTextLayout() -{ - Q_Q(QDeclarativeText); - layout.setCacheEnabled(true); - - int height = 0; - qreal widthUsed = 0; - qreal lineWidth = 0; - - //set manual width - if ((wrapMode != QDeclarativeText::NoWrap || elideMode != QDeclarativeText::ElideNone) && q->widthValid()) - lineWidth = q->width(); - - QTextOption textOption = layout.textOption(); - textOption.setWrapMode(QTextOption::WrapMode(wrapMode)); - layout.setTextOption(textOption); - - layout.beginLayout(); - - while (1) { - QTextLine line = layout.createLine(); - if (!line.isValid()) - break; - - if ((wrapMode != QDeclarativeText::NoWrap || elideMode != QDeclarativeText::ElideNone) && q->widthValid()) - line.setLineWidth(lineWidth); - } - layout.endLayout(); - - int x = 0; - for (int i = 0; i < layout.lineCount(); ++i) { - QTextLine line = layout.lineAt(i); - widthUsed = qMax(widthUsed, line.naturalTextWidth()); - line.setPosition(QPointF(0, height)); - height += int(line.height()); - - if (!cache) { - if (hAlign == QDeclarativeText::AlignLeft) { - x = 0; - } else if (hAlign == QDeclarativeText::AlignRight) { - x = q->width() - (int)line.naturalTextWidth(); - } else if (hAlign == QDeclarativeText::AlignHCenter) { - x = (q->width() - (int)line.naturalTextWidth()) / 2; - } - line.setPosition(QPoint(x, (int)line.y())); - } - } - - return QSize(qCeil(widthUsed), height); -} - -QPixmap QDeclarativeTextPrivate::wrappedTextImage(bool drawStyle) -{ - //do layout - QSize size = cachedLayoutSize; - - int x = 0; - for (int i = 0; i < layout.lineCount(); ++i) { - QTextLine line = layout.lineAt(i); - if (hAlign == QDeclarativeText::AlignLeft) { - x = 0; - } else if (hAlign == QDeclarativeText::AlignRight) { - x = size.width() - (int)line.naturalTextWidth(); - } else if (hAlign == QDeclarativeText::AlignHCenter) { - x = (size.width() - (int)line.naturalTextWidth()) / 2; - } - line.setPosition(QPoint(x, (int)line.y())); - } - - //paint text - QPixmap img(size); - if (!size.isEmpty()) { - img.fill(Qt::transparent); -#ifdef Q_WS_MAC - bool oldSmooth = qt_applefontsmoothing_enabled; - qt_applefontsmoothing_enabled = false; -#endif - QPainter p(&img); -#ifdef Q_WS_MAC - qt_applefontsmoothing_enabled = oldSmooth; -#endif - drawWrappedText(&p, QPointF(0,0), drawStyle); - } - return img; -} - -void QDeclarativeTextPrivate::drawWrappedText(QPainter *p, const QPointF &pos, bool drawStyle) -{ - if (drawStyle) - p->setPen(styleColor); - else - p->setPen(color); - p->setFont(font); - layout.draw(p , pos); -} - -QPixmap QDeclarativeTextPrivate::richTextImage(bool drawStyle) -{ - QSize size = doc->size().toSize(); - - //paint text - QPixmap img(size); - img.fill(Qt::transparent); -#ifdef Q_WS_MAC - bool oldSmooth = qt_applefontsmoothing_enabled; - qt_applefontsmoothing_enabled = false; -#endif - QPainter p(&img); -#ifdef Q_WS_MAC - qt_applefontsmoothing_enabled = oldSmooth; -#endif - - QAbstractTextDocumentLayout::PaintContext context; - - QTextOption oldOption(doc->defaultTextOption()); - if (drawStyle) { - context.palette.setColor(QPalette::Text, styleColor); - QTextOption colorOption(doc->defaultTextOption()); - colorOption.setFlags(QTextOption::SuppressColors); - doc->setDefaultTextOption(colorOption); - } else { - context.palette.setColor(QPalette::Text, color); - } - doc->documentLayout()->draw(&p, context); - if (drawStyle) - doc->setDefaultTextOption(oldOption); - return img; -} - -void QDeclarativeTextPrivate::checkImgCache() -{ - if (!imgDirty) - return; - - bool empty = text.isEmpty(); - QPixmap newImgCache; - if (empty) { - imgStyleCache = QPixmap(); - } else if (richText) { - newImgCache = richTextImage(false); - if (style != QDeclarativeText::Normal) - imgStyleCache = richTextImage(true); //### should use styleColor - } else { - newImgCache = wrappedTextImage(false); - if (style != QDeclarativeText::Normal) - imgStyleCache = wrappedTextImage(true); //### should use styleColor - } - imgCache = newImgCache; - if (!empty) - switch (style) { - case QDeclarativeText::Outline: - drawOutline(); - break; - case QDeclarativeText::Sunken: - drawOutline(-1); - break; - case QDeclarativeText::Raised: - drawOutline(1); - break; - default: - break; - } - - imgDirty = false; -} - -void QDeclarativeTextPrivate::ensureDoc() -{ - if (!doc) { - Q_Q(QDeclarativeText); - doc = new QTextDocumentWithImageResources(q); - doc->setDocumentMargin(0); - } -} - /*! Returns the number of resources (images) that are being loaded asynchronously. */ @@ -1103,22 +1189,14 @@ int QDeclarativeText::resourcesLoading() const return d->doc ? d->doc->resourcesLoading() : 0; } -/*! - \qmlproperty bool Text::clip - This property holds whether the text is clipped. - - Note that if the text does not fit in the bounding rectangle it will be abruptly chopped. - - If you want to display potentially long text in a limited space, you probably want to use \c elide instead. -*/ - +/*! \internal */ void QDeclarativeText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) { Q_D(QDeclarativeText); - if (d->cache || d->style != Normal) { - d->checkImgCache(); - if (d->imgCache.isNull()) + if (d->cacheAllTextAsImage || d->style != Normal) { + d->checkImageCache(); + if (d->imageCache.isNull()) return; bool oldAA = p->testRenderHint(QPainter::Antialiasing); @@ -1128,23 +1206,23 @@ void QDeclarativeText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWid QRect br = boundingRect().toRect(); - bool needClip = clip() && (d->imgCache.width() > width() || - d->imgCache.height() > height()); + bool needClip = clip() && (d->imageCache.width() > width() || + d->imageCache.height() > height()); if (needClip) - p->drawPixmap(0, 0, width(), height(), d->imgCache, -br.x(), -br.y(), width(), height()); + p->drawPixmap(0, 0, width(), height(), d->imageCache, -br.x(), -br.y(), width(), height()); else - p->drawPixmap(br.x(), br.y(), d->imgCache); + p->drawPixmap(br.x(), br.y(), d->imageCache); if (d->smooth) { p->setRenderHint(QPainter::Antialiasing, oldAA); p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth); } } else { - qreal y = boundingRect().y(); + QRectF bounds = boundingRect(); - bool needClip = clip() && (d->cachedLayoutSize.width() > width() || - d->cachedLayoutSize.height() > height()); + bool needClip = clip() && (d->layedOutTextSize.width() > width() || + d->layedOutTextSize.height() > height()); if (needClip) { p->save(); @@ -1153,49 +1231,35 @@ void QDeclarativeText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWid if (d->richText) { QAbstractTextDocumentLayout::PaintContext context; context.palette.setColor(QPalette::Text, d->color); - p->translate(0, y); + p->translate(bounds.x(), bounds.y()); d->doc->documentLayout()->draw(p, context); - p->translate(0, -y); + p->translate(-bounds.x(), -bounds.y()); } else { - d->drawWrappedText(p, QPointF(0,y), false); + d->drawTextLayout(p, QPointF(0, bounds.y()), false); } - if (needClip) + + if (needClip) { p->restore(); + } } } -/*! - \qmlproperty bool Text::smooth - - This property holds whether the text is smoothly scaled or transformed. - - Smooth filtering gives better visual quality, but is slower. If - the item is displayed at its natural size, this property has no visual or - performance effect. - - \note Generally scaling artifacts are only visible if the item is stationary on - the screen. A common pattern when animating an item is to disable smooth - filtering at the beginning of the animation and reenable it at the conclusion. -*/ - +/*! \internal */ void QDeclarativeText::componentComplete() { Q_D(QDeclarativeText); QDeclarativeItem::componentComplete(); - if (d->dirty) { + if (d->updateOnComponentComplete) { + d->updateOnComponentComplete = false; if (d->richText) { d->ensureDoc(); d->doc->setText(d->text); } d->updateLayout(); - d->dirty = false; } } -/*! - \overload - Handles the given mouse \a event. - */ +/*! \internal */ void QDeclarativeText::mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeText); @@ -1214,26 +1278,7 @@ void QDeclarativeText::mousePressEvent(QGraphicsSceneMouseEvent *event) } -/*! - \qmlsignal Text::onLinkActivated(string link) - - This handler is called when the user clicks on a link embedded in the text. - The link must be in rich text or HTML format and the - \a link string provides access to the particular link. - - \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0 - - The example code will display the text - "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}." - - Clicking on the highlighted link will output - \tt{http://qt.nokia.com link activated} to the console. -*/ - -/*! - \overload - Handles the given mouse \a event. - */ +/*! \internal */ void QDeclarativeText::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeText); diff --git a/src/declarative/graphicsitems/qdeclarativetext_p_p.h b/src/declarative/graphicsitems/qdeclarativetext_p_p.h index db68558..e37f477 100644 --- a/src/declarative/graphicsitems/qdeclarativetext_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativetext_p_p.h @@ -74,24 +74,8 @@ public: ~QDeclarativeTextPrivate(); - void ensureDoc(); void updateSize(); void updateLayout(); - void markImgDirty() { - Q_Q(QDeclarativeText); - imgDirty = true; - if (q->isComponentComplete()) - q->update(); - } - void checkImgCache(); - - void drawOutline(); - void drawOutline(int yOffset); - - QPixmap wrappedTextImage(bool drawStyle); - void drawWrappedText(QPainter *p, const QPointF &pos, bool drawStyle); - QPixmap richTextImage(bool drawStyle); - QSize setupTextLayout(); QString text; QFont font; @@ -99,23 +83,37 @@ public: QDeclarativeText::TextStyle style; QColor styleColor; QString activeLink; - QPixmap imgCache; - QPixmap imgStyleCache; QDeclarativeText::HAlignment hAlign; QDeclarativeText::VAlignment vAlign; QDeclarativeText::TextElideMode elideMode; - bool imgDirty:1; - bool dirty:1; + QDeclarativeText::TextFormat format; + QDeclarativeText::WrapMode wrapMode; + + void invalidateImageCache(); + void checkImageCache(); + QPixmap imageCache; + + bool imageCacheDirty:1; + bool updateOnComponentComplete:1; bool richText:1; bool singleline:1; - bool cache:1; + bool cacheAllTextAsImage:1; bool internalWidthUpdate:1; + + QSize layedOutTextSize; + + void ensureDoc(); + QPixmap textDocumentImage(bool drawStyle); QTextDocumentWithImageResources *doc; + + QSize setupTextLayout(); + QPixmap textLayoutImage(bool drawStyle); + void drawTextLayout(QPainter *p, const QPointF &pos, bool drawStyle); QDeclarativeTextLayout layout; - QSize cachedLayoutSize; - QDeclarativeText::TextFormat format; - QDeclarativeText::WrapMode wrapMode; - + + static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource); + static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset); + static inline QDeclarativeTextPrivate *get(QDeclarativeText *t) { return t->d_func(); } diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index 6f5608a..e05f4e4 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -319,6 +319,7 @@ void QDeclarativeTextEdit::setTextFormat(TextFormat format) updateSize(); } d->format = format; + d->control->setAcceptRichText(d->format != PlainText); emit textFormatChanged(d->format); } diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index 637dd77..0903427 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -1464,6 +1464,7 @@ void QDeclarativeTextInputPrivate::init() void QDeclarativeTextInput::cursorPosChanged() { Q_D(QDeclarativeTextInput); + d->updateHorizontalScroll(); updateRect();//TODO: Only update rect between pos's updateMicroFocus(); emit cursorPositionChanged(); diff --git a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp index 439f500..e569dd2 100644 --- a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp @@ -403,6 +403,8 @@ public: QDeclarativeListAccessor *m_listAccessor; QModelIndex m_root; + QList<QByteArray> watchedRoles; + QList<int> watchedRoleIds; }; class QDeclarativeVisualDataModelDataMetaObject : public QDeclarativeOpenMetaObject @@ -1170,10 +1172,25 @@ int QDeclarativeVisualDataModel::indexOf(QDeclarativeItem *item, QObject *) cons return -1; } +void QDeclarativeVisualDataModel::setWatchedRoles(QList<QByteArray> roles) +{ + Q_D(QDeclarativeVisualDataModel); + d->watchedRoles = roles; + d->watchedRoleIds.clear(); +} + void QDeclarativeVisualDataModel::_q_itemsChanged(int index, int count, const QList<int> &roles) { Q_D(QDeclarativeVisualDataModel); + bool changed = false; + if (!d->watchedRoles.isEmpty() && d->watchedRoleIds.isEmpty()) { + foreach (QByteArray r, d->watchedRoles) { + if (d->m_roleNames.contains(r)) + d->watchedRoleIds << d->m_roleNames.value(r); + } + } + for (QHash<int,QDeclarativeVisualDataModelPrivate::ObjectRef>::ConstIterator iter = d->m_cache.begin(); iter != d->m_cache.end(); ++iter) { const int idx = iter.key(); @@ -1183,6 +1200,8 @@ void QDeclarativeVisualDataModel::_q_itemsChanged(int index, int count, QDeclarativeVisualDataModelData *data = d->data(objRef.obj); for (int roleIdx = 0; roleIdx < roles.count(); ++roleIdx) { int role = roles.at(roleIdx); + if (!changed && !d->watchedRoleIds.isEmpty() && d->watchedRoleIds.contains(role)) + changed = true; int propId = data->propForRole(role); if (propId != -1) { if (data->hasValue(propId)) { @@ -1217,6 +1236,8 @@ void QDeclarativeVisualDataModel::_q_itemsChanged(int index, int count, } } } + if (changed) + emit itemsChanged(index, count); } void QDeclarativeVisualDataModel::_q_itemsInserted(int index, int count) diff --git a/src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h b/src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h index f09d8dd..5e187c2 100644 --- a/src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h +++ b/src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h @@ -79,6 +79,7 @@ public: virtual bool completePending() const = 0; virtual void completeItem() = 0; virtual QString stringValue(int, const QString &) = 0; + virtual void setWatchedRoles(QList<QByteArray> roles) = 0; virtual int indexOf(QDeclarativeItem *item, QObject *objectContext) const = 0; @@ -87,6 +88,7 @@ Q_SIGNALS: void itemsInserted(int index, int count); void itemsRemoved(int index, int count); void itemsMoved(int from, int to, int count); + void itemsChanged(int index, int count); void modelReset(); void createdItem(int index, QDeclarativeItem *item); void destroyingItem(QDeclarativeItem *item); @@ -120,6 +122,7 @@ public: virtual bool completePending() const; virtual void completeItem(); virtual QString stringValue(int index, const QString &role); + virtual void setWatchedRoles(QList<QByteArray>) {} virtual int indexOf(QDeclarativeItem *item, QObject *objectContext) const; @@ -174,6 +177,7 @@ public: bool completePending() const; void completeItem(); virtual QString stringValue(int index, const QString &role); + virtual void setWatchedRoles(QList<QByteArray> roles); int indexOf(QDeclarativeItem *item, QObject *objectContext) const; diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index dc28e22..74bc5bd 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -1932,6 +1932,9 @@ bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property { obj->addValueProperty(prop); + if (prop->values.count() > 1) + COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") ); + for (int ii = 0; ii < prop->values.count(); ++ii) { Value *v = prop->values.at(ii); if (v->object) { @@ -2562,8 +2565,8 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, QStringList alias = astNodeToStringList(node); - if (alias.count() != 1 && alias.count() != 2) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id> or <id>.<property>")); + if (alias.count() < 1 || alias.count() > 3) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); if (!compileState.ids.contains(alias.at(0))) COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); @@ -2575,11 +2578,14 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, int propIdx = -1; int flags = 0; bool writable = false; - if (alias.count() == 2) { + if (alias.count() == 2 || alias.count() == 3) { propIdx = idObject->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData()); - if (-1 == propIdx) + if (-1 == propIdx) { COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + } else if (propIdx > 0xFFFF) { + COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds")); + } QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx); if (!aliasProperty.isScriptable()) @@ -2587,6 +2593,22 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, writable = aliasProperty.isWritable(); + if (alias.count() == 3) { + QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()]; + if (!valueType) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + + propIdx |= ((unsigned int)aliasProperty.type()) << 24; + + int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData()); + if (valueTypeIndex == -1) + COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + Q_ASSERT(valueTypeIndex <= 0xFF); + + aliasProperty = valueType->metaObject()->property(valueTypeIndex); + propIdx |= (valueTypeIndex << 16); + } + if (aliasProperty.isEnumType()) typeName = "int"; // Avoid introducing a dependency on the aliased metaobject else diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp index b532b0c..cfef9cf 100644 --- a/src/declarative/qml/qdeclarativecomponent.cpp +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -57,7 +57,6 @@ #include <QStack> #include <QStringList> -#include <QFileInfo> #include <QtCore/qdebug.h> #include <QApplication> diff --git a/src/declarative/qml/qdeclarativedata_p.h b/src/declarative/qml/qdeclarativedata_p.h index e916273..def4188 100644 --- a/src/declarative/qml/qdeclarativedata_p.h +++ b/src/declarative/qml/qdeclarativedata_p.h @@ -64,6 +64,7 @@ class QDeclarativeAbstractBinding; class QDeclarativeContext; class QDeclarativePropertyCache; class QDeclarativeContextData; +class QDeclarativeNotifier; // This class is structured in such a way, that simply zero'ing it is the // default state for elemental object allocations. This is crucial in the // workings of the QDeclarativeInstruction::CreateSimpleObject instruction. @@ -75,20 +76,23 @@ public: : ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), context(0), outerContext(0), bindings(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), - attachedProperties(0), scriptValue(0), objectDataRefCount(0), propertyCache(0), guards(0) { + scriptValue(0), objectDataRefCount(0), propertyCache(0), guards(0), extendedData(0) { init(); } static inline void init() { QAbstractDeclarativeData::destroyed = destroyed; QAbstractDeclarativeData::parentChanged = parentChanged; + QAbstractDeclarativeData::objectNameChanged = objectNameChanged; } static void destroyed(QAbstractDeclarativeData *, QObject *); static void parentChanged(QAbstractDeclarativeData *, QObject *, QObject *); + static void objectNameChanged(QAbstractDeclarativeData *, QObject *); void destroyed(QObject *); void parentChanged(QObject *, QObject *); + void objectNameChanged(QObject *); void setImplicitDestructible() { if (!explicitIndestructibleSet) indestructible = false; @@ -123,8 +127,6 @@ public: QDeclarativeCompiledData *deferredComponent; // Can't this be found from the context? unsigned int deferredIdx; - QHash<int, QObject *> *attachedProperties; - // ### Can we make this QScriptValuePrivate so we incur no additional allocation // cost? QScriptValue *scriptValue; @@ -147,6 +149,18 @@ public: return 0; } } + + QDeclarativeNotifier *objectNameNotifier() const; + QHash<int, QObject *> *attachedProperties() const; + + struct ExtendedData { + ExtendedData(); + ~ExtendedData(); + + QHash<int, QObject *> attachedProperties; + void *objectNameNotifier; + }; + mutable ExtendedData *extendedData; }; template<class T> diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 9ca7858..c391568 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -68,6 +68,7 @@ #include "private/qdeclarativelist_p.h" #include "private/qdeclarativetypenamecache_p.h" #include "private/qdeclarativeinclude_p.h" +#include "private/qdeclarativenotifier_p.h" #include <QtCore/qmetaobject.h> #include <QScriptClass> @@ -104,6 +105,7 @@ #ifdef Q_OS_WIN // for %APPDATA% #include <qt_windows.h> #include <qlibrary.h> +#include <windows.h> #define CSIDL_APPDATA 0x001a // <username>\Application Data #endif @@ -468,6 +470,11 @@ void QDeclarativeData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QO static_cast<QDeclarativeData *>(d)->parentChanged(o, p); } +void QDeclarativeData::objectNameChanged(QAbstractDeclarativeData *d, QObject *o) +{ + static_cast<QDeclarativeData *>(d)->objectNameChanged(o); +} + void QDeclarativeEnginePrivate::init() { Q_Q(QDeclarativeEngine); @@ -949,7 +956,7 @@ QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool cre if (!data) return 0; // Attached properties are only on objects created by QML - QObject *rv = data->attachedProperties?data->attachedProperties->value(id):0; + QObject *rv = data->extendedData?data->attachedProperties()->value(id):0; if (rv || !create) return rv; @@ -959,11 +966,8 @@ QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool cre rv = pf(const_cast<QObject *>(object)); - if (rv) { - if (!data->attachedProperties) - data->attachedProperties = new QHash<int, QObject *>(); - data->attachedProperties->insert(id, rv); - } + if (rv) + data->attachedProperties()->insert(id, rv); return rv; } @@ -984,8 +988,6 @@ void QDeclarativeData::destroyed(QObject *object) { if (deferredComponent) deferredComponent->release(); - if (attachedProperties) - delete attachedProperties; if (nextContextObject) nextContextObject->prevContextObject = prevContextObject; @@ -1019,6 +1021,9 @@ void QDeclarativeData::destroyed(QObject *object) if (scriptValue) delete scriptValue; + if (extendedData) + delete extendedData; + if (ownMemory) delete this; } @@ -1028,6 +1033,11 @@ void QDeclarativeData::parentChanged(QObject *, QObject *parent) if (!parent && scriptValue) { delete scriptValue; scriptValue = 0; } } +void QDeclarativeData::objectNameChanged(QObject *) +{ + if (extendedData) objectNameNotifier()->notify(); +} + bool QDeclarativeData::hasBindingBit(int bit) const { if (bindingBitsSize > bit) @@ -1064,6 +1074,28 @@ void QDeclarativeData::setBindingBit(QObject *obj, int bit) bindingBits[bit / 32] |= (1 << (bit % 32)); } +QDeclarativeData::ExtendedData::ExtendedData() +: objectNameNotifier(0) +{ +} + +QDeclarativeData::ExtendedData::~ExtendedData() +{ + ((QDeclarativeNotifier *)&objectNameNotifier)->~QDeclarativeNotifier(); +} + +QDeclarativeNotifier *QDeclarativeData::objectNameNotifier() const +{ + if (!extendedData) extendedData = new ExtendedData; + return (QDeclarativeNotifier *)&extendedData->objectNameNotifier; +} + +QHash<int, QObject *> *QDeclarativeData::attachedProperties() const +{ + if (!extendedData) extendedData = new ExtendedData; + return &extendedData->attachedProperties; +} + /*! Creates a QScriptValue allowing you to use \a object in QML script. \a engine is the QDeclarativeEngine it is to be created in. @@ -2159,4 +2191,42 @@ const QMetaObject *QDeclarativeEnginePrivate::metaObjectForType(int t) const } } +bool QDeclarative_isFileCaseCorrect(const QString &fileName) +{ +#if defined(Q_OS_MAC) || defined(Q_OS_WIN32) + QFileInfo info(fileName); + + QString absolute = info.absoluteFilePath(); + +#if defined(Q_OS_MAC) + QString canonical = info.canonicalFilePath(); +#elif defined(Q_OS_WIN32) + wchar_t buffer[1024]; + + DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024); + if (rv == 0 || rv >= 1024) return true; + rv = ::GetLongPathName(buffer, buffer, 1024); + if (rv == 0 || rv >= 1024) return true; + + QString canonical((QChar *)buffer); +#endif + + int absoluteLength = absolute.length(); + int canonicalLength = canonical.length(); + + int length = qMin(absoluteLength, canonicalLength); + for (int ii = 0; ii < length; ++ii) { + const QChar &a = absolute.at(absoluteLength - 1 - ii); + const QChar &c = canonical.at(canonicalLength - 1 - ii); + + if (a.toLower() != c.toLower()) + return true; + if (a != c) + return false; + } +#endif + + return true; +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativefastproperties.cpp b/src/declarative/qml/qdeclarativefastproperties.cpp index eb69b6a..78e3afd 100644 --- a/src/declarative/qml/qdeclarativefastproperties.cpp +++ b/src/declarative/qml/qdeclarativefastproperties.cpp @@ -51,10 +51,19 @@ QT_BEGIN_NAMESPACE // primarily read from bindings is a candidate for inclusion as a fast // property. +static void QObject_objectName(QObject *object, void *output, QDeclarativeNotifierEndpoint *endpoint) +{ + if (endpoint) + endpoint->connect(QDeclarativeData::get(object, true)->objectNameNotifier()); + *((QString *)output) = object->objectName(); +} + QDeclarativeFastProperties::QDeclarativeFastProperties() { add(&QDeclarativeItem::staticMetaObject, QDeclarativeItem::staticMetaObject.indexOfProperty("parent"), QDeclarativeItemPrivate::parentProperty); + add(&QObject::staticMetaObject, QObject::staticMetaObject.indexOfProperty("objectName"), + QObject_objectName); } int QDeclarativeFastProperties::accessorIndexForProperty(const QMetaObject *metaObject, int propertyIndex) diff --git a/src/declarative/qml/qdeclarativeglobal_p.h b/src/declarative/qml/qdeclarativeglobal_p.h index 1041992..65d9b24 100644 --- a/src/declarative/qml/qdeclarativeglobal_p.h +++ b/src/declarative/qml/qdeclarativeglobal_p.h @@ -75,6 +75,19 @@ struct QDeclarativeGraphics_DerivedObject : public QObject }; /*! + Returns true if the case of \a fileName is equivalent to the file case of + \a fileName on disk, and false otherwise. + + This is used to ensure that the behavior of QML on a case-insensitive file + system is the same as on a case-sensitive file system. This function + performs a "best effort" attempt to determine the real case of the file. + It may have false positives (say the case is correct when it isn't), but it + should never have a false negative (say the case is incorrect when it is + correct). +*/ +bool QDeclarative_isFileCaseCorrect(const QString &fileName); + +/*! Makes the \a object a child of \a parent. Note that when using this method, neither \a parent nor the object's previous parent (if it had one) will receive ChildRemoved or ChildAdded events. diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp index fe4ed48..6f5216a 100644 --- a/src/declarative/qml/qdeclarativeimport.cpp +++ b/src/declarative/qml/qdeclarativeimport.cpp @@ -351,7 +351,11 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath { QFile file(absoluteFilePath); QString filecontent; - if (file.open(QFile::ReadOnly)) { + if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) { + if (errorString) + *errorString = QDeclarativeImportDatabase::tr("cannot load module \"%1\": File name case mismatch for \"%2\"").arg(uri).arg(absoluteFilePath); + return false; + } else if (file.open(QFile::ReadOnly)) { filecontent = QString::fromUtf8(file.readAll()); if (qmlImportTrace()) qDebug().nospace() << "QDeclarativeImports(" << qPrintable(base.toString()) << "::importExtension: " @@ -913,6 +917,11 @@ bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QSt } if (!engineInitialized || !typesRegistered) { + if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) { + if (errorString) + *errorString = tr("File name case mismatch for \"%2\"").arg(absoluteFilePath); + return false; + } QPluginLoader loader(absoluteFilePath); if (!loader.load()) { diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index ab6ff74..61a1f55 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -239,8 +239,13 @@ QDeclarativeObjectScriptClass::property(QObject *obj, const Identifier &name) } } else { if (enginePriv->captureProperties && !(lastData->flags & QDeclarativePropertyCache::Data::IsConstant)) { - enginePriv->capturedProperties << - QDeclarativeEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex); + if (lastData->coreIndex == 0) { + enginePriv->capturedProperties << + QDeclarativeEnginePrivate::CapturedProperty(QDeclarativeData::get(obj, true)->objectNameNotifier()); + } else { + enginePriv->capturedProperties << + QDeclarativeEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex); + } } if (QDeclarativeValueTypeFactory::isValueType((uint)lastData->propType)) { diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp index 061f309..c8e1a07 100644 --- a/src/declarative/qml/qdeclarativetypeloader.cpp +++ b/src/declarative/qml/qdeclarativetypeloader.cpp @@ -44,6 +44,7 @@ #include <private/qdeclarativeengine_p.h> #include <private/qdeclarativecompiler_p.h> #include <private/qdeclarativecomponent_p.h> +#include <private/qdeclarativeglobal_p.h> #include <QtDeclarative/qdeclarativecomponent.h> #include <QtCore/qdebug.h> @@ -493,6 +494,13 @@ void QDeclarativeDataLoader::load(QDeclarativeDataBlob *blob) QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(blob->m_url); if (!lf.isEmpty()) { + if (!QDeclarative_isFileCaseCorrect(lf)) { + QDeclarativeError error; + error.setUrl(blob->m_url); + error.setDescription(QLatin1String("File name case mismatch")); + blob->setError(error); + return; + } QFile file(lf); if (file.open(QFile::ReadOnly)) { QByteArray data = file.readAll(); diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp index 37f08fc..e28062b 100644 --- a/src/declarative/qml/qdeclarativevmemetaobject.cpp +++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp @@ -459,7 +459,7 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) id -= propOffset; if (id < metaData->propertyCount) { - int t = (metaData->propertyData() + id)->propertyType; + int t = (metaData->propertyData() + id)->propertyType; bool needActivate = false; if (t == -1) { @@ -586,11 +586,26 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) connectAlias(id); - if (d->propertyIdx == -1) { + if (d->isObjectAlias()) { *reinterpret_cast<QObject **>(a[0]) = target; return -1; + } else if (d->isValueTypeAlias()) { + // Value type property + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine); + + QDeclarativeValueType *valueType = ep->valueTypes[d->valueType()]; + Q_ASSERT(valueType); + + valueType->read(target, d->propertyIndex()); + int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a); + + if (c == QMetaObject::WriteProperty) + valueType->write(target, d->propertyIndex(), 0x00); + + return rv; + } else { - return QMetaObject::metacall(target, c, d->propertyIdx, a); + return QMetaObject::metacall(target, c, d->propertyIndex(), a); } } @@ -823,8 +838,8 @@ void QDeclarativeVMEMetaObject::connectAlias(int aliasId) int sigIdx = methodOffset + aliasId + metaData->propertyCount; QMetaObject::connect(context, d->contextIdx + ctxtPriv->notifyIndex, object, sigIdx); - if (d->propertyIdx != -1) { - QMetaProperty prop = target->metaObject()->property(d->propertyIdx); + if (!d->isObjectAlias()) { + QMetaProperty prop = target->metaObject()->property(d->propertyIndex()); if (prop.hasNotifySignal()) QDeclarativePropertyPrivate::connect(target, prop.notifySignalIndex(), object, sigIdx); } diff --git a/src/declarative/qml/qdeclarativevmemetaobject_p.h b/src/declarative/qml/qdeclarativevmemetaobject_p.h index 4ccaa73..5134763 100644 --- a/src/declarative/qml/qdeclarativevmemetaobject_p.h +++ b/src/declarative/qml/qdeclarativevmemetaobject_p.h @@ -84,6 +84,25 @@ struct QDeclarativeVMEMetaData int contextIdx; int propertyIdx; int flags; + + bool isObjectAlias() const { + return propertyIdx == -1; + } + bool isPropertyAlias() const { + return !isObjectAlias() && !(propertyIdx & 0xFF000000); + } + bool isValueTypeAlias() const { + return !isObjectAlias() && (propertyIdx & 0xFF000000); + } + int propertyIndex() const { + return propertyIdx & 0x0000FFFF; + } + int valueTypeIndex() const { + return (propertyIdx & 0x00FF0000) >> 16; + } + int valueType() const { + return ((unsigned int)propertyIdx) >> 24; + } }; struct PropertyData { diff --git a/src/declarative/util/qdeclarativefontloader.cpp b/src/declarative/util/qdeclarativefontloader.cpp index 3e4a81a..d2f65ef 100644 --- a/src/declarative/util/qdeclarativefontloader.cpp +++ b/src/declarative/util/qdeclarativefontloader.cpp @@ -49,7 +49,6 @@ #include <QDebug> #include <QNetworkRequest> #include <QNetworkReply> -#include <QFile> #include <QFontDatabase> #include <private/qobject_p.h> diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp index 6804d4a..852b055 100644 --- a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp +++ b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp @@ -208,7 +208,7 @@ bool QDeclarativeListModelWorkerAgent::event(QEvent *e) const QList<Change> &changes = s->data.changes; if (m_copy) { - bool cc = m_copy->count() != s->list->count(); + bool cc = m_orig->count() != s->list->count(); FlatListModel *orig = m_orig->m_flat; FlatListModel *copy = s->list->m_flat; diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 83aafe9..3ad8f33 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2365,7 +2365,7 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo while (fsi->d_ptr->focusScopeItem && fsi->d_ptr->focusScopeItem->isVisible()) fsi = fsi->d_ptr->focusScopeItem; fsi->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ true, - /* focusFromShow = */ true); + /* focusFromHide = */ false); } break; } @@ -2375,6 +2375,10 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo QGraphicsItem *fi = subFocusItem; if (fi && fi != scene->focusItem()) { scene->setFocusItem(fi); + } else if (flags & QGraphicsItem::ItemIsFocusScope && + !scene->focusItem() && + q->isAncestorOf(scene->d_func()->lastFocusItem)) { + q_ptr->setFocus(); } } } else { @@ -2385,7 +2389,7 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, bo if (p->flags() & QGraphicsItem::ItemIsFocusScope) { if (p->d_ptr->visible) { p->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ true, - /* focusFromShow = */ true); + /* focusFromHide = */ true); } break; } @@ -3245,13 +3249,13 @@ bool QGraphicsItem::hasFocus() const */ void QGraphicsItem::setFocus(Qt::FocusReason focusReason) { - d_ptr->setFocusHelper(focusReason, /* climb = */ true, /* focusFromShow = */ false); + d_ptr->setFocusHelper(focusReason, /* climb = */ true, /* focusFromHide = */ false); } /*! \internal */ -void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool climb, bool focusFromShow) +void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool climb, bool focusFromHide) { // Disabled / unfocusable items cannot accept focus. if (!q_ptr->isEnabled() || !(flags & QGraphicsItem::ItemIsFocusable)) @@ -3272,7 +3276,7 @@ void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool clim if (p->flags() & QGraphicsItem::ItemIsFocusScope) { QGraphicsItem *oldFocusScopeItem = p->d_ptr->focusScopeItem; p->d_ptr->focusScopeItem = q_ptr; - if (!p->focusItem() && !focusFromShow) { + if (!p->focusItem() && !focusFromHide) { if (oldFocusScopeItem) oldFocusScopeItem->d_ptr->focusScopeItemChange(false); focusScopeItemChange(true); @@ -3334,7 +3338,7 @@ void QGraphicsItemPrivate::clearFocusHelper(bool giveFocusToParent) while (p) { if (p->flags() & QGraphicsItem::ItemIsFocusScope) { p->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ false, - /* focusFromShow = */ false); + /* focusFromHide = */ false); return; } p = p->d_ptr->parent; diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index c8a7699..8480c19 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -477,7 +477,7 @@ public: inline void markParentDirty(bool updateBoundingRect = false); - void setFocusHelper(Qt::FocusReason focusReason, bool climb, bool focusFromShow); + void setFocusHelper(Qt::FocusReason focusReason, bool climb, bool focusFromHide); void clearFocusHelper(bool giveFocusToParent); void setSubFocus(QGraphicsItem *rootItem = 0); void clearSubFocus(QGraphicsItem *rootItem = 0); diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp index 47249d9..b7c8acb 100644 --- a/src/gui/image/qpixmap_s60.cpp +++ b/src/gui/image/qpixmap_s60.cpp @@ -968,11 +968,12 @@ void QS60PixmapData::fromNativeType(void* pixmap, NativeType nativeType) if (needsCopy) { TSize size = sourceBitmap->SizeInPixels(); + int bytesPerLine = sourceBitmap->ScanLineLength(size.iWidth, displayMode); QSymbianBitmapDataAccess da; da.beginDataAccess(sourceBitmap); uchar *bytes = (uchar*)sourceBitmap->DataAddress(); - QImage img = QImage(bytes, size.iWidth, size.iHeight, format); + QImage img = QImage(bytes, size.iWidth, size.iHeight, bytesPerLine, format); img = img.copy(); da.endDataAccess(sourceBitmap); diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 23be51b..38d7d2f 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3153,10 +3153,8 @@ void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti) const TUint8 *glyphBitmapBytes; TSize glyphBitmapSize; fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize); - const glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyphs[i]); - const int x = qFloor(positions[i].x + metrics.x); - const int y = qFloor(positions[i].y + metrics.y); - + const int x = qFloor(positions[i].x + tmetrics.HorizBearingX()); + const int y = qFloor(positions[i].y - tmetrics.HorizBearingY()); alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight); } diff --git a/src/gui/s60framework/qs60mainapplication.cpp b/src/gui/s60framework/qs60mainapplication.cpp index 74432af..24d2496 100644 --- a/src/gui/s60framework/qs60mainapplication.cpp +++ b/src/gui/s60framework/qs60mainapplication.cpp @@ -47,6 +47,9 @@ #include "qs60mainapplication.h" #include <bautils.h> #include <coemain.h> +#ifndef Q_WS_S60 +# include <eikserverapp.h> +#endif QT_BEGIN_NAMESPACE @@ -152,7 +155,11 @@ CDictionaryStore *QS60MainApplication::OpenIniFileLC(RFs &aFs) const */ void QS60MainApplication::NewAppServerL(CApaAppServer *&aAppServer) { +#ifdef Q_WS_S60 QS60MainApplicationBase::NewAppServerL(aAppServer); +#else + aAppServer = new(ELeave) CEikAppServer; +#endif } QT_END_NAMESPACE diff --git a/src/gui/text/qfontengine_s60.cpp b/src/gui/text/qfontengine_s60.cpp index e9dcfa0..134c1ed 100644 --- a/src/gui/text/qfontengine_s60.cpp +++ b/src/gui/text/qfontengine_s60.cpp @@ -41,6 +41,7 @@ #include "qfontengine_s60_p.h" #include "qtextengine_p.h" +#include "qendian.h" #include "qglobal.h" #include <private/qapplication_p.h> #include "qimage.h" @@ -177,6 +178,24 @@ CFont *QSymbianTypeFaceExtras::fontOwner() const return m_cFont; } +QFixed QSymbianTypeFaceExtras::unitsPerEm() const +{ + if (m_unitsPerEm.value() != 0) + return m_unitsPerEm; + const QByteArray head = getSfntTable(MAKE_TAG('h', 'e', 'a', 'd')); + const int unitsPerEmOffset = 18; + if (head.size() > unitsPerEmOffset + sizeof(quint16)) { + const uchar* tableData = reinterpret_cast<const uchar*>(head.constData()); + const uchar* unitsPerEm = tableData + unitsPerEmOffset; + m_unitsPerEm = qFromBigEndian<quint16>(unitsPerEm); + } else { + // Bitmap font? Corrupt font? + // We return -1 and let the QFontEngineS60 return the pixel size. + m_unitsPerEm = -1; + } + return m_unitsPerEm; +} + // duplicated from qfontengine_xyz.cpp static inline unsigned int getChar(const QChar *str, int &i, const int len) { @@ -249,6 +268,13 @@ QFontEngineS60::~QFontEngineS60() releaseFont(m_scaledFont); } +QFixed QFontEngineS60::emSquareSize() const +{ + const QFixed unitsPerEm = m_extras->unitsPerEm(); + return unitsPerEm.toInt() == -1 ? + QFixed::fromReal(m_originalFontSizeInPixels) : unitsPerEm; +} + bool QFontEngineS60::stringToCMap(const QChar *characters, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const { if (*nglyphs < len) { @@ -278,10 +304,13 @@ bool QFontEngineS60::stringToCMap(const QChar *characters, int len, QGlyphLayout void QFontEngineS60::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const { Q_UNUSED(flags); + TOpenFontCharMetrics metrics; + const TUint8 *glyphBitmapBytes; + TSize glyphBitmapSize; for (int i = 0; i < glyphs->numGlyphs; i++) { - const glyph_metrics_t bbox = boundingBox_const(glyphs->glyphs[i]); - glyphs->advances_x[i] = bbox.xoff; - glyphs->advances_y[i] = bbox.yoff; + getCharacterData(glyphs->glyphs[i], metrics, glyphBitmapBytes, glyphBitmapSize); + glyphs->advances_x[i] = metrics.HorizAdvance(); + glyphs->advances_y[i] = 0; } } @@ -309,6 +338,7 @@ void QFontEngineS60::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, parseGlyphPathData(outlineChar, outlineEnd, *path, fontSizeInPixels, positions[count++].toPointF(), false); } while(KErrNone == iterator.Next() && count <= nglyphs); + iterator.Close(); #else // Q_SYMBIAN_HAS_GLYPHOUTLINE_API QFontEngine::addGlyphsToPath(glyphs, positions, nglyphs, path, flags); #endif //Q_SYMBIAN_HAS_GLYPHOUTLINE_API @@ -316,29 +346,17 @@ void QFontEngineS60::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, QImage QFontEngineS60::alphaMapForGlyph(glyph_t glyph) { + // Note: On some Symbian versions (apparently <= Symbian^1), this + // function will return gray values 0x00, 0x10 ... 0xe0, 0xf0 due + // to a bug. The glyphs are nowhere perfectly opaque. + // This has been fixed for Symbian^3. + TOpenFontCharMetrics metrics; const TUint8 *glyphBitmapBytes; TSize glyphBitmapSize; getCharacterData(glyph, metrics, glyphBitmapBytes, glyphBitmapSize); QImage result(glyphBitmapBytes, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight, glyphBitmapSize.iWidth, QImage::Format_Indexed8); result.setColorTable(grayPalette()); - - // The above setColorTable() call detached the image data anyway, so why not shape tha data a bit, while we can. - // CFont::GetCharacterData() returns 8-bit data that obviously was 4-bit data before, and converted to 8-bit incorrectly. - // The data values are 0x00, 0x10 ... 0xe0, 0xf0. So, a real opaque 0xff is never reached, which we get punished - // for every time we want to blit this glyph in the raster paint engine. - // "Fix" is to convert all 0xf0 to 0xff. Is fine, quality wise, and I assume faster than correcting all values. - // Blitting is however, evidentially faster now. - const int bpl = result.bytesPerLine(); - for (int row = 0; row < result.height(); ++row) { - uchar *scanLine = result.scanLine(row); - for (int column = 0; column < bpl; ++column) { - if (*scanLine == 0xf0) - *scanLine = 0xff; - scanLine++; - } - } - return result; } @@ -360,13 +378,11 @@ glyph_metrics_t QFontEngineS60::boundingBox_const(glyph_t glyph) const const TUint8 *glyphBitmapBytes; TSize glyphBitmapSize; getCharacterData(glyph, metrics, glyphBitmapBytes, glyphBitmapSize); - TRect glyphBounds; - metrics.GetHorizBounds(glyphBounds); const glyph_metrics_t result( - glyphBounds.iTl.iX, - glyphBounds.iTl.iY, - glyphBounds.Width(), - glyphBounds.Height(), + metrics.HorizBearingX(), + -metrics.HorizBearingY(), + metrics.Width(), + metrics.Height(), metrics.HorizAdvance(), 0 ); diff --git a/src/gui/text/qfontengine_s60_p.h b/src/gui/text/qfontengine_s60_p.h index d05c23c..c65ce55 100644 --- a/src/gui/text/qfontengine_s60_p.h +++ b/src/gui/text/qfontengine_s60_p.h @@ -82,11 +82,13 @@ public: const uchar *cmap() const; CFont *fontOwner() const; bool isSymbolCMap() const; + QFixed unitsPerEm() const; private: CFont* m_cFont; mutable bool m_symbolCMap; mutable QByteArray m_cmapTable; + mutable QFixed m_unitsPerEm; #ifndef Q_SYMBIAN_HAS_FONTTABLE_API COpenFont *m_openFont; mutable MOpenFontTrueTypeExtension *m_trueTypeExtension; @@ -99,6 +101,7 @@ public: QFontEngineS60(const QFontDef &fontDef, const QSymbianTypeFaceExtras *extras); ~QFontEngineS60(); + QFixed emSquareSize() const; bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; void recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const; diff --git a/src/openvg/qvg_symbian.cpp b/src/openvg/qvg_symbian.cpp index 45138f6..e2a99c2 100644 --- a/src/openvg/qvg_symbian.cpp +++ b/src/openvg/qvg_symbian.cpp @@ -186,10 +186,11 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) QImage::Format format = qt_TDisplayMode2Format(displayMode); TSize size = bitmap->SizeInPixels(); + int bytesPerLine = bitmap->ScanLineLength(size.iWidth, displayMode); bitmap->BeginDataAccess(); uchar *bytes = (uchar*)bitmap->DataAddress(); - QImage img = QImage(bytes, size.iWidth, size.iHeight, format); + QImage img = QImage(bytes, size.iWidth, size.iHeight, bytesPerLine, format); img = img.copy(); bitmap->EndDataAccess(); diff --git a/src/s60installs/bwins/QtCoreu.def b/src/s60installs/bwins/QtCoreu.def index 5eeb244..f4e3a28 100644 --- a/src/s60installs/bwins/QtCoreu.def +++ b/src/s60installs/bwins/QtCoreu.def @@ -4483,4 +4483,5 @@ EXPORTS ?msecsSinceReference@QElapsedTimer@@QBE_JXZ @ 4482 NONAME ; long long QElapsedTimer::msecsSinceReference(void) const ?selectThread@QEventDispatcherSymbian@@AAEAAVQSelectThread@@XZ @ 4483 NONAME ; class QSelectThread & QEventDispatcherSymbian::selectThread(void) ?qt_symbian_SetupThreadHeap@@YAHHAAUSStdEpocThreadCreateInfo@@@Z @ 4484 NONAME ; int qt_symbian_SetupThreadHeap(int, struct SStdEpocThreadCreateInfo &) + ?objectNameChanged@QAbstractDeclarativeData@@2P6AXPAV1@PAVQObject@@@ZA @ 4485 NONAME ; void (*QAbstractDeclarativeData::objectNameChanged)(class QAbstractDeclarativeData *, class QObject *) diff --git a/src/s60installs/bwins/QtDeclarativeu.def b/src/s60installs/bwins/QtDeclarativeu.def index cf0398a..b72147e 100644 --- a/src/s60installs/bwins/QtDeclarativeu.def +++ b/src/s60installs/bwins/QtDeclarativeu.def @@ -1838,4 +1838,5 @@ EXPORTS ?addChanged@QDeclarativeBasePositioner@@IAEXXZ @ 1837 NONAME ; void QDeclarativeBasePositioner::addChanged(void) ?start@QDeclarativeAbstractAnimation@@QAEXXZ @ 1838 NONAME ; void QDeclarativeAbstractAnimation::start(void) ?qt_metacall@QDeclarativeAbstractAnimation@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1839 NONAME ; int QDeclarativeAbstractAnimation::qt_metacall(enum QMetaObject::Call, int, void * *) + ?connect@QDeclarativePropertyPrivate@@SA_NPBVQObject@@H0HHPAH@Z @ 1840 NONAME ; bool QDeclarativePropertyPrivate::connect(class QObject const *, int, class QObject const *, int, int, int *) diff --git a/src/s60installs/eabi/QtCoreu.def b/src/s60installs/eabi/QtCoreu.def index f496839..eb53dca 100644 --- a/src/s60installs/eabi/QtCoreu.def +++ b/src/s60installs/eabi/QtCoreu.def @@ -3712,4 +3712,5 @@ EXPORTS _ZltRK13QElapsedTimerS1_ @ 3711 NONAME _ZrsR11QDataStreamR12QEasingCurve @ 3712 NONAME _Z26qt_symbian_SetupThreadHeapiR24SStdEpocThreadCreateInfo @ 3713 NONAME + _ZN24QAbstractDeclarativeData17objectNameChangedE @ 3714 NONAME DATA 4 diff --git a/src/s60installs/eabi/QtDeclarativeu.def b/src/s60installs/eabi/QtDeclarativeu.def index d4084cc..cbfafdc 100644 --- a/src/s60installs/eabi/QtDeclarativeu.def +++ b/src/s60installs/eabi/QtDeclarativeu.def @@ -1883,4 +1883,5 @@ EXPORTS _ZThn8_N29QDeclarativeAbstractAnimation9setTargetERK20QDeclarativeProperty @ 1882 NONAME _ZThn8_N29QDeclarativeAbstractAnimationD0Ev @ 1883 NONAME _ZThn8_N29QDeclarativeAbstractAnimationD1Ev @ 1884 NONAME + _ZN27QDeclarativePropertyPrivate7connectEPK7QObjectiS2_iiPi @ 1885 NONAME diff --git a/src/s60installs/qt.iby b/src/s60installs/qt.iby index b6cdce9..4afbf05 100644 --- a/src/s60installs/qt.iby +++ b/src/s60installs/qt.iby @@ -53,6 +53,9 @@ file=ABI_DIR\BUILD_DIR\qaudio.dll SHARED_LIB_DIR\qaudio.dll file=ABI_DIR\BUILD_DIR\qvggraphicssystem.dll SHARED_LIB_DIR\qvggraphicssystem.dll file=ABI_DIR\BUILD_DIR\qglgraphicssystem.dll SHARED_LIB_DIR\qglgraphicssystem.dll +// bearer +file=ABI_DIR\BUILD_DIR\qsymbianbearer.dll SHARED_LIB_DIR\qsymbianbearer.dll + // S60 version compatibility plugins for 5.0 (3.1 and 3.2 devices are never likely to have this in ROM, // so don't bother including those plugins file=ABI_DIR\BUILD_DIR\qts60plugin_5_0.dll SHARED_LIB_DIR\qts60plugin_5_0.dll @@ -99,6 +102,9 @@ data=\epoc32\data\qt\qtlibspluginstubs\qaudio.qtplugin resource\qt\plugins\audio data=\epoc32\data\z\resource\qt\plugins\graphicssystems\qvggraphicssystem.qtplugin resource\qt\plugins\graphicssystems\qvggraphicssystem.qtplugin data=\epoc32\data\z\resource\qt\plugins\graphicssystems\qglgraphicssystem.qtplugin resource\qt\plugins\graphicssystems\qglgraphicssystem.qtplugin +// bearer stub +data=\epoc32\data\z\resource\qt\plugins\bearer\qsymbianbearer.qtplugin resource\qt\plugins\bearer\qsymbianbearer.qtplugin + // Stub sis file data=ZSYSTEM\install\qt_stub.sis System\Install\qt_stub.sis data=ZSYSTEM\install\qtwebkit_stub.sis System\Install\qtwebkit_stub.sis diff --git a/src/s60installs/qtdemoapps.iby b/src/s60installs/qtdemoapps.iby deleted file mode 100644 index d888135..0000000 --- a/src/s60installs/qtdemoapps.iby +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef QTDEMOAPPS_IBY -#define QTDEMOAPPS_IBY - -// A subset of Qt demo & example applications - -// Note that star requires OpenVG and the Qt OpenVG paint engine -S60_APP_EXE(star) -S60_APP_RESOURCE(star) -data=\epoc32\data\Z\private\10003a3f\import\Apps\star_reg.rsc \private\10003a3f\import\apps\star_reg.rsc - -S60_APP_EXE(wiggly) -S60_APP_RESOURCE(wiggly) -data=\epoc32\data\Z\private\10003a3f\import\Apps\wiggly_reg.rsc \private\10003a3f\import\apps\wiggly_reg.rsc - -#endif // QTDEMOAPPS_IBY diff --git a/src/s60installs/s60installs.pro b/src/s60installs/s60installs.pro index bc9d98b..2e6d2fe 100644 --- a/src/s60installs/s60installs.pro +++ b/src/s60installs/s60installs.pro @@ -200,5 +200,4 @@ symbian: { } BLD_INF_RULES.prj_exports += "qt.iby $$CORE_MW_LAYER_IBY_EXPORT_PATH(qt.iby)" - BLD_INF_RULES.prj_exports += "qtdemoapps.iby $$CUSTOMER_VARIANT_APP_LAYER_IBY_EXPORT_PATH(qtdemoapps.iby)" } diff --git a/tests/auto/declarative/qdeclarativebehaviors/data/reassignedAnimation.qml b/tests/auto/declarative/qdeclarativebehaviors/data/reassignedAnimation.qml index 9fca5c3..56ac216 100644 --- a/tests/auto/declarative/qdeclarativebehaviors/data/reassignedAnimation.qml +++ b/tests/auto/declarative/qdeclarativebehaviors/data/reassignedAnimation.qml @@ -7,9 +7,9 @@ Rectangle { objectName: "MyRect" width: 100; height: 100; color: "green" Behavior on x { + id: myBehavior objectName: "MyBehavior" NumberAnimation {id: na1; duration: 200 } - NumberAnimation {id: na2; duration: 1000 } } } MouseArea { @@ -24,4 +24,9 @@ Rectangle { x: 200 } } + + NumberAnimation {id: na2; duration: 1000 } + Component.onCompleted: { + myBehavior.animation = na2; + } } diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/objectName.qml b/tests/auto/declarative/qdeclarativeecmascript/data/objectName.qml new file mode 100644 index 0000000..ca8c90d --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/objectName.qml @@ -0,0 +1,8 @@ +import QtQuick 1.0 + +QtObject { + objectName: "hello" + + property string test1: objectName + property string test2: objectName.substr(1, 3) +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 4feb630..02832f3 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -162,6 +162,7 @@ private slots: void deleteLater(); void in(); void sharedAttachedObject(); + void objectName(); void include(); @@ -2594,6 +2595,24 @@ void tst_qdeclarativeecmascript::sharedAttachedObject() delete o; } +// QTBUG-13999 +void tst_qdeclarativeecmascript::objectName() +{ + QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml")); + QObject *o = component.create(); + QVERIFY(o != 0); + + QCOMPARE(o->property("test1").toString(), QString("hello")); + QCOMPARE(o->property("test2").toString(), QString("ell")); + + o->setObjectName("world"); + + QCOMPARE(o->property("test1").toString(), QString("world")); + QCOMPARE(o->property("test2").toString(), QString("orl")); + + delete o; +} + QTEST_MAIN(tst_qdeclarativeecmascript) #include "tst_qdeclarativeecmascript.moc" diff --git a/tests/auto/declarative/qdeclarativefocusscope/data/qtBug13380.qml b/tests/auto/declarative/qdeclarativefocusscope/data/qtBug13380.qml new file mode 100644 index 0000000..1784202 --- /dev/null +++ b/tests/auto/declarative/qdeclarativefocusscope/data/qtBug13380.qml @@ -0,0 +1,24 @@ +import QtQuick 1.0 + +Rectangle { + width: 400; height: 400 + + property bool showRect: false + onShowRectChanged: if (showRect) rect.visible = true + property bool noFocus: !fs2.activeFocus + + FocusScope { + id: fs1 + focus: true + } + Rectangle { + id: rect + visible: false + FocusScope { + id: fs2 + Rectangle { + focus: true + } + } + } +} diff --git a/tests/auto/declarative/qdeclarativefocusscope/tst_qdeclarativefocusscope.cpp b/tests/auto/declarative/qdeclarativefocusscope/tst_qdeclarativefocusscope.cpp index ec8f048..4cafbd9 100644 --- a/tests/auto/declarative/qdeclarativefocusscope/tst_qdeclarativefocusscope.cpp +++ b/tests/auto/declarative/qdeclarativefocusscope/tst_qdeclarativefocusscope.cpp @@ -70,6 +70,7 @@ private slots: void forceFocus(); void noParentFocus(); void signalEmission(); + void qtBug13380(); }; /* @@ -400,6 +401,31 @@ void tst_qdeclarativefocusscope::signalEmission() delete view; } +void tst_qdeclarativefocusscope::qtBug13380() +{ + QDeclarativeView *view = new QDeclarativeView; + view->setSource(QUrl::fromLocalFile(SRCDIR "/data/qtBug13380.qml")); + + view->show(); + QVERIFY(view->rootObject()); + qApp->setActiveWindow(view); + qApp->processEvents(); + +#ifdef Q_WS_X11 + // to be safe and avoid failing setFocus with window managers + qt_x11_wait_for_window_manager(view); +#endif + + QVERIFY(view->hasFocus()); + QVERIFY(view->scene()->hasFocus()); + QVERIFY(view->rootObject()->property("noFocus").toBool()); + + view->rootObject()->setProperty("showRect", true); + QVERIFY(view->rootObject()->property("noFocus").toBool()); + + delete view; +} + QTEST_MAIN(tst_qdeclarativefocusscope) #include "tst_qdeclarativefocusscope.moc" diff --git a/tests/auto/declarative/qdeclarativegridview/data/header.qml b/tests/auto/declarative/qdeclarativegridview/data/header.qml new file mode 100644 index 0000000..99baacd --- /dev/null +++ b/tests/auto/declarative/qdeclarativegridview/data/header.qml @@ -0,0 +1,32 @@ +import QtQuick 1.0 + +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 + header: Text { objectName: "header"; text: "Header"; height: 30 } + } +} diff --git a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp index 975cf8f..f7acd87 100644 --- a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp +++ b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp @@ -82,6 +82,7 @@ private slots: void QTBUG_8456(); void manualHighlight(); void footer(); + void header(); private: QDeclarativeView *createView(); @@ -1214,6 +1215,40 @@ void tst_QDeclarativeGridView::footer() QTRY_COMPARE(footer->y(), 0.0); } +void tst_QDeclarativeGridView::header() +{ + 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/header.qml")); + qApp->processEvents(); + + QDeclarativeGridView *gridview = findItem<QDeclarativeGridView>(canvas->rootObject(), "grid"); + QTRY_VERIFY(gridview != 0); + + QDeclarativeItem *contentItem = gridview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QDeclarativeText *header = findItem<QDeclarativeText>(contentItem, "header"); + QVERIFY(header); + + QCOMPARE(header->y(), 0.0); + QCOMPARE(gridview->contentY(), 0.0); + + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, "wrapper", 0); + QVERIFY(item); + QCOMPARE(item->y(), 30.0); + + model.clear(); + QTRY_COMPARE(header->y(), 0.0); +} + QDeclarativeView *tst_QDeclarativeGridView::createView() { diff --git a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp index 8f9b2ea..f1e026f 100644 --- a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp +++ b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp @@ -84,6 +84,7 @@ private slots: void tiling_QTBUG_6716(); void noLoading(); void paintedWidthHeight(); + void sourceSize_QTBUG_14303(); private: template<typename T> @@ -377,7 +378,7 @@ void tst_qdeclarativeimage::noLoading() QTRY_COMPARE(statusSpy.count(), 0); // Loading remote file - ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/oldcolors.png"); + ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/heart200.png"); QTRY_VERIFY(obj->status() == QDeclarativeImage::Loading); QTRY_VERIFY(obj->progress() == 0.0); QTRY_VERIFY(obj->status() == QDeclarativeImage::Ready); @@ -388,7 +389,7 @@ void tst_qdeclarativeimage::noLoading() // Loading remote file again - should not go through 'Loading' state. ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/colors.png")); - ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/oldcolors.png"); + ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/heart200.png"); QTRY_VERIFY(obj->status() == QDeclarativeImage::Ready); QTRY_VERIFY(obj->progress() == 1.0); QTRY_COMPARE(sourceSpy.count(), 4); @@ -436,6 +437,35 @@ void tst_qdeclarativeimage::paintedWidthHeight() } } +void tst_qdeclarativeimage::sourceSize_QTBUG_14303() +{ + QString componentStr = "import QtQuick 1.0\nImage { source: srcImage }"; + QDeclarativeContext *ctxt = engine.rootContext(); + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/heart200.png")); + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QDeclarativeImage *obj = qobject_cast<QDeclarativeImage*>(component.create()); + + QSignalSpy sourceSizeSpy(obj, SIGNAL(sourceSizeChanged())); + + QTRY_VERIFY(obj != 0); + QTRY_VERIFY(obj->status() == QDeclarativeImage::Ready); + + QTRY_COMPARE(obj->sourceSize().width(), 200); + QTRY_COMPARE(obj->sourceSize().height(), 200); + QTRY_COMPARE(sourceSizeSpy.count(), 0); + + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/colors.png")); + QTRY_COMPARE(obj->sourceSize().width(), 120); + QTRY_COMPARE(obj->sourceSize().height(), 120); + QTRY_COMPARE(sourceSizeSpy.count(), 1); + + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/heart200.png")); + QTRY_COMPARE(obj->sourceSize().width(), 200); + QTRY_COMPARE(obj->sourceSize().height(), 200); + QTRY_COMPARE(sourceSizeSpy.count(), 2); +} + /* Find an item with the specified objectName. If index is supplied then the item must also evaluate the {index} expression equal to index diff --git a/tests/auto/declarative/qdeclarativeitem/data/keystest.qml b/tests/auto/declarative/qdeclarativeitem/data/keystest.qml index 3927f42..9af6e9f 100644 --- a/tests/auto/declarative/qdeclarativeitem/data/keystest.qml +++ b/tests/auto/declarative/qdeclarativeitem/data/keystest.qml @@ -17,6 +17,7 @@ Item { Item { id: item2 + visible: forwardeeVisible Keys.onPressed: keysTestObject.forwardedKey(event.key) Keys.onReleased: keysTestObject.forwardedKey(event.key) } diff --git a/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp b/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp index bbbf73e..b4903ae 100644 --- a/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp +++ b/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp @@ -204,6 +204,7 @@ void tst_QDeclarativeItem::keys() canvas->rootContext()->setContextProperty("keysTestObject", testObject); canvas->rootContext()->setContextProperty("enableKeyHanding", QVariant(true)); + canvas->rootContext()->setContextProperty("forwardeeVisible", QVariant(true)); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/keystest.qml")); canvas->show(); @@ -287,6 +288,17 @@ void tst_QDeclarativeItem::keys() testObject->reset(); + canvas->rootContext()->setContextProperty("forwardeeVisible", QVariant(false)); + key = QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1); + QApplication::sendEvent(canvas, &key); + QCOMPARE(testObject->mKey, int(Qt::Key_A)); + QCOMPARE(testObject->mForwardedKey, 0); + QCOMPARE(testObject->mText, QLatin1String("A")); + QVERIFY(testObject->mModifiers == Qt::NoModifier); + QVERIFY(!key.isAccepted()); + + testObject->reset(); + canvas->rootContext()->setContextProperty("enableKeyHanding", QVariant(false)); QCOMPARE(canvas->rootObject()->property("isEnabled").toBool(), false); diff --git a/tests/auto/declarative/qdeclarativelanguage/data/alias.10.qml b/tests/auto/declarative/qdeclarativelanguage/data/alias.10.qml new file mode 100644 index 0000000..bf6352e --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/alias.10.qml @@ -0,0 +1,8 @@ +import Test 1.0 + +MyTypeObject { + id: root + property alias valueAlias: root.rectProperty + + rectProperty: "10,11,9x8" +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/alias.11.qml b/tests/auto/declarative/qdeclarativelanguage/data/alias.11.qml new file mode 100644 index 0000000..fbd50d9 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/alias.11.qml @@ -0,0 +1,8 @@ +import Test 1.0 + +MyTypeObject { + id: root + + property alias aliasProperty: root.rectProperty.x + rectProperty: "19,13,100x120" +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/importIncorrectCase.qml b/tests/auto/declarative/qdeclarativelanguage/data/importIncorrectCase.qml new file mode 100644 index 0000000..247f527 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/importIncorrectCase.qml @@ -0,0 +1,5 @@ +import QtQuick 1.0 +import com.Nokia.installedtest 1.0 + +QtObject { +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/incorrectCase.errors.insensitive.txt b/tests/auto/declarative/qdeclarativelanguage/data/incorrectCase.errors.insensitive.txt new file mode 100644 index 0000000..3813680 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/incorrectCase.errors.insensitive.txt @@ -0,0 +1,2 @@ +3:1:Type IncorrectCaseType unavailable +-1:-1:File name case mismatch diff --git a/tests/auto/declarative/qdeclarativelanguage/data/incorrectCase.errors.sensitive.txt b/tests/auto/declarative/qdeclarativelanguage/data/incorrectCase.errors.sensitive.txt new file mode 100644 index 0000000..abed1a7 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/incorrectCase.errors.sensitive.txt @@ -0,0 +1 @@ +3:1:IncorrectCaseType is not a type diff --git a/tests/auto/declarative/qdeclarativelanguage/data/incorrectCase.qml b/tests/auto/declarative/qdeclarativelanguage/data/incorrectCase.qml new file mode 100644 index 0000000..d11000b --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/incorrectCase.qml @@ -0,0 +1,4 @@ +import QtQuick 1.0 + +IncorrectCaseType { +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/incorrectCaseType.qml b/tests/auto/declarative/qdeclarativelanguage/data/incorrectCaseType.qml new file mode 100644 index 0000000..cf32b45 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/incorrectCaseType.qml @@ -0,0 +1,4 @@ +import QtQuick 1.0 + +QtObject { +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.10.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.10.errors.txt new file mode 100644 index 0000000..93652a7 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.10.errors.txt @@ -0,0 +1 @@ +5:23:Invalid alias location diff --git a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.10.qml b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.10.qml new file mode 100644 index 0000000..3ff7b16 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.10.qml @@ -0,0 +1,6 @@ +import Test 1.0 + +MyTypeObject { + id: root + property alias a: root.rectProperty.blah +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.3.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.3.errors.txt index 7260be4..fbf1b58 100644 --- a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.3.errors.txt +++ b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.3.errors.txt @@ -1 +1 @@ -5:23:Invalid alias reference. An alias reference must be specified as <id> or <id>.<property> +5:23:Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property> diff --git a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.3.qml b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.3.qml index cc71753..a363373 100644 --- a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.3.qml +++ b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.3.qml @@ -2,5 +2,5 @@ import Test 1.0 MyTypeObject { id: root - property alias a: root.rectProperty.x + property alias a: root.rectProperty.x.y } diff --git a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.4.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.4.errors.txt index 7260be4..fbf1b58 100644 --- a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.4.errors.txt +++ b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.4.errors.txt @@ -1 +1 @@ -5:23:Invalid alias reference. An alias reference must be specified as <id> or <id>.<property> +5:23:Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property> diff --git a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.8.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.8.errors.txt new file mode 100644 index 0000000..93652a7 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.8.errors.txt @@ -0,0 +1 @@ +5:23:Invalid alias location diff --git a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.8.qml b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.8.qml new file mode 100644 index 0000000..4faa52d --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.8.qml @@ -0,0 +1,7 @@ +import Test 1.0 + +MyTypeObject { + id: root + property alias a: root.imaginary.x +} + diff --git a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.9.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.9.errors.txt new file mode 100644 index 0000000..93652a7 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.9.errors.txt @@ -0,0 +1 @@ +5:23:Invalid alias location diff --git a/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.9.qml b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.9.qml new file mode 100644 index 0000000..f183912 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/invalidAlias.9.qml @@ -0,0 +1,6 @@ +import Test 1.0 + +MyTypeObject { + id: root + property alias a: root.floatProperty.x +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.2.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.2.errors.txt new file mode 100644 index 0000000..beae562 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.2.errors.txt @@ -0,0 +1 @@ +5:10:Cannot assign multiple values to a singular property diff --git a/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.2.qml b/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.2.qml new file mode 100644 index 0000000..2fd7fd2 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.2.qml @@ -0,0 +1,7 @@ +import QtQuick 1.0 + +QtObject { + property QtObject a + a: [ QtObject {}, QtObject {} ] +} + diff --git a/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.errors.txt new file mode 100644 index 0000000..beae562 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.errors.txt @@ -0,0 +1 @@ +5:10:Cannot assign multiple values to a singular property diff --git a/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.qml b/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.qml new file mode 100644 index 0000000..da56cb8 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/singularProperty.qml @@ -0,0 +1,6 @@ +import QtQuick 1.0 + +QtObject { + property variant a + a: [ QtObject {}, QtObject {} ] +} diff --git a/tests/auto/declarative/qdeclarativelanguage/qtest/declarative/qmllanguage/noqmldir/Test.qml b/tests/auto/declarative/qdeclarativelanguage/qtest/declarative/qmllanguage/noqmldir/Test.qml new file mode 100644 index 0000000..0b054d0 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/qtest/declarative/qmllanguage/noqmldir/Test.qml @@ -0,0 +1,2 @@ +import QtQuick 1.0 +Rectangle { } diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp index 9a8c944..061ac48 100644 --- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp +++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp @@ -144,6 +144,7 @@ private slots: void importsInstalled(); void importsOrder_data(); void importsOrder(); + void importIncorrectCase(); void qmlAttachedPropertiesObjectMethod(); void customOnProperty(); @@ -348,6 +349,9 @@ void tst_qdeclarativelanguage::errors_data() QTest::newRow("invalidAlias.5") << "invalidAlias.5.qml" << "invalidAlias.5.errors.txt" << false; QTest::newRow("invalidAlias.6") << "invalidAlias.6.qml" << "invalidAlias.6.errors.txt" << false; QTest::newRow("invalidAlias.7") << "invalidAlias.7.qml" << "invalidAlias.7.errors.txt" << false; + QTest::newRow("invalidAlias.8") << "invalidAlias.8.qml" << "invalidAlias.8.errors.txt" << false; + QTest::newRow("invalidAlias.9") << "invalidAlias.9.qml" << "invalidAlias.9.errors.txt" << false; + QTest::newRow("invalidAlias.10") << "invalidAlias.10.qml" << "invalidAlias.10.errors.txt" << false; QTest::newRow("invalidAttachedProperty.1") << "invalidAttachedProperty.1.qml" << "invalidAttachedProperty.1.errors.txt" << false; QTest::newRow("invalidAttachedProperty.2") << "invalidAttachedProperty.2.qml" << "invalidAttachedProperty.2.errors.txt" << false; @@ -380,6 +384,15 @@ void tst_qdeclarativelanguage::errors_data() QTest::newRow("invalidProperty") << "invalidProperty.qml" << "invalidProperty.errors.txt" << false; QTest::newRow("nonScriptableProperty") << "nonScriptableProperty.qml" << "nonScriptableProperty.errors.txt" << false; QTest::newRow("notAvailable") << "notAvailable.qml" << "notAvailable.errors.txt" << false; + QTest::newRow("singularProperty") << "singularProperty.qml" << "singularProperty.errors.txt" << false; + QTest::newRow("singularProperty.2") << "singularProperty.2.qml" << "singularProperty.2.errors.txt" << false; + QTest::newRow("incorrectCase") << "incorrectCase.qml" +#if defined(Q_OS_MAC) || defined(Q_OS_WIN32) + << "incorrectCase.errors.insensitive.txt" +#else + << "incorrectCase.errors.sensitive.txt" +#endif + << false; } @@ -1054,6 +1067,47 @@ void tst_qdeclarativelanguage::aliasProperties() delete object; } + + // Valuetype alias + // Simple "int" alias + { + QDeclarativeComponent component(&engine, TEST_FILE("alias.10.qml")); + VERIFY_ERRORS(0); + QObject *object = component.create(); + QVERIFY(object != 0); + + // Read through alias + QCOMPARE(object->property("valueAlias").toRect(), QRect(10, 11, 9, 8)); + object->setProperty("rectProperty", QVariant(QRect(33, 12, 99, 100))); + QCOMPARE(object->property("valueAlias").toRect(), QRect(33, 12, 99, 100)); + + // Write throught alias + object->setProperty("valueAlias", QVariant(QRect(3, 3, 4, 9))); + QCOMPARE(object->property("valueAlias").toRect(), QRect(3, 3, 4, 9)); + QCOMPARE(object->property("rectProperty").toRect(), QRect(3, 3, 4, 9)); + + delete object; + } + + // Valuetype sub-alias + { + QDeclarativeComponent component(&engine, TEST_FILE("alias.11.qml")); + VERIFY_ERRORS(0); + QObject *object = component.create(); + QVERIFY(object != 0); + + // Read through alias + QCOMPARE(object->property("aliasProperty").toInt(), 19); + object->setProperty("rectProperty", QVariant(QRect(33, 8, 102, 111))); + QCOMPARE(object->property("aliasProperty").toInt(), 33); + + // Write throught alias + object->setProperty("aliasProperty", QVariant(4)); + QCOMPARE(object->property("aliasProperty").toInt(), 4); + QCOMPARE(object->property("rectProperty").toRect(), QRect(4, 8, 102, 111)); + + delete object; + } } // QTBUG-13374 Test that alias properties and signals can coexist @@ -1515,6 +1569,7 @@ void tst_qdeclarativelanguage::basicRemote_data() QString serverdir = "http://127.0.0.1:14447/qtest/declarative/qmllanguage/"; QTest::newRow("no need for qmldir") << QUrl(serverdir+"Test.qml") << "" << ""; + QTest::newRow("absent qmldir") << QUrl(serverdir+"/noqmldir/Test.qml") << "" << ""; QTest::newRow("need qmldir") << QUrl(serverdir+"TestLocal.qml") << "" << ""; } @@ -1722,6 +1777,22 @@ void tst_qdeclarativelanguage::importsOrder() testType(qml,type,error); } +void tst_qdeclarativelanguage::importIncorrectCase() +{ + QDeclarativeComponent component(&engine, TEST_FILE("importIncorrectCase.qml")); + + QList<QDeclarativeError> errors = component.errors(); + QCOMPARE(errors.count(), 1); + +#if defined(Q_OS_MAC) || defined(Q_OS_WIN32) + QString expectedError = QLatin1String("cannot load module \"com.Nokia.installedtest\": File name case mismatch for \"") + QFileInfo(__FILE__).absoluteDir().filePath("data/lib/com/Nokia/installedtest/qmldir") + QLatin1String("\""); +#else + QString expectedError = QLatin1String("module \"com.Nokia.installedtest\" is not installed"); +#endif + + QCOMPARE(errors.at(0).description(), expectedError); +} + void tst_qdeclarativelanguage::qmlAttachedPropertiesObjectMethod() { QObject object; diff --git a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp index be77f8e..4b8d772 100644 --- a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp +++ b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp @@ -320,11 +320,16 @@ void tst_qdeclarativelistmodel::dynamic() if (!warning.isEmpty()) QTest::ignoreMessage(QtWarningMsg, warning.toLatin1()); + QSignalSpy spyCount(&model, SIGNAL(countChanged())); + int actual = e.evaluate().toInt(); if (e.hasError()) qDebug() << e.error(); // errors not expected QCOMPARE(actual,result); + + if (model.count() > 0) + QVERIFY(spyCount.count() > 0); } void tst_qdeclarativelistmodel::dynamic_worker_data() @@ -351,6 +356,8 @@ void tst_qdeclarativelistmodel::dynamic_worker() QDeclarativeItem *item = createWorkerTest(&eng, &component, &model); QVERIFY(item != 0); + QSignalSpy spyCount(&model, SIGNAL(countChanged())); + if (script[0] == QLatin1Char('{') && script[script.length()-1] == QLatin1Char('}')) script = script.mid(1, script.length() - 2); QVariantList operations; @@ -367,6 +374,9 @@ void tst_qdeclarativelistmodel::dynamic_worker() waitForWorker(item); QCOMPARE(QDeclarativeProperty(item, "result").read().toInt(), result); + if (model.count() > 0) + QVERIFY(spyCount.count() > 0); + delete item; qApp->processEvents(); } diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp index 6452bae..2649c0d 100644 --- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp +++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp @@ -937,6 +937,8 @@ void tst_QDeclarativeListView::sections() QCOMPARE(next->text().toInt(), (i+1)/5); } + QSignalSpy currentSectionChangedSpy(listview, SIGNAL(currentSectionChanged())); + // Remove section boundary model.removeItem(5); @@ -972,13 +974,25 @@ void tst_QDeclarativeListView::sections() listview->setContentY(140); QTRY_COMPARE(listview->currentSection(), QString("1")); + QTRY_COMPARE(currentSectionChangedSpy.count(), 1); + listview->setContentY(20); QTRY_COMPARE(listview->currentSection(), QString("0")); + QTRY_COMPARE(currentSectionChangedSpy.count(), 2); + item = findItem<QDeclarativeItem>(contentItem, "wrapper", 1); QTRY_VERIFY(item); QTRY_COMPARE(item->height(), 20.0); + // check that headers change when item changes + listview->setContentY(0); + model.modifyItem(0, "changed", "2"); + + item = findItem<QDeclarativeItem>(contentItem, "wrapper", 1); + QTRY_VERIFY(item); + QTRY_COMPARE(item->height(), 40.0); + delete canvas; } diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/data/incorrectCase.qml b/tests/auto/declarative/qdeclarativemoduleplugin/data/incorrectCase.qml new file mode 100644 index 0000000..a21ece7 --- /dev/null +++ b/tests/auto/declarative/qdeclarativemoduleplugin/data/incorrectCase.qml @@ -0,0 +1,4 @@ +import com.nokia.WrongCase 1.0 + +MyPluginType { value: 123 } + diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/imports/com/nokia/WrongCase/qmldir b/tests/auto/declarative/qdeclarativemoduleplugin/imports/com/nokia/WrongCase/qmldir new file mode 100644 index 0000000..6c87874 --- /dev/null +++ b/tests/auto/declarative/qdeclarativemoduleplugin/imports/com/nokia/WrongCase/qmldir @@ -0,0 +1 @@ +plugin PluGin diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/pluginWrongCase/plugin.cpp b/tests/auto/declarative/qdeclarativemoduleplugin/pluginWrongCase/plugin.cpp new file mode 100644 index 0000000..5e91f4e --- /dev/null +++ b/tests/auto/declarative/qdeclarativemoduleplugin/pluginWrongCase/plugin.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 <QStringList> +#include <QtDeclarative/qdeclarativeextensionplugin.h> +#include <QtDeclarative/qdeclarative.h> +#include <QDebug> + +class MyPluginType : public QObject +{ + Q_OBJECT + Q_PROPERTY(int value READ value WRITE setValue) + +public: + MyPluginType(QObject *parent=0) : QObject(parent) + { + qWarning("import worked"); + } + + int value() const { return v; } + void setValue(int i) { v = i; } + +private: + int v; +}; + + +class MyPlugin : public QDeclarativeExtensionPlugin +{ + Q_OBJECT +public: + MyPlugin() + { + qWarning("plugin created"); + } + + void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == "com.nokia.WrongCase"); + qmlRegisterType<MyPluginType>(uri, 1, 0, "MyPluginType"); + } +}; + +#include "plugin.moc" + +Q_EXPORT_PLUGIN2(plugin, MyPlugin); diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/pluginWrongCase/pluginWrongCase.pro b/tests/auto/declarative/qdeclarativemoduleplugin/pluginWrongCase/pluginWrongCase.pro new file mode 100644 index 0000000..c7337ca --- /dev/null +++ b/tests/auto/declarative/qdeclarativemoduleplugin/pluginWrongCase/pluginWrongCase.pro @@ -0,0 +1,10 @@ +TEMPLATE = lib +CONFIG += plugin +SOURCES = plugin.cpp +QT = core declarative +TARGET = Plugin +DESTDIR = ../imports/com/nokia/WrongCase + +symbian: { + TARGET.EPOCALLOWDLLDATA=1 +} diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/qdeclarativemoduleplugin.pro b/tests/auto/declarative/qdeclarativemoduleplugin/qdeclarativemoduleplugin.pro index 824b402..221e465 100644 --- a/tests/auto/declarative/qdeclarativemoduleplugin/qdeclarativemoduleplugin.pro +++ b/tests/auto/declarative/qdeclarativemoduleplugin/qdeclarativemoduleplugin.pro @@ -1,6 +1,6 @@ QT = core TEMPLATE = subdirs -SUBDIRS = plugin +SUBDIRS = plugin pluginWrongCase tst_qdeclarativemoduleplugin_pro.depends += plugin SUBDIRS += tst_qdeclarativemoduleplugin.pro diff --git a/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.cpp b/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.cpp index e1022e0..85fa718 100644 --- a/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.cpp +++ b/tests/auto/declarative/qdeclarativemoduleplugin/tst_qdeclarativemoduleplugin.cpp @@ -54,6 +54,7 @@ public: private slots: void importsPlugin(); + void incorrectPluginCase(); }; #ifdef Q_OS_SYMBIAN @@ -120,6 +121,30 @@ void tst_qdeclarativemoduleplugin::importsPlugin() delete object; } +void tst_qdeclarativemoduleplugin::incorrectPluginCase() +{ + QDeclarativeEngine engine; + engine.addImportPath(QLatin1String(SRCDIR) + QDir::separator() + QLatin1String("imports")); + + QDeclarativeComponent component(&engine, TEST_FILE("data/incorrectCase.qml")); + + QList<QDeclarativeError> errors = component.errors(); + QCOMPARE(errors.count(), 1); + +#if defined(Q_OS_MAC) || defined(Q_OS_WIN32) +#if defined(Q_OS_MAC) + QString libname = "libPluGin.dylib"; +#elif defined(Q_OS_WIN32) + QString libname = "PluGin.dll"; +#endif + QString expectedError = QLatin1String("plugin cannot be loaded for module \"com.nokia.WrongCase\": File name case mismatch for \"") + QFileInfo(__FILE__).absoluteDir().filePath("imports/com/nokia/WrongCase/" + libname) + QLatin1String("\""); +#else + QString expectedError = QLatin1String("module \"com.nokia.WrongCase\" plugin \"PluGin\" not found"); +#endif + + QCOMPARE(errors.at(0).description(), expectedError); +} + QTEST_MAIN(tst_qdeclarativemoduleplugin) #include "tst_qdeclarativemoduleplugin.moc" diff --git a/tests/auto/declarative/qdeclarativemousearea/data/doubleclick.qml b/tests/auto/declarative/qdeclarativemousearea/data/doubleclick.qml index 2348444..55b0812 100644 --- a/tests/auto/declarative/qdeclarativemousearea/data/doubleclick.qml +++ b/tests/auto/declarative/qdeclarativemousearea/data/doubleclick.qml @@ -4,11 +4,13 @@ Item { id: root property int clicked: 0 property int doubleClicked: 0 + property int released: 0 MouseArea { width: 200; height: 200 onClicked: { root.clicked++ } onDoubleClicked: { root.doubleClicked++ } + onReleased: { root.released++ } } } diff --git a/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp b/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp index 5e88450..5a50e0d 100644 --- a/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp +++ b/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp @@ -413,14 +413,19 @@ void tst_QDeclarativeMouseArea::doubleClick() releaseEvent.setButtons(Qt::LeftButton); QApplication::sendEvent(scene, &releaseEvent); + QCOMPARE(canvas->rootObject()->property("released").toInt(), 1); + QGraphicsSceneMouseEvent dblClickEvent(QEvent::GraphicsSceneMouseDoubleClick); dblClickEvent.setScenePos(QPointF(100, 100)); dblClickEvent.setButton(Qt::LeftButton); dblClickEvent.setButtons(Qt::LeftButton); QApplication::sendEvent(scene, &dblClickEvent); + QApplication::sendEvent(scene, &releaseEvent); + QCOMPARE(canvas->rootObject()->property("clicked").toInt(), 1); QCOMPARE(canvas->rootObject()->property("doubleClicked").toInt(), 1); + QCOMPARE(canvas->rootObject()->property("released").toInt(), 2); } QTEST_MAIN(tst_QDeclarativeMouseArea) diff --git a/tests/auto/declarative/qdeclarativetext/data/alignments_cb.png b/tests/auto/declarative/qdeclarativetext/data/alignments_cb.png Binary files differindex b5c6bba..3f143d5 100644 --- a/tests/auto/declarative/qdeclarativetext/data/alignments_cb.png +++ b/tests/auto/declarative/qdeclarativetext/data/alignments_cb.png diff --git a/tests/auto/declarative/qdeclarativetext/data/alignments_cc.png b/tests/auto/declarative/qdeclarativetext/data/alignments_cc.png Binary files differindex c9ffcc1..c6e6250 100644 --- a/tests/auto/declarative/qdeclarativetext/data/alignments_cc.png +++ b/tests/auto/declarative/qdeclarativetext/data/alignments_cc.png diff --git a/tests/auto/declarative/qdeclarativetext/data/alignments_ct.png b/tests/auto/declarative/qdeclarativetext/data/alignments_ct.png Binary files differindex eda0d25..c54058f 100644 --- a/tests/auto/declarative/qdeclarativetext/data/alignments_ct.png +++ b/tests/auto/declarative/qdeclarativetext/data/alignments_ct.png diff --git a/tests/auto/declarative/qdeclarativetext/data/alignments_lb.png b/tests/auto/declarative/qdeclarativetext/data/alignments_lb.png Binary files differindex 1b50a81..11715e9 100644 --- a/tests/auto/declarative/qdeclarativetext/data/alignments_lb.png +++ b/tests/auto/declarative/qdeclarativetext/data/alignments_lb.png diff --git a/tests/auto/declarative/qdeclarativetext/data/alignments_lc.png b/tests/auto/declarative/qdeclarativetext/data/alignments_lc.png Binary files differindex f041b86..c27e5d8 100644 --- a/tests/auto/declarative/qdeclarativetext/data/alignments_lc.png +++ b/tests/auto/declarative/qdeclarativetext/data/alignments_lc.png diff --git a/tests/auto/declarative/qdeclarativetext/data/alignments_lt.png b/tests/auto/declarative/qdeclarativetext/data/alignments_lt.png Binary files differindex c75e0d1..18694a9 100644 --- a/tests/auto/declarative/qdeclarativetext/data/alignments_lt.png +++ b/tests/auto/declarative/qdeclarativetext/data/alignments_lt.png diff --git a/tests/auto/declarative/qdeclarativetext/data/alignments_rb.png b/tests/auto/declarative/qdeclarativetext/data/alignments_rb.png Binary files differindex b06a5da..010c6ae 100644 --- a/tests/auto/declarative/qdeclarativetext/data/alignments_rb.png +++ b/tests/auto/declarative/qdeclarativetext/data/alignments_rb.png diff --git a/tests/auto/declarative/qdeclarativetext/data/alignments_rc.png b/tests/auto/declarative/qdeclarativetext/data/alignments_rc.png Binary files differindex e468857..2828bbc 100644 --- a/tests/auto/declarative/qdeclarativetext/data/alignments_rc.png +++ b/tests/auto/declarative/qdeclarativetext/data/alignments_rc.png diff --git a/tests/auto/declarative/qdeclarativetext/data/alignments_rt.png b/tests/auto/declarative/qdeclarativetext/data/alignments_rt.png Binary files differindex 576715f..5cf3c03 100644 --- a/tests/auto/declarative/qdeclarativetext/data/alignments_rt.png +++ b/tests/auto/declarative/qdeclarativetext/data/alignments_rt.png diff --git a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index 472c5ef..a7971cc 100644 --- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -56,6 +56,8 @@ #include <QDir> #include <QStyle> #include <QInputContext> +#include <QClipboard> +#include <QMimeData> #include <private/qapplication_p.h> #include <private/qtextcontrol_p.h> @@ -119,6 +121,8 @@ private slots: void openInputPanelOnClick(); void openInputPanelOnFocus(); void geometrySignals(); + void pastingRichText_QTBUG_14003(); + private: void simulateKey(QDeclarativeView *, int key); QDeclarativeView *createView(const QString &filename); @@ -1174,6 +1178,27 @@ void tst_qdeclarativetextedit::geometrySignals() delete o; } +void tst_qdeclarativetextedit::pastingRichText_QTBUG_14003() +{ +#ifndef QT_NO_CLIPBOARD + QString componentStr = "import QtQuick 1.0\nTextEdit { textFormat: TextEdit.PlainText }"; + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QDeclarativeTextEdit *obj = qobject_cast<QDeclarativeTextEdit*>(component.create()); + + QTRY_VERIFY(obj != 0); + QTRY_VERIFY(obj->textFormat() == QDeclarativeTextEdit::PlainText); + + QMimeData *mData = new QMimeData; + mData->setHtml("<font color=\"red\">Hello</font>"); + QApplication::clipboard()->setMimeData(mData); + + obj->paste(); + QTRY_VERIFY(obj->text() == ""); + QTRY_VERIFY(obj->textFormat() == QDeclarativeTextEdit::PlainText); +#endif +} + QTEST_MAIN(tst_qdeclarativetextedit) #include "tst_qdeclarativetextedit.moc" diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 2901dd5..2ddccd2 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -9065,6 +9065,9 @@ void tst_QGraphicsItem::focusScope() scope2->hide(); scope2->show(); QVERIFY(!scope2->hasFocus()); + QVERIFY(scope1->hasFocus()); + scope2->setFocus(); + scope3->setFocus(); QVERIFY(scope3->hasFocus()); QGraphicsRectItem *rect4 = new QGraphicsRectItem; diff --git a/tests/auto/qpixmap/tst_qpixmap.cpp b/tests/auto/qpixmap/tst_qpixmap.cpp index 24cbb21..fdf8311 100644 --- a/tests/auto/qpixmap/tst_qpixmap.cpp +++ b/tests/auto/qpixmap/tst_qpixmap.cpp @@ -1160,6 +1160,8 @@ void tst_QPixmap::fromSymbianCFbsBitmap_data() const int smallHeight = 20; const int largeWidth = 240; const int largeHeight = 320; + const int notAlignedWidth = 250; + const int notAlignedHeight = 250; // Indexed Color Formats - Disabled since images seem to be blank -> no palette? // QTest::newRow("EGray2 small") << EGray2 << smallWidth << smallHeight << QColor(Qt::black); @@ -1172,14 +1174,19 @@ void tst_QPixmap::fromSymbianCFbsBitmap_data() // Direct Color Formats QTest::newRow("EColor4K small") << EColor4K << smallWidth << smallHeight << QColor(Qt::red); QTest::newRow("EColor4K big") << EColor4K << largeWidth << largeHeight << QColor(Qt::red); + QTest::newRow("EColor4K not aligned") << EColor4K << notAlignedWidth << notAlignedHeight << QColor(Qt::red); QTest::newRow("EColor64K small") << EColor64K << smallWidth << smallHeight << QColor(Qt::green); QTest::newRow("EColor64K big") << EColor64K << largeWidth << largeHeight << QColor(Qt::green); + QTest::newRow("EColor64K not aligned") << EColor64K << notAlignedWidth << notAlignedHeight << QColor(Qt::green); QTest::newRow("EColor16M small") << EColor16M << smallWidth << smallHeight << QColor(Qt::yellow); QTest::newRow("EColor16M big") << EColor16M << largeWidth << largeHeight << QColor(Qt::yellow); + QTest::newRow("EColor16M not aligned") << EColor16M << notAlignedWidth << notAlignedHeight << QColor(Qt::yellow); QTest::newRow("EColor16MU small") << EColor16MU << smallWidth << smallHeight << QColor(Qt::red); QTest::newRow("EColor16MU big") << EColor16MU << largeWidth << largeHeight << QColor(Qt::red); + QTest::newRow("EColor16MU not aligned") << EColor16MU << notAlignedWidth << notAlignedHeight << QColor(Qt::red); QTest::newRow("EColor16MA small opaque") << EColor16MA << smallWidth << smallHeight << QColor(255, 255, 0); QTest::newRow("EColor16MA big opaque") << EColor16MA << largeWidth << largeHeight << QColor(255, 255, 0); + QTest::newRow("EColor16MA not aligned opaque") << EColor16MA << notAlignedWidth << notAlignedHeight << QColor(255, 255, 0); // Semi-transparent Colors - Disabled for now, since the QCOMPARE fails, but visually confirmed to work // QTest::newRow("EColor16MA small semi") << EColor16MA << smallWidth << smallHeight << QColor(255, 255, 0, 127); @@ -1237,6 +1244,10 @@ void tst_QPixmap::fromSymbianCFbsBitmap() QColor actualColor(image.pixel(1, 1)); QCOMPARE(actualColor, color); + + QImage shouldBe(pixmap.width(), pixmap.height(), image.format()); + shouldBe.fill(color.rgba()); + QCOMPARE(image, shouldBe); } __UHEAP_MARKEND; |