summaryrefslogtreecommitdiffstats
path: root/src/declarative
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative')
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflickable.cpp4
-rw-r--r--src/declarative/graphicsitems/qdeclarativegridview.cpp9
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimagebase.cpp15
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h2
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem.cpp9
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview.cpp55
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview_p.h2
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea.cpp12
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea_p_p.h3
-rw-r--r--src/declarative/graphicsitems/qdeclarativepainteditem.cpp1
-rw-r--r--src/declarative/graphicsitems/qdeclarativepathview.cpp6
-rw-r--r--src/declarative/graphicsitems/qdeclarativetext.cpp959
-rw-r--r--src/declarative/graphicsitems/qdeclarativetext_p_p.h48
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextedit.cpp1
-rw-r--r--src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp21
-rw-r--r--src/declarative/graphicsitems/qdeclarativevisualitemmodel_p.h4
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp30
-rw-r--r--src/declarative/qml/qdeclarativecomponent.cpp1
-rw-r--r--src/declarative/qml/qdeclarativedata_p.h20
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp86
-rw-r--r--src/declarative/qml/qdeclarativefastproperties.cpp9
-rw-r--r--src/declarative/qml/qdeclarativeglobal_p.h13
-rw-r--r--src/declarative/qml/qdeclarativeimport.cpp11
-rw-r--r--src/declarative/qml/qdeclarativeobjectscriptclass.cpp9
-rw-r--r--src/declarative/qml/qdeclarativetypeloader.cpp8
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject.cpp25
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject_p.h19
-rw-r--r--src/declarative/util/qdeclarativefontloader.cpp1
-rw-r--r--src/declarative/util/qdeclarativelistmodelworkeragent.cpp2
29 files changed, 844 insertions, 541 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp
index 33c21b1..001abca 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 b135e84..95a4fd6 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>
@@ -1180,7 +1179,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;
@@ -1222,7 +1221,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;
@@ -1247,7 +1246,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;
@@ -1275,7 +1274,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/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 584c5ec..c3fdf36 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;