aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp38
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp146
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h3
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp206
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp1
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp3
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h4
-rw-r--r--src/quick/items/qquickdrag.cpp10
-rw-r--r--src/quick/items/qquickdroparea.cpp2
-rw-r--r--src/quick/items/qquickevents_p_p.h2
-rw-r--r--src/quick/items/qquickflickable.cpp22
-rw-r--r--src/quick/items/qquickflickable_p_p.h2
-rw-r--r--src/quick/items/qquickgridview.cpp16
-rw-r--r--src/quick/items/qquickimage.cpp6
-rw-r--r--src/quick/items/qquickitem.cpp209
-rw-r--r--src/quick/items/qquickitem.h4
-rw-r--r--src/quick/items/qquickitem_p.h12
-rw-r--r--src/quick/items/qquickitemsmodule.cpp7
-rw-r--r--src/quick/items/qquickitemview.cpp21
-rw-r--r--src/quick/items/qquickitemview_p.h1
-rw-r--r--src/quick/items/qquicklistview.cpp19
-rw-r--r--src/quick/items/qquickloader.cpp8
-rw-r--r--src/quick/items/qquickmousearea.cpp9
-rw-r--r--src/quick/items/qquickmousearea_p.h2
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp28
-rw-r--r--src/quick/items/qquickmultipointtoucharea_p.h4
-rw-r--r--src/quick/items/qquickpathview.cpp2
-rw-r--r--src/quick/items/qquickpincharea.cpp28
-rw-r--r--src/quick/items/qquickpincharea_p.h4
-rw-r--r--src/quick/items/qquickpositioners.cpp106
-rw-r--r--src/quick/items/qquickrectangle.cpp2
-rw-r--r--src/quick/items/qquickrepeater.cpp17
-rw-r--r--src/quick/items/qquickrepeater_p_p.h2
-rw-r--r--src/quick/items/qquickscreen.cpp86
-rw-r--r--src/quick/items/qquickscreen_p.h11
-rw-r--r--src/quick/items/qquickshadereffect.cpp4
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp6
-rw-r--r--src/quick/items/qquicktext.cpp98
-rw-r--r--src/quick/items/qquicktext_p.h8
-rw-r--r--src/quick/items/qquicktext_p_p.h4
-rw-r--r--src/quick/items/qquicktextcontrol.cpp50
-rw-r--r--src/quick/items/qquicktextcontrol_p.h2
-rw-r--r--src/quick/items/qquicktextcontrol_p_p.h3
-rw-r--r--src/quick/items/qquicktextdocument.h2
-rw-r--r--src/quick/items/qquicktextedit.cpp224
-rw-r--r--src/quick/items/qquicktextedit_p.h9
-rw-r--r--src/quick/items/qquicktextedit_p_p.h4
-rw-r--r--src/quick/items/qquicktextinput.cpp27
-rw-r--r--src/quick/items/qquicktextinput_p_p.h2
-rw-r--r--src/quick/items/qquicktextnode.cpp6
-rw-r--r--src/quick/items/qquicktextnode_p.h5
-rw-r--r--src/quick/items/qquickview.cpp2
-rw-r--r--src/quick/items/qquickwindow.cpp320
-rw-r--r--src/quick/items/qquickwindow.h7
-rw-r--r--src/quick/items/qquickwindow_p.h29
-rw-r--r--src/quick/items/qquickwindowmodule.cpp24
56 files changed, 1453 insertions, 426 deletions
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index e7546535a1..9c4cef1fe1 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -175,7 +175,6 @@ public:
uint hasTileSize :1;
uint hasCanvasWindow :1;
uint available :1;
- uint contextInitialized :1;
QQuickCanvasItem::RenderTarget renderTarget;
QQuickCanvasItem::RenderStrategy renderStrategy;
QString contextType;
@@ -193,7 +192,6 @@ QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
, hasTileSize(false)
, hasCanvasWindow(false)
, available(false)
- , contextInitialized(false)
, renderTarget(QQuickCanvasItem::Image)
, renderStrategy(QQuickCanvasItem::Cooperative)
{
@@ -272,7 +270,7 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
requires the pixel data to be exchanged between the system memory and the
graphic card, which is significantly more expensive. Rendering may also be
synchronized with the V-sync signal (to avoid
- \l{en.wikipedia.org/wiki/Screen_tearing}{screen tearing}) which will further
+ \l{http://en.wikipedia.org/wiki/Screen_tearing}{screen tearing}) which will further
impact pixel operations with \c Canvas.FrambufferObject render target.
\section1 Tips for Porting Existing HTML5 Canvas applications
@@ -343,7 +341,7 @@ void QQuickCanvasItem::setContextType(const QString &contextType)
if (contextType.compare(d->contextType, Qt::CaseInsensitive) == 0)
return;
- if (d->contextInitialized) {
+ if (d->context) {
qmlInfo(this) << "Canvas already initialized with a different context type";
return;
}
@@ -368,7 +366,7 @@ void QQuickCanvasItem::setContextType(const QString &contextType)
QQmlV4Handle QQuickCanvasItem::context() const
{
Q_D(const QQuickCanvasItem);
- if (d->contextInitialized)
+ if (d->context)
return QQmlV4Handle(d->context->v4value());
return QQmlV4Handle(QV4::Value::nullValue());
@@ -402,7 +400,7 @@ void QQuickCanvasItem::setCanvasSize(const QSizeF & size)
d->canvasSize = size;
emit canvasSizeChanged();
- if (d->contextInitialized)
+ if (d->context)
polish();
}
}
@@ -437,7 +435,7 @@ void QQuickCanvasItem::setTileSize(const QSize & size)
emit tileSizeChanged();
- if (d->contextInitialized)
+ if (d->context)
polish();
}
}
@@ -470,7 +468,7 @@ void QQuickCanvasItem::setCanvasWindow(const QRectF& rect)
d->hasCanvasWindow = true;
emit canvasWindowChanged();
- if (d->contextInitialized)
+ if (d->context)
polish();
}
}
@@ -502,7 +500,7 @@ void QQuickCanvasItem::setRenderTarget(QQuickCanvasItem::RenderTarget target)
{
Q_D(QQuickCanvasItem);
if (d->renderTarget != target) {
- if (d->contextInitialized) {
+ if (d->context) {
qmlInfo(this) << "Canvas:renderTarget not changeble once context is active.";
return;
}
@@ -546,7 +544,7 @@ void QQuickCanvasItem::setRenderStrategy(QQuickCanvasItem::RenderStrategy strate
{
Q_D(QQuickCanvasItem);
if (d->renderStrategy != strategy) {
- if (d->contextInitialized) {
+ if (d->context) {
qmlInfo(this) << "Canvas:renderStrategy not changeable once context is active.";
return;
}
@@ -651,7 +649,7 @@ void QQuickCanvasItem::updatePolish()
Q_D(QQuickCanvasItem);
- if (d->contextInitialized)
+ if (d->context && d->renderStrategy != QQuickCanvasItem::Cooperative)
d->context->prepare(d->canvasSize.toSize(), d->tileSize, d->canvasWindow.toRect(), d->dirtyRect.toRect(), d->smooth, d->antialiasing);
if (d->animationCallbacks.size() > 0 && isVisible()) {
@@ -676,7 +674,7 @@ void QQuickCanvasItem::updatePolish()
}
}
- if (d->contextInitialized) {
+ if (d->context) {
if (d->renderStrategy == QQuickCanvasItem::Cooperative)
update();
else
@@ -688,8 +686,10 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
{
Q_D(QQuickCanvasItem);
- if (!d->contextInitialized)
+ if (!d->context || d->canvasWindow.size().isEmpty()) {
+ delete oldNode;
return 0;
+ }
QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode*>(oldNode);
if (!node)
@@ -700,10 +700,13 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
else
node->setFiltering(QSGTexture::Nearest);
- if (d->renderStrategy == QQuickCanvasItem::Cooperative)
+ if (d->renderStrategy == QQuickCanvasItem::Cooperative) {
+ d->context->prepare(d->canvasSize.toSize(), d->tileSize, d->canvasWindow.toRect(), d->dirtyRect.toRect(), d->smooth, d->antialiasing);
d->context->flush();
+ }
node->setTexture(d->context->texture());
+ node->markDirty(QSGNode::DirtyMaterial);
node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
return node;
}
@@ -763,7 +766,7 @@ void QQuickCanvasItem::getContext(QQmlV4Function *args)
/*!
\qmlmethod long QtQuick2::Canvas::requestAnimationFrame(callback)
- This function schedules callback to be invoked before composing the QtQuick
+ This function schedules callback to be invoked before composing the Qt Quick
scene.
*/
@@ -970,7 +973,7 @@ bool QQuickCanvasItem::isImageLoaded(const QUrl& url) const
QImage QQuickCanvasItem::toImage(const QRectF& rect) const
{
Q_D(const QQuickCanvasItem);
- if (d->contextInitialized) {
+ if (d->context) {
if (rect.isEmpty())
return d->context->toImage(canvasWindow());
else
@@ -1026,7 +1029,7 @@ void QQuickCanvasItem::delayedCreate()
{
Q_D(QQuickCanvasItem);
- if (!d->contextInitialized && !d->contextType.isNull())
+ if (!d->context && !d->contextType.isNull())
createContext(d->contextType);
requestPaint();
@@ -1055,7 +1058,6 @@ void QQuickCanvasItem::initializeContext(QQuickCanvasContext *context, const QVa
d->context = context;
d->context->init(this, args);
d->context->setV8Engine(QQmlEnginePrivate::getV8Engine(qmlEngine(this)));
- d->contextInitialized = true;
connect(d->context, SIGNAL(textureChanged()), SLOT(update()));
connect(d->context, SIGNAL(textureChanged()), SIGNAL(painted()));
emit contextChanged();
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 5011fd45f2..c9ee426565 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -210,9 +210,11 @@ QFont qt_font_from_string(const QString& fontString) {
font.setBold(true);
else if (token.endsWith(QStringLiteral("px"))) {
QString number = token;
- number.remove(QStringLiteral("px"));
- //font.setPointSizeF(number.trimmed().toFloat());
- font.setPixelSize(number.trimmed().toInt());
+ number.remove(QLatin1String("px"));
+ bool ok = false;
+ float pixelSize = number.trimmed().toFloat(&ok);
+ if (ok)
+ font.setPixelSize(int(pixelSize));
} else
font.setFamily(token);
}
@@ -426,50 +428,86 @@ DEFINE_MANAGED_VTABLE(QQuickContext2DStyle);
QImage qt_image_convolute_filter(const QImage& src, const QVector<qreal>& weights, int radius = 0)
{
- int sides = radius ? radius : qRound(qSqrt(weights.size()));
- int half = qFloor(sides/2);
+ // weights 3x3 => delta 1
+ int delta = radius ? radius : qFloor(qSqrt(weights.size()) / qreal(2));
+ int filterDim = 2 * delta + 1;
QImage dst = QImage(src.size(), src.format());
+
int w = src.width();
int h = src.height();
- for (int y = 0; y < dst.height(); ++y) {
- QRgb *dr = (QRgb*)dst.scanLine(y);
- for (int x = 0; x < dst.width(); ++x) {
- unsigned char* dRgb = ((unsigned char*)&dr[x]);
- unsigned char red=0, green=0, blue=0, alpha=0;
- int sy = y;
- int sx = x;
-
- for (int cy=0; cy<sides; cy++) {
- for (int cx=0; cx<sides; cx++) {
- int scy = sy + cy - half;
- int scx = sx + cx - half;
- if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
- const QRgb *sr = (const QRgb*)(src.constScanLine(scy));
- const unsigned char* sRgb = ((const unsigned char*)&sr[scx]);
- qreal wt = radius ? weights[0] : weights[cy*sides+cx];
- red += sRgb[0] * wt;
- green += sRgb[1] * wt;
- blue += sRgb[2] * wt;
- alpha += sRgb[3] * wt;
- }
- }
- }
- dRgb[0] = red;
- dRgb[1] = green;
- dRgb[2] = blue;
- dRgb[3] = alpha;
- }
+
+ const QRgb *sr = (const QRgb *)(src.constBits());
+ int srcStride = src.bytesPerLine() / 4;
+
+ QRgb *dr = (QRgb*)dst.bits();
+ int dstStride = dst.bytesPerLine() / 4;
+
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ int red = 0;
+ int green = 0;
+ int blue = 0;
+ int alpha = 0;
+
+ qreal redF = 0;
+ qreal greenF = 0;
+ qreal blueF = 0;
+ qreal alphaF = 0;
+
+ int sy = y;
+ int sx = x;
+
+ for (int cy = 0; cy < filterDim; ++cy) {
+ int scy = sy + cy - delta;
+
+ if (scy < 0 || scy >= h)
+ continue;
+
+ const QRgb *sry = sr + scy * srcStride;
+
+ for (int cx = 0; cx < filterDim; ++cx) {
+ int scx = sx + cx - delta;
+
+ if (scx < 0 || scx >= w)
+ continue;
+
+ const QRgb col = sry[scx];
+
+ if (radius) {
+ red += qRed(col);
+ green += qGreen(col);
+ blue += qBlue(col);
+ alpha += qAlpha(col);
+ } else {
+ qreal wt = weights[cy * filterDim + cx];
+
+ redF += qRed(col) * wt;
+ greenF += qGreen(col) * wt;
+ blueF += qBlue(col) * wt;
+ alphaF += qAlpha(col) * wt;
+ }
+ }
+ }
+
+ if (radius)
+ dr[x] = qRgba(qRound(red * weights[0]), qRound(green * weights[0]), qRound(blue * weights[0]), qRound(alpha * weights[0]));
+ else
+ dr[x] = qRgba(qRound(redF), qRound(greenF), qRound(blueF), qRound(alphaF));
+ }
+
+ dr += dstStride;
}
+
return dst;
}
void qt_image_boxblur(QImage& image, int radius, bool quality)
{
int passes = quality? 3: 1;
- for (int i=0; i < passes; i++) {
- image = qt_image_convolute_filter(image, QVector<qreal>() << 1.0/(radius * radius * 1.0), radius);
- }
+ int filterSize = 2 * radius + 1;
+ for (int i = 0; i < passes; ++i)
+ image = qt_image_convolute_filter(image, QVector<qreal>() << 1.0 / (filterSize * filterSize), radius);
}
static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
@@ -644,7 +682,7 @@ static QV4::Value qt_create_image_data(qreal w, qreal h, QV8Engine* engine, cons
pixelData->image = QImage(w, h, QImage::Format_ARGB32);
pixelData->image.fill(0x00000000);
} else {
- Q_ASSERT(image.width() == w && image.height() == h);
+ Q_ASSERT(image.width() == int(w) && image.height() == int(h));
pixelData->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
}
@@ -2525,7 +2563,11 @@ QV4::Value QQuickJSContext2DPrototype::method_drawImage(QV4::SimpleCallContext *
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else {
- V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
+ QUrl url(ctx->arguments[0].toQString());
+ if (url.isValid())
+ pixmap = r->context->createPixmap(url);
+ else
+ V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else {
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
@@ -2790,7 +2832,7 @@ QV4::Value QQuickJSContext2DPrototype::method_createImageData(QV4::SimpleCallCon
}
/*!
- \qmlmethod CanvasImageData QtQuick2::Canvas::getImageData(real sx, real sy, real sw, real sh)
+ \qmlmethod CanvasImageData QtQuick2::Context2D::getImageData(real sx, real sy, real sw, real sh)
Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
*/
QV4::Value QQuickJSContext2DPrototype::method_getImageData(QV4::SimpleCallContext *ctx)
@@ -3488,7 +3530,6 @@ QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString&
QPainterPath textPath;
textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
- textPath = state.matrix.map(textPath);
return textPath;
}
@@ -3662,7 +3703,7 @@ QImage QQuickContext2D::toImage(const QRectF& bounds)
if (m_texture->thread() == QThread::currentThread())
m_texture->grabImage(bounds);
else if (m_renderStrategy == QQuickCanvasItem::Cooperative) {
- qWarning() << "Pixel read back is not support in Cooperative mode, please try Theaded or Immediate mode";
+ qWarning() << "Pixel readback is not supported in Cooperative mode, please try Threaded or Immediate mode";
return QImage();
} else {
QMetaObject::invokeMethod(m_texture,
@@ -3775,7 +3816,6 @@ void QQuickContext2D::pushState()
void QQuickContext2D::reset()
{
QQuickContext2D::State newState;
- newState.matrix = QTransform();
m_path = QPainterPath();
@@ -3787,28 +3827,6 @@ void QQuickContext2D::reset()
newState.clipPath = defaultClipPath;
newState.clipPath.setFillRule(Qt::WindingFill);
- newState.strokeStyle = QColor("#000000");
- newState.fillStyle = QColor("#000000");
- newState.fillPatternRepeatX = false;
- newState.fillPatternRepeatY = false;
- newState.strokePatternRepeatX = false;
- newState.strokePatternRepeatY = false;
- newState.invertibleCTM = true;
- newState.fillRule = Qt::WindingFill;
- newState.globalAlpha = 1.0;
- newState.lineWidth = 1;
- newState.lineCap = Qt::FlatCap;
- newState.lineJoin = Qt::MiterJoin;
- newState.miterLimit = 10;
- newState.shadowOffsetX = 0;
- newState.shadowOffsetY = 0;
- newState.shadowBlur = 0;
- newState.shadowColor = qRgba(0, 0, 0, 0);
- newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
- newState.font = QFont(QStringLiteral("sans-serif"), 10);
- newState.textAlign = QQuickContext2D::Start;
- newState.textBaseline = QQuickContext2D::Alphabetic;
-
m_stateStack.clear();
m_stateStack.push(newState);
popState();
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 0fe8bc6db2..8164108bd3 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -131,10 +131,11 @@ public:
, shadowBlur(0)
, shadowColor(qRgba(0, 0, 0, 0))
, globalCompositeOperation(QPainter::CompositionMode_SourceOver)
- , font(QFont(QLatin1String("sans-serif"), 10))
+ , font(QFont(QLatin1String("sans-serif")))
, textAlign(QQuickContext2D::Start)
, textBaseline(QQuickContext2D::Alphabetic)
{
+ font.setPixelSize(10);
}
QTransform matrix;
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index 7c5841810b..d433efcb69 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -54,86 +54,136 @@ QT_BEGIN_NAMESPACE
void qt_image_boxblur(QImage& image, int radius, bool quality);
-static QImage makeShadowImage(const QImage& image, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
-{
- QImage shadowImg(image.width() + blur + qAbs(offsetX),
- image.height() + blur + qAbs(offsetY),
- QImage::Format_ARGB32_Premultiplied);
- shadowImg.fill(0);
- QPainter tmpPainter(&shadowImg);
- tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
- qreal shadowX = offsetX > 0? offsetX : 0;
- qreal shadowY = offsetY > 0? offsetY : 0;
-
- tmpPainter.drawImage(shadowX, shadowY, image);
- tmpPainter.end();
-
- if (blur > 0)
- qt_image_boxblur(shadowImg, blur/2, true);
-
- // blacken the image with shadow color...
- tmpPainter.begin(&shadowImg);
- tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
- tmpPainter.fillRect(shadowImg.rect(), color);
- tmpPainter.end();
- return shadowImg;
-}
+namespace {
+ class ShadowImageMaker
+ {
+ public:
+ virtual ~ShadowImageMaker() {}
-static void fillRectShadow(QPainter* p, QRectF shadowRect, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
-{
- QRectF r = shadowRect;
- r.moveTo(0, 0);
+ void paintShapeAndShadow(QPainter *p, qreal offsetX, qreal offsetY, qreal blur, const QColor &color)
+ {
+ QRectF bounds = boundingRect().translated(offsetX, offsetY).adjusted(-2*blur, -2*blur, 2*blur, 2*blur);
+ QRect boundsAligned = bounds.toAlignedRect();
+
+ QImage shadowImage(boundsAligned.size(), QImage::Format_ARGB32_Premultiplied);
+ shadowImage.fill(0);
+
+ QPainter shadowPainter(&shadowImage);
+ shadowPainter.setRenderHints(p->renderHints());
+ shadowPainter.translate(offsetX - boundsAligned.left(), offsetY - boundsAligned.top());
+ paint(&shadowPainter);
+ shadowPainter.end();
+
+ if (blur > 0)
+ qt_image_boxblur(shadowImage, qMax(1, qRound(blur / 2)), true);
+
+ // blacken the image with shadow color...
+ shadowPainter.begin(&shadowImage);
+ shadowPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ shadowPainter.fillRect(shadowImage.rect(), color);
+ shadowPainter.end();
+
+ p->drawImage(boundsAligned.topLeft(), shadowImage);
+ paint(p);
+ }
- QImage shadowImage(r.size().width() + 1, r.size().height() + 1, QImage::Format_ARGB32_Premultiplied);
- QPainter tp;
- tp.begin(&shadowImage);
- tp.fillRect(r, p->brush());
- tp.end();
- shadowImage = makeShadowImage(shadowImage, offsetX, offsetY, blur, color);
+ virtual void paint(QPainter *p) const = 0;
+ virtual QRectF boundingRect() const = 0;
+ };
- qreal dx = shadowRect.left() + (offsetX < 0? offsetX:0);
- qreal dy = shadowRect.top() + (offsetY < 0? offsetY:0);
+ class FillRectShadow : public ShadowImageMaker
+ {
+ public:
+ FillRectShadow(const QRectF &rect, const QBrush &brush)
+ : m_rect(rect.normalized())
+ , m_brush(brush)
+ {
+ }
+
+ void paint(QPainter *p) const { p->fillRect(m_rect, m_brush); }
+ QRectF boundingRect() const { return m_rect; }
- p->drawImage(dx, dy, shadowImage);
- p->fillRect(shadowRect, p->brush());
+ private:
+ QRectF m_rect;
+ QBrush m_brush;
+ };
+
+ class FillPathShadow : public ShadowImageMaker
+ {
+ public:
+ FillPathShadow(const QPainterPath &path, const QBrush &brush)
+ : m_path(path)
+ , m_brush(brush)
+ {
+ }
+
+ void paint(QPainter *p) const { p->fillPath(m_path, m_brush); }
+ QRectF boundingRect() const { return m_path.boundingRect(); }
+
+ private:
+ QPainterPath m_path;
+ QBrush m_brush;
+ };
+
+ class StrokePathShadow : public ShadowImageMaker
+ {
+ public:
+ StrokePathShadow(const QPainterPath &path, const QPen &pen)
+ : m_path(path)
+ , m_pen(pen)
+ {
+ }
+
+ void paint(QPainter *p) const { p->strokePath(m_path, m_pen); }
+
+ QRectF boundingRect() const
+ {
+ qreal d = qMax(qreal(1), m_pen.widthF());
+ return m_path.boundingRect().adjusted(-d, -d, d, d);
+ }
+
+ private:
+ QPainterPath m_path;
+ QPen m_pen;
+ };
+
+ class DrawImageShadow : public ShadowImageMaker
+ {
+ public:
+ DrawImageShadow(const QImage &image, const QPointF &offset)
+ : m_image(image)
+ , m_offset(offset)
+ {
+ }
+
+ void paint(QPainter *p) const { p->drawImage(m_offset, m_image); }
+
+ QRectF boundingRect() const { return QRectF(m_image.rect()).translated(m_offset); }
+
+ private:
+ QImage m_image;
+ QPointF m_offset;
+ };
+}
+
+static void fillRectShadow(QPainter* p, QRectF shadowRect, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
+{
+ FillRectShadow shadowMaker(shadowRect, p->brush());
+ shadowMaker.paintShapeAndShadow(p, offsetX, offsetY, blur, color);
}
static void fillShadowPath(QPainter* p, const QPainterPath& path, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
{
- QRectF r = path.boundingRect();
- QImage img(r.size().width() + r.left() + 1,
- r.size().height() + r.top() + 1,
- QImage::Format_ARGB32_Premultiplied);
- img.fill(0);
- QPainter tp(&img);
- tp.fillPath(path.translated(0, 0), p->brush());
- tp.end();
-
- QImage shadowImage = makeShadowImage(img, offsetX, offsetY, blur, color);
- qreal dx = r.left() + (offsetX < 0? offsetX:0);
- qreal dy = r.top() + (offsetY < 0? offsetY:0);
-
- p->drawImage(dx, dy, shadowImage);
- p->fillPath(path, p->brush());
+ FillPathShadow shadowMaker(path, p->brush());
+ shadowMaker.paintShapeAndShadow(p, offsetX, offsetY, blur, color);
}
static void strokeShadowPath(QPainter* p, const QPainterPath& path, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
{
- QRectF r = path.boundingRect();
- QImage img(r.size().width() + r.left() + 1,
- r.size().height() + r.top() + 1,
- QImage::Format_ARGB32_Premultiplied);
- img.fill(0);
- QPainter tp(&img);
- tp.strokePath(path, p->pen());
- tp.end();
-
- QImage shadowImage = makeShadowImage(img, offsetX, offsetY, blur, color);
- qreal dx = r.left() + (offsetX < 0? offsetX:0);
- qreal dy = r.top() + (offsetY < 0? offsetY:0);
- p->drawImage(dx, dy, shadowImage);
- p->strokePath(path, p->pen());
+ StrokePathShadow shadowMaker(path, p->pen());
+ shadowMaker.paintShapeAndShadow(p, offsetX, offsetY, blur, color);
}
+
static inline void drawRepeatPattern(QPainter* p, const QImage& image, const QRectF& rect, const bool repeatX, const bool repeatY)
{
// Patterns must be painted so that the top left of the first image is anchored at
@@ -259,15 +309,16 @@ static void qt_drawImage(QPainter *p, QQuickContext2D::State& state, QImage imag
if (sw != dw || sh != dh)
image = image.scaled(dw, dh);
- if (shadow) {
- QImage shadow = makeShadowImage(image, state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
- qreal shadow_dx = dx + (state.shadowOffsetX < 0? state.shadowOffsetY:0);
- qreal shadow_dy = dy + (state.shadowOffsetX < 0? state.shadowOffsetY:0);
- p->drawImage(shadow_dx, shadow_dy, shadow);
- }
//Strange OpenGL painting behavior here, without beginNativePainting/endNativePainting, only the first image is painted.
p->beginNativePainting();
- p->drawImage(dx, dy, image);
+
+ if (shadow) {
+ DrawImageShadow shadowMaker(image, QPointF(dx, dy));
+ shadowMaker.paintShapeAndShadow(p, state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
+ } else {
+ p->drawImage(dx, dy, image);
+ }
+
p->endNativePainting();
}
@@ -295,12 +346,9 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
case QQuickContext2D::ClearRect:
{
QPainter::CompositionMode cm = p->compositionMode();
- qreal alpha = p->opacity();
- p->setCompositionMode(QPainter::CompositionMode_Source);
- p->setOpacity(0);
- p->fillRect(takeRect(), QColor(qRgba(0, 0, 0, 0)));
+ p->setCompositionMode(QPainter::CompositionMode_Clear);
+ p->fillRect(takeRect(), Qt::white);
p->setCompositionMode(cm);
- p->setOpacity(alpha);
break;
}
case QQuickContext2D::FillRect:
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index 729e32e564..84ab5bb8fb 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -586,6 +586,7 @@ QQuickCanvasItem::RenderTarget QQuickContext2DImageTexture::renderTarget() const
void QQuickContext2DImageTexture::bind()
{
imageTexture()->bind();
+ updateBindOptions();
}
bool QQuickContext2DImageTexture::updateTexture()
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 0a0fac307c..2025db4fc8 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -156,6 +156,9 @@ QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
if (!parent->property("value").isNull()) {
connect(parent, SIGNAL(valueChanged()), this, SLOT(valueChanged()));
}
+ if (!parent->property("cursorPosition").isNull()) {
+ connect(parent, SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChanged()));
+ }
}
QQuickAccessibleAttached::~QQuickAccessibleAttached()
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 2124356a70..131b379a07 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -142,6 +142,10 @@ public Q_SLOTS:
QAccessibleValueChangeEvent ev(parent(), parent()->property("value"));
QAccessible::updateAccessibility(&ev);
}
+ void cursorPositionChanged() {
+ QAccessibleTextCursorEvent ev(parent(), parent()->property("cursorPosition").toInt());
+ QAccessible::updateAccessibility(&ev);
+ }
Q_SIGNALS:
void roleChanged();
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index 55b3e569ef..e828899204 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -114,13 +114,13 @@ public:
\ingroup qtquick-input
\brief For specifying drag and drop events for moved Items
- Using the Drag attached property any Item can made a source of drag and drop
+ Using the Drag attached property any Item can be made a source of drag and drop
events within a scene.
- When a drag is \l active on an item any change in that items position will
- generate a drag events that will be sent to any DropArea that intersects
- the with new position of the item. Other items which implement drag and
- drop event handlers can also receive these events.
+ When a drag is \l active on an item any change in that item's position will
+ generate a drag event that will be sent to any DropArea that intersects
+ with the new position of the item. Other items which implement drag and
+ drop event handlers can also receive these events.
The following snippet shows how an item can be dragged with a MouseArea.
However, dragging is not limited to mouse drags, anything that can move an item
diff --git a/src/quick/items/qquickdroparea.cpp b/src/quick/items/qquickdroparea.cpp
index f930835bee..659e606ef9 100644
--- a/src/quick/items/qquickdroparea.cpp
+++ b/src/quick/items/qquickdroparea.cpp
@@ -400,7 +400,7 @@ QStringList QQuickDropEvent::keys() const
*/
/*!
- \qmlproperty real QtQuick2::DragEvent::accepted
+ \qmlproperty bool QtQuick2::DragEvent::accepted
This property holds whether the drag event was accepted by a handler.
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index 469ae9d0e4..6f1b152ad3 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -93,7 +93,7 @@ private:
QKeyEvent event;
};
-// used in QtLocation
+// used in Qt Location
class Q_QUICK_PRIVATE_EXPORT QQuickMouseEvent : public QObject
{
Q_OBJECT
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index ff56bcaa0e..e6b39d5380 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -423,12 +423,16 @@ void QQuickFlickablePrivate::fixupX_callback(void *data)
void QQuickFlickablePrivate::fixupX()
{
Q_Q(QQuickFlickable);
+ if (!q->isComponentComplete())
+ return; //Do not fixup from initialization values
fixup(hData, q->minXExtent(), q->maxXExtent());
}
void QQuickFlickablePrivate::fixupY()
{
Q_Q(QQuickFlickable);
+ if (!q->isComponentComplete())
+ return; //Do not fixup from initialization values
fixup(vData, q->minYExtent(), q->maxYExtent());
}
@@ -913,6 +917,18 @@ void QQuickFlickable::setFlickableDirection(FlickableDirection direction)
}
}
+/*!
+ \qmlproperty bool QtQuick2::Flickable::pixelAligned
+
+ This property sets the alignment of \l contentX and \l contentY to
+ pixels (\c true) or subpixels (\c false).
+
+ Enable pixelAligned to optimize for still content or moving content with
+ high constrast edges, such as one-pixel-wide lines, text or vector graphics.
+ Disable pixelAligned when optimizing for animation quality.
+
+ The default is \c false.
+*/
bool QQuickFlickable::pixelAligned() const
{
Q_D(const QQuickFlickable);
@@ -2265,7 +2281,11 @@ bool QQuickFlickablePrivate::isViewMoving() const
within the timeout, both the press and release will be delivered.
Note that for nested Flickables with pressDelay set, the pressDelay of
- outer Flickables is overridden by the innermost Flickable.
+ outer Flickables is overridden by the innermost Flickable. If the drag
+ exceeds the platform drag threshold, the press event will be delivered
+ regardless of this property.
+
+ \sa QStyleHints
*/
int QQuickFlickable::pressDelay() const
{
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 513a26e747..0186029fa0 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -101,7 +101,7 @@ public:
AxisData(QQuickFlickablePrivate *fp, void (QQuickFlickablePrivate::*func)(qreal))
: move(fp, func)
, transitionToBounds(0)
- , viewSize(-1), startMargin(0), endMargin(0)
+ , viewSize(-1), lastPos(0), startMargin(0), endMargin(0)
, origin(0)
, transitionTo(0)
, continuousFlickVelocity(0), velocityTime(), vTime(0)
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index e40d21b498..bc71a1c064 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -2564,6 +2564,22 @@ bool QQuickGridViewPrivate::needsRefillForAddedOrRemovedIndex(int modelIndex) co
\b Note: methods should only be called after the Component has completed.
*/
+
+/*!
+ \qmlmethod QtQuick2::GridView::forceLayout()
+
+ Responding to changes in the model is usually batched to happen only once
+ per frame. This means that inside script blocks it is possible for the
+ underlying model to have changed, but the GridView has not caught up yet.
+
+ This method forces the GridView to immediately respond to any outstanding
+ changes in the model.
+
+ \since QtQuick 2.1
+
+ \b Note: methods should only be called after the Component has completed.
+*/
+
QQuickGridViewAttached *QQuickGridView::qmlAttachedProperties(QObject *obj)
{
return new QQuickGridViewAttached(obj);
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 9403b7967e..6fe4b39974 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -233,6 +233,8 @@ void QQuickImagePrivate::setImage(const QImage &image)
Image {
width: 120; height: 120
fillMode: Image.Tile
+ horizontalAlignment: Image.AlignLeft
+ verticalAlignment: Image.AlignTop
source: "qtlogo.png"
}
\endqml
@@ -244,6 +246,7 @@ void QQuickImagePrivate::setImage(const QImage &image)
Image {
width: 120; height: 120
fillMode: Image.TileVertically
+ verticalAlignment: Image.AlignTop
source: "qtlogo.png"
}
\endqml
@@ -255,6 +258,7 @@ void QQuickImagePrivate::setImage(const QImage &image)
Image {
width: 120; height: 120
fillMode: Image.TileHorizontally
+ verticalAlignment: Image.AlignLeft
source: "qtlogo.png"
}
\endqml
@@ -460,7 +464,7 @@ qreal QQuickImage::paintedHeight() const
\qmlproperty enumeration QtQuick2::Image::horizontalAlignment
\qmlproperty enumeration QtQuick2::Image::verticalAlignment
- Sets the horizontal and vertical alignment of the image. By default, the image is top-left aligned.
+ Sets the horizontal and vertical alignment of the image. By default, the image is center aligned.
The valid values for \c horizontalAlignment are \c Image.AlignLeft, \c Image.AlignRight and \c Image.AlignHCenter.
The valid values for \c verticalAlignment are \c Image.AlignTop, \c Image.AlignBottom
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 4ce9b15921..d0417c80f3 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -58,6 +58,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qnumeric.h>
+#include <QtGui/qpa/qplatformtheme.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmlengine_p.h>
@@ -1365,7 +1366,7 @@ QQuickKeysAttached *QQuickKeysAttached::qmlAttachedProperties(QObject *obj)
\brief Property used to mirror layout behavior
The LayoutMirroring attached property is used to horizontally mirror \l {anchor-layout}{Item anchors},
- \l{Item Layouts}{positioner} types (such as \l Row and \l Grid)
+ \l{Item Positioners}{positioner} types (such as \l Row and \l Grid)
and views (such as \l GridView and horizontal \l ListView). Mirroring is a visual change: left
anchors become right anchors, and positioner types like \l Grid and \l Row reverse the
horizontal layout of child items.
@@ -1405,7 +1406,7 @@ QQuickKeysAttached *QQuickKeysAttached::qmlAttachedProperties(QObject *obj)
This property holds whether the item's layout is mirrored horizontally. Setting this to true
horizontally reverses \l {anchor-layout}{anchor} settings such that left anchors become right,
- and right anchors become left. For \l{Item Layouts}{positioner} types
+ and right anchors become left. For \l{Item Positioners}{positioner} types
(such as \l Row and \l Grid) and view types (such as \l {GridView}{GridView} and \l {ListView}{ListView})
this also mirrors the horizontal layout direction of the item.
@@ -1573,7 +1574,7 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
/*!
\class QQuickItem
- \brief The QQuickItem class provides the most basic of all visual items in QtQuick.
+ \brief The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
\inmodule QtQuick
All visual items in Qt Quick inherit from QQuickItem. Although a QQuickItem
@@ -2037,6 +2038,44 @@ QQuickItem::~QQuickItem()
/*!
\internal
+*/
+bool QQuickItemPrivate::qt_tab_all_widgets()
+{
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ return theme->themeHint(QPlatformTheme::TabAllWidgets).toBool();
+ return true;
+}
+
+/*!
+ \internal
+*/
+bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item)
+{
+ bool result = true;
+
+ if (!item->window())
+ return false;
+
+ if (item == item->window()->contentItem())
+ return true;
+
+#ifndef QT_NO_ACCESSIBILITY
+ result = false;
+ if (QObject *acc = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(item, false)) {
+ int role = acc->property("role").toInt();
+ if (role == QAccessible::EditableText
+ || role == QAccessible::Table
+ || role == QAccessible::List
+ || role == QAccessible::SpinBox)
+ result = true;
+ }
+#endif
+
+ return result;
+}
+
+/*!
+ \internal
\brief QQuickItemPrivate::focusNextPrev focuses the next/prev item in the tab-focus-chain
\param item The item that currently has the focus
\param forward The direction
@@ -2047,8 +2086,21 @@ QQuickItem::~QQuickItem()
*/
bool QQuickItemPrivate::focusNextPrev(QQuickItem *item, bool forward)
{
+ QQuickItem *next = QQuickItemPrivate::nextPrevItemInTabFocusChain(item, forward);
+
+ if (next == item)
+ return false;
+
+ next->forceActiveFocus(forward ? Qt::TabFocusReason : Qt::BacktabFocusReason);
+
+ return true;
+}
+
+QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, bool forward)
+{
Q_ASSERT(item);
- Q_ASSERT(item->activeFocusOnTab());
+
+ bool all = QQuickItemPrivate::qt_tab_all_widgets();
QQuickItem *from = 0;
if (forward) {
@@ -2060,6 +2112,10 @@ bool QQuickItemPrivate::focusNextPrev(QQuickItem *item, bool forward)
from = item->parentItem();
}
bool skip = false;
+ const QQuickItem * const contentItem = item->window()->contentItem();
+ const QQuickItem * const originalItem = item;
+ QQuickItem * startItem = item;
+ QQuickItem * firstFromItem = from;
QQuickItem *current = item;
do {
skip = false;
@@ -2110,16 +2166,29 @@ bool QQuickItemPrivate::focusNextPrev(QQuickItem *item, bool forward)
skip = true;
}
}
-
from = last;
- } while (skip || !current->activeFocusOnTab() || !current->isEnabled() || !current->isVisible());
-
- if (current == item)
- return false;
-
- current->forceActiveFocus(forward ? Qt::TabFocusReason : Qt::BacktabFocusReason);
+ if (current == startItem && from == firstFromItem) {
+ // wrapped around, avoid endless loops
+ if (originalItem == contentItem) {
+#ifdef FOCUS_DEBUG
+ qDebug() << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem";
+#endif
+ return item->window()->contentItem();
+ } else {
+#ifdef FOCUS_DEBUG
+ qDebug() << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return " << startItem;
+#endif
+ return startItem;
+ }
+ }
+ if (!firstFromItem) { //start from root
+ startItem = current;
+ firstFromItem = from;
+ }
+ } while (skip || !current->activeFocusOnTab() || !current->isEnabled() || !current->isVisible()
+ || !(all || QQuickItemPrivate::canAcceptTabFocus(current)));
- return true;
+ return current;
}
/*!
@@ -2255,7 +2324,8 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
}
}
- d->resolveLayoutMirror();
+ if (d->parentItem)
+ d->resolveLayoutMirror();
d->itemChange(ItemParentHasChanged, d->parentItem);
@@ -2341,13 +2411,16 @@ void QQuickItem::stackAfter(const QQuickItem *sibling)
QQuickItemPrivate::get(parentPrivate->childItems.at(ii))->siblingOrderChanged();
}
+/*! \fn void QQuickItem::windowChanged(QQuickWindow *window)
+ This signal is emitted when the item's \a window changes.
+*/
+
/*!
Returns the window in which this item is rendered.
- The item does not have a window until it has been assigned into a scene. To
- get notification about this, reimplement the itemChange() function and
- listen for the ItemSceneChange change. The itemChange() function is called
- both when the item is entered into a scene and when it is removed from a scene.
+ The item does not have a window until it has been assigned into a scene. The
+ \l windowChanged signal provides a notification both when the item is entered
+ into a scene and when it is removed from a scene.
*/
QQuickWindow *QQuickItem::window() const
{
@@ -2498,8 +2571,7 @@ void QQuickItemPrivate::derefWindow()
if (c->cursorItem == q)
c->cursorItem = 0;
#endif
- if ( hoverEnabled )
- c->hoverItems.removeAll(q);
+ c->hoverItems.removeAll(q);
if (itemNodeInstance)
c->cleanup(itemNodeInstance);
if (!parentItem)
@@ -2688,9 +2760,26 @@ void QQuickItemPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
} else {
if (o->inherits("QGraphicsItem"))
qWarning("Cannot add a QtQuick 1.0 item (%s) into a QtQuick 2.0 scene!", o->metaObject()->className());
+ else {
+ QQuickWindow *thisWindow = qmlobject_cast<QQuickWindow *>(o);
+ QQuickItem *item = that;
+ QQuickWindow *itemWindow = that->window();
+ while (!itemWindow && item && item->parentItem()) {
+ item = item->parentItem();
+ itemWindow = item->window();
+ }
+
+ if (thisWindow) {
+ if (itemWindow)
+ thisWindow->setTransientParent(itemWindow);
+ else
+ QObject::connect(item, SIGNAL(windowChanged(QQuickWindow*)),
+ thisWindow, SLOT(setTransientParent_helper(QQuickWindow*)));
+ }
+ o->setParent(that);
+ }
- // XXX todo - do we really want this behavior?
- o->setParent(that);
+ resources_append(prop, o);
}
}
@@ -2768,30 +2857,38 @@ void QQuickItemPrivate::data_clear(QQmlListProperty<QObject> *property)
QObject *QQuickItemPrivate::resources_at(QQmlListProperty<QObject> *prop, int index)
{
- const QObjectList children = prop->object->children();
- if (index < children.count())
- return children.at(index);
- else
- return 0;
+ QQuickItemPrivate *quickItemPrivate = QQuickItemPrivate::get(static_cast<QQuickItem *>(prop->object));
+ return quickItemPrivate->extra.isAllocated() ? quickItemPrivate->extra->resourcesList.value(index) : 0;
}
-void QQuickItemPrivate::resources_append(QQmlListProperty<QObject> *prop, QObject *o)
+void QQuickItemPrivate::resources_append(QQmlListProperty<QObject> *prop, QObject *object)
{
- // XXX todo - do we really want this behavior?
- o->setParent(prop->object);
+ QQuickItem *quickItem = static_cast<QQuickItem *>(prop->object);
+ QQuickItemPrivate *quickItemPrivate = QQuickItemPrivate::get(quickItem);
+ if (!quickItemPrivate->extra.value().resourcesList.contains(object)) {
+ quickItemPrivate->extra.value().resourcesList.append(object);
+ qmlobject_connect(object, QObject, SIGNAL(destroyed(QObject*)),
+ quickItem, QQuickItem, SLOT(_q_resourceObjectDeleted(QObject*)));
+ }
}
int QQuickItemPrivate::resources_count(QQmlListProperty<QObject> *prop)
{
- return prop->object->children().count();
+ QQuickItemPrivate *quickItemPrivate = QQuickItemPrivate::get(static_cast<QQuickItem *>(prop->object));
+ return quickItemPrivate->extra.isAllocated() ? quickItemPrivate->extra->resourcesList.count() : 0;
}
void QQuickItemPrivate::resources_clear(QQmlListProperty<QObject> *prop)
{
- // XXX todo - do we really want this behavior?
- const QObjectList children = prop->object->children();
- for (int index = 0; index < children.count(); index++)
- children.at(index)->setParent(0);
+ QQuickItem *quickItem = static_cast<QQuickItem *>(prop->object);
+ QQuickItemPrivate *quickItemPrivate = QQuickItemPrivate::get(quickItem);
+ if (quickItemPrivate->extra.isAllocated()) {//If extra is not allocated resources is empty.
+ foreach (QObject *object, quickItemPrivate->extra->resourcesList) {
+ qmlobject_disconnect(object, QObject, SIGNAL(destroyed(QObject*)),
+ quickItem, QQuickItem, SLOT(_q_resourceObjectDeleted(QObject*)));
+ }
+ quickItemPrivate->extra->resourcesList.clear();
+ }
}
QQuickItem *QQuickItemPrivate::children_at(QQmlListProperty<QQuickItem> *prop, int index)
@@ -2938,6 +3035,12 @@ void QQuickItemPrivate::transform_clear(QQmlListProperty<QQuickTransform> *prop)
p->dirty(QQuickItemPrivate::Transform);
}
+void QQuickItemPrivate::_q_resourceObjectDeleted(QObject *object)
+{
+ if (extra.isAllocated() && extra->resourcesList.contains(object))
+ extra->resourcesList.removeAll(object);
+}
+
/*!
\qmlproperty AnchorLine QtQuick2::Item::anchors.top
\qmlproperty AnchorLine QtQuick2::Item::anchors.bottom
@@ -3917,6 +4020,28 @@ void QQuickItem::forceActiveFocus(Qt::FocusReason reason)
}
/*!
+ \qmlmethod QtQuick2::Item::nextItemInFocusChain(bool forward)
+
+ \since QtQuick 2.1
+
+ Returns the item in the focus chain which is next to this item.
+ If \a forward is \c true, or not supplied, it is the next item in
+ the forwards direction. If \a forward is \c false, it is the next
+ item in the backwards direction.
+*/
+/*!
+ Returns the item in the focus chain which is next to this item.
+ If \a forward is \c true, or not supplied, it is the next item in
+ the forwards direction. If \a forward is \c false, it is the next
+ item in the backwards direction.
+*/
+
+QQuickItem *QQuickItem::nextItemInFocusChain(bool forward)
+{
+ return QQuickItemPrivate::nextPrevItemInTabFocusChain(this, forward);
+}
+
+/*!
\qmlmethod QtQuick2::Item::childAt(real x, real y)
Returns the first visible child item found at point (\a x, \a y) within
@@ -4280,7 +4405,8 @@ void QQuickItemPrivate::deliverKeyEvent(QKeyEvent *e)
return;
//only care about KeyPress now
- if (q->activeFocusOnTab() && e->type() == QEvent::KeyPress) {
+ if ((q == q->window()->contentItem() || q->activeFocusOnTab())
+ && e->type() == QEvent::KeyPress) {
bool res = false;
if (!(e->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
if (e->key() == Qt::Key_Backtab
@@ -4417,11 +4543,18 @@ void QQuickItemPrivate::deliverDragEvent(QEvent *e)
\a value contains extra information relating to the change, when
applicable.
+
+ If you re-implement this method in a subclass, be sure to call
+ \code
+ QQuickItem::itemChange(change, value);
+ \endcode
+ typically at the end of your implementation, to ensure the
+ \l windowChanged signal will be emitted.
*/
void QQuickItem::itemChange(ItemChange change, const ItemChangeData &value)
{
- Q_UNUSED(change);
- Q_UNUSED(value);
+ if (change == ItemSceneChange)
+ emit windowChanged(value.window);
}
#ifndef QT_NO_IM
@@ -5489,7 +5622,7 @@ void QQuickItem::setActiveFocusOnTab(bool activeFocusOnTab)
return;
if (window()) {
- if ((this == window()->activeFocusItem()) && !activeFocusOnTab) {
+ if ((this == window()->activeFocusItem()) && this != window()->contentItem() && !activeFocusOnTab) {
qWarning("QQuickItem: Cannot set activeFocusOnTab to false once item is the active focus item.");
return;
}
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index 4c99a6a9c5..6ad121fffa 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -324,6 +324,7 @@ public:
Q_INVOKABLE void mapToItem(QQmlV4Function*) const;
Q_INVOKABLE void forceActiveFocus();
Q_INVOKABLE void forceActiveFocus(Qt::FocusReason reason);
+ Q_INVOKABLE QQuickItem *nextItemInFocusChain(bool forward = true);
Q_INVOKABLE QQuickItem *childAt(qreal x, qreal y) const;
#ifndef QT_NO_IM
@@ -355,6 +356,7 @@ Q_SIGNALS:
void smoothChanged(bool);
void antialiasingChanged(bool);
void clipChanged(bool);
+ Q_REVISION(1) void windowChanged(QQuickWindow* window);
// XXX todo
void childrenChanged();
@@ -430,6 +432,8 @@ protected:
QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent = 0);
private:
+ Q_PRIVATE_SLOT(d_func(), void _q_resourceObjectDeleted(QObject *))
+
friend class QQuickWindow;
friend class QQuickWindowPrivate;
friend class QSGRenderer;
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 4bd9d82c20..0ffc092a83 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -128,7 +128,7 @@ void QQuickContents::calcGeometry(QQuickItem *changed)
class QQuickTransformPrivate : public QObjectPrivate
{
- Q_DECLARE_PUBLIC(QQuickTransform);
+ Q_DECLARE_PUBLIC(QQuickTransform)
public:
static QQuickTransformPrivate* get(QQuickTransform *transform) { return transform->d_func(); }
@@ -293,6 +293,8 @@ public:
static QQuickTransform *transform_at(QQmlListProperty<QQuickTransform> *list, int);
static void transform_clear(QQmlListProperty<QQuickTransform> *list);
+ void _q_resourceObjectDeleted(QObject *);
+
enum ChangeType {
Geometry = 0x01,
SiblingOrder = 0x02,
@@ -363,6 +365,8 @@ public:
Qt::MouseButtons acceptedMouseButtons;
QQuickItem::TransformOrigin origin:5;
+
+ QObjectList resourcesList;
};
QLazilyAllocated<ExtraData> extra;
@@ -485,6 +489,10 @@ public:
void itemToParentTransform(QTransform &) const;
static bool focusNextPrev(QQuickItem *item, bool forward);
+ static QQuickItem *nextPrevItemInTabFocusChain(QQuickItem *item, bool forward);
+
+ static bool qt_tab_all_widgets(); //todo: move to QGuiApplication?
+ static bool canAcceptTabFocus(QQuickItem *item);
qreal x;
qreal y;
@@ -886,7 +894,7 @@ QSGNode *QQuickItemPrivate::childContainerNode()
return groupNode;
}
-Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickItemPrivate::ChangeTypes);
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickItemPrivate::ChangeTypes)
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 741583a95d..6f1edc718a 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -167,6 +167,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickKeyEvent>();
qmlRegisterType<QQuickMouseEvent>();
qmlRegisterType<QQuickWheelEvent>();
+ qmlRegisterType<QQuickCloseEvent>();
qmlRegisterType<QQuickTransform>();
qmlRegisterType<QQuickPathElement>();
qmlRegisterType<QQuickCurve>();
@@ -230,7 +231,13 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickItem, 1>(uri, 2, 1,"Item");
qmlRegisterType<QQuickGrid, 1>(uri, 2, 1, "Grid");
+ qmlRegisterUncreatableType<QQuickItemView, 1>(uri, 2, 1, "ItemView", QQuickItemView::tr("ItemView is an abstract base class"));
+ qmlRegisterType<QQuickListView, 1>(uri, 2, 1, "ListView");
+ qmlRegisterType<QQuickGridView, 1>(uri, 2, 1, "GridView");
qmlRegisterType<QQuickTextEdit, 1>(uri, 2, 1, "TextEdit");
+
+ qmlRegisterType<QQuickText, 2>(uri, 2, 2, "Text");
+ qmlRegisterType<QQuickTextEdit, 2>(uri, 2, 2, "TextEdit");
}
void QQuickItemsModule::defineModule()
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 72f892178f..a6dabee7ba 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -249,7 +249,6 @@ QQuickItemView::~QQuickItemView()
QQuickItem *QQuickItemView::currentItem() const
{
Q_D(const QQuickItemView);
- const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
return d->currentItem ? d->currentItem->item : 0;
}
@@ -379,14 +378,12 @@ int QQuickItemView::count() const
Q_D(const QQuickItemView);
if (!d->model)
return 0;
- const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
return d->model->count();
}
int QQuickItemView::currentIndex() const
{
Q_D(const QQuickItemView);
- const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
return d->currentIndex;
}
@@ -496,7 +493,6 @@ QQmlComponent *QQuickItemView::header() const
QQuickItem *QQuickItemView::headerItem() const
{
Q_D(const QQuickItemView);
- const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
return d->header ? d->header->item : 0;
}
@@ -532,7 +528,6 @@ QQmlComponent *QQuickItemView::footer() const
QQuickItem *QQuickItemView::footerItem() const
{
Q_D(const QQuickItemView);
- const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
return d->footer ? d->footer->item : 0;
}
@@ -559,7 +554,6 @@ void QQuickItemView::setFooter(QQmlComponent *footerComponent)
QQmlComponent *QQuickItemView::highlight() const
{
Q_D(const QQuickItemView);
- const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
return d->highlightComponent;
}
@@ -579,7 +573,6 @@ void QQuickItemView::setHighlight(QQmlComponent *highlightComponent)
QQuickItem *QQuickItemView::highlightItem() const
{
Q_D(const QQuickItemView);
- const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
return d->highlight ? d->highlight->item : 0;
}
@@ -965,6 +958,12 @@ QQuickItem *QQuickItemView::itemAt(qreal x, qreal y) const
return 0;
}
+void QQuickItemView::forceLayout()
+{
+ Q_D(QQuickItemView);
+ d->applyPendingChanges();
+}
+
void QQuickItemViewPrivate::applyPendingChanges()
{
Q_Q(QQuickItemView);
@@ -2205,7 +2204,7 @@ FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, bool asynchronous)
if (!delegateValidated) {
delegateValidated = true;
QObject* delegate = q->delegate();
- qmlInfo(delegate ? delegate : q) << q->tr("Delegate must be of Item type");
+ qmlInfo(delegate ? delegate : q) << QQuickItemView::tr("Delegate must be of Item type");
}
}
inRequest = false;
@@ -2260,8 +2259,10 @@ void QQuickItemView::destroyingItem(QObject *object)
{
Q_D(QQuickItemView);
QQuickItem* item = qmlobject_cast<QQuickItem*>(object);
- item->setParentItem(0);
- d->unrequestedItems.remove(item);
+ if (item) {
+ item->setParentItem(0);
+ d->unrequestedItems.remove(item);
+ }
}
bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h
index b0f910680a..d7812bcdad 100644
--- a/src/quick/items/qquickitemview_p.h
+++ b/src/quick/items/qquickitemview_p.h
@@ -202,6 +202,7 @@ public:
Q_INVOKABLE QQuickItem *itemAt(qreal x, qreal y) const;
Q_INVOKABLE void positionViewAtBeginning();
Q_INVOKABLE void positionViewAtEnd();
+ Q_REVISION(1) Q_INVOKABLE void forceLayout();
virtual void setContentX(qreal pos);
virtual void setContentY(qreal pos);
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 53dc715469..4d42c9ece1 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -1659,7 +1659,7 @@ bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
A ListView displays data from models created from built-in QML types like ListModel
and XmlListModel, or custom model classes defined in C++ that inherit from
- QAbstractListModel.
+ QAbstractItemModel or QAbstractListModel.
A ListView has a \l model, which defines the data to be displayed, and
a \l delegate, which defines how the data should be displayed. Items in a
@@ -2185,7 +2185,7 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
each section.
- \snippet quick/views/listview/sections.qml 0
+ \snippet views/listview/sections.qml 0
\image qml-listview-sections-example.png
@@ -3108,6 +3108,21 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
\b Note: methods should only be called after the Component has completed.
*/
+/*!
+ \qmlmethod QtQuick2::ListView::forceLayout()
+
+ Responding to changes in the model is usually batched to happen only once
+ per frame. This means that inside script blocks it is possible for the
+ underlying model to have changed, but the ListView has not caught up yet.
+
+ This method forces the ListView to immediately respond to any outstanding
+ changes in the model.
+
+ \since QtQuick 2.1
+
+ \b Note: methods should only be called after the Component has completed.
+*/
+
QQuickListViewAttached *QQuickListView::qmlAttachedProperties(QObject *obj)
{
return new QQuickListViewAttached(obj);
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index af766ac294..8f4dc0bd17 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -264,7 +264,7 @@ qreal QQuickLoaderPrivate::getImplicitHeight() const
\c event.accepted to \c true so that the event is not propagated to the
parent \l Rectangle.
- Since QtQuick 2.0 Loader can also load non-visual components.
+ Since \c {QtQuick 2.0}, Loader can also load non-visual components.
\section2 Using a Loader within a view delegate
@@ -376,7 +376,7 @@ void QQuickLoader::setActive(bool newVal)
\qmlproperty url QtQuick2::Loader::source
This property holds the URL of the QML component to instantiate.
- Since QtQuick 2.0 Loader is able to load any type of object; it
+ Since \c {QtQuick 2.0}, Loader is able to load any type of object; it
is not restricted to Item types.
To unload the currently loaded object, set this property to an empty string,
@@ -451,7 +451,7 @@ void QQuickLoader::loadFromSource()
To unload the currently loaded object, set this property to an empty string
or \c undefined.
- Since QtQuick 2.0 Loader is able to load any type of object; it
+ Since \c {QtQuick 2.0}, Loader is able to load any type of object; it
is not restricted to Item types.
\sa source, progress
@@ -903,7 +903,7 @@ void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
\qmlproperty object QtQuick2::Loader::item
This property holds the top-level object that is currently loaded.
- Since QtQuick 2.0 Loader can load any object type.
+ Since \c {QtQuick 2.0}, Loader can load any object type.
*/
QObject *QQuickLoader::item() const
{
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index ad0a265035..a8786585da 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -773,11 +773,7 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
// ### we should skip this if these signals aren't used
// ### can GV handle this for us?
- const bool isInside = contains(d->lastPos);
- if (d->hovered && !isInside)
- setHovered(false);
- else if (!d->hovered && isInside)
- setHovered(true);
+ setHovered(contains(d->lastPos));
#ifndef QT_NO_DRAGANDDROP
if (d->drag && d->drag->target()) {
@@ -958,7 +954,8 @@ void QQuickMouseArea::ungrabMouse()
emit canceled();
emit pressedChanged();
emit pressedButtonsChanged();
- if (d->hovered) {
+
+ if (d->hovered && !isUnderMouse()) {
d->hovered = false;
emit hoveredChanged();
}
diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h
index ad15167b10..fa32f32b65 100644
--- a/src/quick/items/qquickmousearea_p.h
+++ b/src/quick/items/qquickmousearea_p.h
@@ -123,7 +123,7 @@ private:
class QQuickMouseAreaPrivate;
class QQuickWheelEvent;
-// used in QtLocation
+// used in Qt Location
class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem
{
Q_OBJECT
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 384c1c7ac8..d6b00cee14 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -47,6 +47,7 @@
#include <QMouseEvent>
#include <math.h>
#include <QDebug>
+#include <qpa/qplatformnativeinterface.h>
QT_BEGIN_NAMESPACE
@@ -322,6 +323,7 @@ void QQuickTouchPoint::setSceneY(qreal sceneY)
QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent)
: QQuickItem(parent),
+ _currentWindow(0),
_minimumTouchPoints(0),
_maximumTouchPoints(INT_MAX),
_stealMouse(false)
@@ -331,6 +333,9 @@ QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent)
if (qmlVisualTouchDebugging()) {
setFlag(QQuickItem::ItemHasContents);
}
+#ifdef Q_OS_MAC
+ connect(this, &QQuickItem::windowChanged, this, &QQuickMultiPointTouchArea::setTouchEventsEnabledForWindow);
+#endif
}
QQuickMultiPointTouchArea::~QQuickMultiPointTouchArea()
@@ -542,6 +547,29 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
_pressedTouchPoints.append(dtp);
}
+void QQuickMultiPointTouchArea::setTouchEventsEnabledForWindow(QWindow *window)
+{
+#ifdef Q_OS_MAC
+ // Resolve function for enabling touch events from the (cocoa) platform plugin.
+ typedef void (*RegisterTouchWindowFunction)(QWindow *, bool);
+ RegisterTouchWindowFunction registerTouchWindow = reinterpret_cast<RegisterTouchWindowFunction>(
+ QGuiApplication::platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow"));
+ if (!registerTouchWindow)
+ return; // Not necessarily an error, Qt migh be using a different platform plugin.
+
+ // Disable touch on the old window, enable on the new window.
+ if (_currentWindow)
+ registerTouchWindow(_currentWindow, false);
+ if (window)
+ registerTouchWindow(window, true);
+ // Save the current window, setTouchEventsEnabledForWindow will be called
+ // with a null window on disable.
+ _currentWindow = window;
+#else // Q_OS_MAC
+ Q_UNUSED(window)
+#endif
+}
+
void QQuickMultiPointTouchArea::addTouchPrototype(QQuickTouchPoint *prototype)
{
int id = _touchPrototypes.count();
diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h
index e2ae5ed24e..afe7d4b77b 100644
--- a/src/quick/items/qquickmultipointtoucharea_p.h
+++ b/src/quick/items/qquickmultipointtoucharea_p.h
@@ -251,6 +251,9 @@ protected:
void grabGesture();
virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+protected slots:
+ void setTouchEventsEnabledForWindow(QWindow *window);
+
private:
void ungrab();
QMap<int,QQuickTouchPoint*> _touchPrototypes; //TouchPoints defined in QML
@@ -258,6 +261,7 @@ private:
QList<QObject*> _releasedTouchPoints;
QList<QObject*> _pressedTouchPoints;
QList<QObject*> _movedTouchPoints;
+ QWindow *_currentWindow;
int _minimumTouchPoints;
int _maximumTouchPoints;
bool _stealMouse;
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index e9aa6985fc..7798641fcd 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -159,7 +159,7 @@ QQuickItem *QQuickPathViewPrivate::getItem(int modelIndex, qreal z, bool async)
if (!delegateValidated) {
delegateValidated = true;
QObject* delegate = q->delegate();
- qmlInfo(delegate ? delegate : q) << q->tr("Delegate must be of Item type");
+ qmlInfo(delegate ? delegate : q) << QQuickPathView::tr("Delegate must be of Item type");
}
}
} else {
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index 0e47b61319..434eaa8723 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -45,6 +45,7 @@
#include <QtGui/qevent.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qstylehints.h>
+#include <qpa/qplatformnativeinterface.h>
#include <float.h>
#include <math.h>
@@ -246,11 +247,15 @@ QQuickPinchAreaPrivate::~QQuickPinchAreaPrivate()
QQuickPinchArea::QQuickPinchArea(QQuickItem *parent)
: QQuickItem(*(new QQuickPinchAreaPrivate), parent)
+ , _currentWindow(0)
{
Q_D(QQuickPinchArea);
d->init();
setAcceptedMouseButtons(Qt::LeftButton);
setFiltersChildMouseEvents(true);
+#ifdef Q_OS_MAC
+ connect(this, &QQuickItem::windowChanged, this, &QQuickPinchArea::setTouchEventsEnabledForWindow);
+#endif
}
QQuickPinchArea::~QQuickPinchArea()
@@ -539,6 +544,29 @@ QQuickPinch *QQuickPinchArea::pinch()
return d->pinch;
}
+void QQuickPinchArea::setTouchEventsEnabledForWindow(QWindow *window)
+{
+#ifdef Q_OS_MAC
+ // Resolve function for enabling touch events from the (cocoa) platform plugin.
+ typedef void (*RegisterTouchWindowFunction)(QWindow *, bool);
+ RegisterTouchWindowFunction registerTouchWindow = reinterpret_cast<RegisterTouchWindowFunction>(
+ QGuiApplication::platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow"));
+ if (!registerTouchWindow)
+ return; // Not necessarily an error, Qt migh be using a different platform plugin.
+
+ // Disable touch on the old window, enable on the new window.
+ if (_currentWindow)
+ registerTouchWindow(_currentWindow, false);
+ if (window)
+ registerTouchWindow(window, true);
+ // Save the current window, setTouchEventsEnabledForWindow will be called
+ // with a null window on disable.
+ _currentWindow = window;
+#else // Q_OS_MAC
+ Q_UNUSED(window)
+#endif
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h
index 4fc77d7f9c..60c2dc742e 100644
--- a/src/quick/items/qquickpincharea_p.h
+++ b/src/quick/items/qquickpincharea_p.h
@@ -283,12 +283,16 @@ protected:
const QRectF &oldGeometry);
virtual void itemChange(ItemChange change, const ItemChangeData& value);
+private slots:
+ void setTouchEventsEnabledForWindow(QWindow *window);
+
private:
void updatePinch();
void handlePress();
void handleRelease();
private:
+ QWindow *_currentWindow;
Q_DISABLE_COPY(QQuickPinchArea)
Q_DECLARE_PRIVATE(QQuickPinchArea)
};
diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp
index 4a74c0bfba..b07a38cdaf 100644
--- a/src/quick/items/qquickpositioners.cpp
+++ b/src/quick/items/qquickpositioners.cpp
@@ -452,7 +452,6 @@ void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *sp
QQuickPositionerAttached *prevLastProperty = 0;
QQuickPositionerAttached *lastProperty = 0;
- int visibleItemIndex = 0;
for (int ii = 0; ii < positionedItems.count(); ++ii) {
const PositionedItem &child = positionedItems.at(ii);
if (!child.item)
@@ -468,28 +467,47 @@ void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *sp
property = static_cast<QQuickPositionerAttached *>(qmlAttachedPropertiesObject<QQuickBasePositioner>(child.item, false));
}
- if (child.isVisible) {
- if (property) {
- property->setIndex(visibleItemIndex);
- property->setIsFirstItem(visibleItemIndex == 0);
+ if (property) {
+ property->setIndex(ii);
+ property->setIsFirstItem(ii == 0);
- if (property->isLastItem())
+ if (property->isLastItem()) {
+ if (prevLastProperty)
+ prevLastProperty->setIsLastItem(false); // there can be only one last property
prevLastProperty = property;
}
-
- lastProperty = property;
- ++visibleItemIndex;
- } else if (property) {
- property->setIndex(-1);
- property->setIsFirstItem(false);
- property->setIsLastItem(false);
}
+
+ lastProperty = property;
}
if (prevLastProperty && prevLastProperty != lastProperty)
prevLastProperty->setIsLastItem(false);
if (lastProperty)
lastProperty->setIsLastItem(true);
+
+ // clear attached properties for unpositioned items
+ for (int ii = 0; ii < unpositionedItems.count(); ++ii) {
+ const PositionedItem &child = unpositionedItems.at(ii);
+ if (!child.item)
+ continue;
+
+ QQuickPositionerAttached *property = 0;
+
+ if (specificProperty) {
+ if (specificPropertyOwner == child.item) {
+ property = specificProperty;
+ }
+ } else {
+ property = static_cast<QQuickPositionerAttached *>(qmlAttachedPropertiesObject<QQuickBasePositioner>(child.item, false));
+ }
+
+ if (property) {
+ property->setIndex(-1);
+ property->setIsFirstItem(false);
+ property->setIsLastItem(false);
+ }
+ }
}
/*!
@@ -608,7 +626,7 @@ void QQuickPositionerAttached::setIsLastItem(bool isLastItem)
more information about its position within the Column.
For more information on using Column and other related positioner-types, see
- \l{Item Layouts}.
+ \l{Item Positioners}.
\section1 Using Transitions
@@ -626,7 +644,7 @@ void QQuickPositionerAttached::setIsLastItem(bool isLastItem)
\image verticalpositioner_transition.gif
- \sa Row, Grid, Flow, Positioner, {qml/positioners}{Positioners example}
+ \sa Row, Grid, Flow, Positioner, ColumnLayout, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Column::populate
@@ -639,7 +657,7 @@ void QQuickPositionerAttached::setIsLastItem(bool isLastItem)
the item that is being added. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \sa add, ViewTransition, {declarative/positioners}{Positioners example}
+ \sa add, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Column::add
@@ -661,7 +679,7 @@ void QQuickPositionerAttached::setIsLastItem(bool isLastItem)
\note This transition is not applied to the items that already part of the positioner
at the time of its creation. In this case, the \l populate transition is applied instead.
- \sa populate, ViewTransition, {declarative/positioners}{Positioners example}
+ \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Column::move
@@ -682,11 +700,11 @@ void QQuickPositionerAttached::setIsLastItem(bool isLastItem)
cases, these lists will be empty. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \note In QtQuick 1, this transition was applied to all items that were part of the
- positioner at the time of its creation. From QtQuick 2 onwards, positioners apply the
+ \note In \l {Qt Quick 1}, this transition was applied to all items that were part of the
+ positioner at the time of its creation. From \l {Qt Quick}{Qt Quick 2} onwards, positioners apply the
\l populate transition to these items instead.
- \sa add, ViewTransition, {qml/positioners}{Positioners example}
+ \sa add, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty real QtQuick2::Column::spacing
@@ -777,10 +795,10 @@ void QQuickColumn::reportConflictingAnchors()
more information about its position within the Row.
For more information on using Row and other related positioner-types, see
- \l{Item Layouts}.
+ \l{Item Positioners}.
- \sa Column, Grid, Flow, Positioner, {qml/positioners}{Positioners example}
+ \sa Column, Grid, Flow, Positioner, RowLayout, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Row::populate
@@ -793,7 +811,7 @@ void QQuickColumn::reportConflictingAnchors()
the item that is being added. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \sa add, ViewTransition, {declarative/positioners}{Positioners example}
+ \sa add, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Row::add
@@ -815,7 +833,7 @@ void QQuickColumn::reportConflictingAnchors()
\note This transition is not applied to the items that already part of the positioner
at the time of its creation. In this case, the \l populate transition is applied instead.
- \sa populate, ViewTransition, {declarative/positioners}{Positioners example}
+ \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Row::move
@@ -836,11 +854,11 @@ void QQuickColumn::reportConflictingAnchors()
cases, these lists will be empty. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \note In QtQuick 1, this transition was applied to all items that were part of the
- positioner at the time of its creation. From QtQuick 2 onwards, positioners apply the
+ \note In \l {Qt Quick 1}, this transition was applied to all items that were part of the
+ positioner at the time of its creation. From \l {Qt Quick}{QtQuick 2} onwards, positioners apply the
\l populate transition to these items instead.
- \sa add, ViewTransition, {qml/positioners}{Positioners example}
+ \sa add, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty real QtQuick2::Row::spacing
@@ -869,7 +887,7 @@ QQuickRow::QQuickRow(QQuickItem *parent)
the right anchor remains to the right of the row.
\endlist
- \sa Grid::layoutDirection, Flow::layoutDirection, {qml/righttoleft/layoutdirection}{Layout directions example}
+ \sa Grid::layoutDirection, Flow::layoutDirection, {Qt Quick Examples - Right to Left}
*/
Qt::LayoutDirection QQuickRow::layoutDirection() const
@@ -1010,10 +1028,10 @@ void QQuickRow::reportConflictingAnchors()
or anchor itself with any of the \l {Item::anchors}{anchor} properties.
For more information on using Grid and other related positioner-types, see
- \l{Item Layouts}.
+ \l{Item Positioners}.
- \sa Flow, Row, Column, Positioner, {qml/positioners}{Positioners example}
+ \sa Flow, Row, Column, Positioner, GridLayout, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Grid::populate
@@ -1026,7 +1044,7 @@ void QQuickRow::reportConflictingAnchors()
the item that is being added. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \sa add, ViewTransition, {declarative/positioners}{Positioners example}
+ \sa add, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Grid::add
@@ -1048,7 +1066,7 @@ void QQuickRow::reportConflictingAnchors()
\note This transition is not applied to the items that already part of the positioner
at the time of its creation. In this case, the \l populate transition is applied instead.
- \sa populate, ViewTransition, {declarative/positioners}{Positioners example}
+ \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Grid::move
@@ -1069,11 +1087,11 @@ void QQuickRow::reportConflictingAnchors()
cases, these lists will be empty. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \note In QtQuick 1, this transition was applied to all items that were part of the
- positioner at the time of its creation. From QtQuick 2 onwards, positioners apply the
+ \note In \l {Qt Quick 1}, this transition was applied to all items that were part of the
+ positioner at the time of its creation. From \l {Qt Quick}{QtQuick 2} onwards, positioners apply the
\l populate transition to these items instead.
- \sa add, ViewTransition, {qml/positioners}{Positioners example}
+ \sa add, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty qreal QtQuick2::Grid::spacing
@@ -1230,7 +1248,7 @@ void QQuickGrid::setColumnSpacing(const qreal columnSpacing)
\l Grid::flow property.
\endlist
- \sa Flow::layoutDirection, Row::layoutDirection, {qml/righttoleft/layoutdirection}{Layout directions example}
+ \sa Flow::layoutDirection, Row::layoutDirection, {Qt Quick Examples - Right to Left}
*/
Qt::LayoutDirection QQuickGrid::layoutDirection() const
{
@@ -1552,9 +1570,9 @@ void QQuickGrid::reportConflictingAnchors()
or anchor itself with any of the \l {Item::anchors}{anchor} properties.
For more information on using Flow and other related positioner-types, see
- \l{Item Layouts}.
+ \l{Item Positioners}.
- \sa Column, Row, Grid, Positioner, {qml/positioners}{Positioners example}
+ \sa Column, Row, Grid, Positioner, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Flow::populate
@@ -1567,7 +1585,7 @@ void QQuickGrid::reportConflictingAnchors()
the item that is being added. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \sa add, ViewTransition, {declarative/positioners}{Positioners example}
+ \sa add, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Flow::add
@@ -1589,7 +1607,7 @@ void QQuickGrid::reportConflictingAnchors()
\note This transition is not applied to the items that already part of the positioner
at the time of its creation. In this case, the \l populate transition is applied instead.
- \sa populate, ViewTransition, {declarative/positioners}{Positioners example}
+ \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty Transition QtQuick2::Flow::move
@@ -1610,11 +1628,11 @@ void QQuickGrid::reportConflictingAnchors()
cases, these lists will be empty. See the \l ViewTransition documentation for more details
and examples on using these transitions.
- \note In QtQuick 1, this transition was applied to all items that were part of the
- positioner at the time of its creation. From QtQuick 2 onwards, positioners apply the
+ \note In \l {Qt Quick 1}, this transition was applied to all items that were part of the
+ positioner at the time of its creation. From \l {Qt Quick}{QtQuick 2} onwards, positioners apply the
\l populate transition to these items instead.
- \sa add, ViewTransition, {qml/positioners}{Positioners example}
+ \sa add, ViewTransition, {Qt Quick Examples - Positioners}
*/
/*!
\qmlproperty real QtQuick2::Flow::spacing
@@ -1692,7 +1710,7 @@ void QQuickFlow::setFlow(Flow flow)
\l Flow::flow property.
\endlist
- \sa Grid::layoutDirection, Row::layoutDirection, {qml/righttoleft/layoutdirection}{Layout directions example}
+ \sa Grid::layoutDirection, Row::layoutDirection, {Qt Quick Examples - Right to Left}
*/
Qt::LayoutDirection QQuickFlow::layoutDirection() const
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index 3c3bd8897b..c9f37930e2 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -302,7 +302,7 @@ int QQuickRectanglePrivate::doUpdateSlotIdx = -1;
\clearfloat
\section1 Performance
- Using the \l antialiasing property improves the appearance of a rounded rectangle at
+ Using the \l Item::antialiasing property improves the appearance of a rounded rectangle at
the cost of rendering performance. You should consider unsetting this property
for rectangles in motion, and only set it when they are stationary.
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index 35e37d1246..d92b3b43d8 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -217,7 +217,7 @@ void QQuickRepeater::setModel(const QVariant &model)
d->model = new QQmlDelegateModel(qmlContext(this));
d->ownModel = true;
if (isComponentComplete())
- static_cast<QQmlDelegateModel *>(d->model)->componentComplete();
+ static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
}
if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model))
dataModel->setModel(model);
@@ -329,7 +329,7 @@ void QQuickRepeater::componentComplete()
{
Q_D(QQuickRepeater);
if (d->model && d->ownModel)
- static_cast<QQmlDelegateModel *>(d->model)->componentComplete();
+ static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
QQuickItem::componentComplete();
regenerate();
if (d->model && d->model->count())
@@ -351,11 +351,12 @@ void QQuickRepeater::clear()
if (d->model) {
for (int i = 0; i < d->deletables.count(); ++i) {
- QQuickItem *item = d->deletables.at(i);
- if (complete)
- emit itemRemoved(i, item);
- item->setParentItem(0);
- d->model->release(item);
+ if (QQuickItem *item = d->deletables.at(i)) {
+ if (complete)
+ emit itemRemoved(i, item);
+ item->setParentItem(0);
+ d->model->release(item);
+ }
}
}
d->deletables.clear();
@@ -395,7 +396,7 @@ void QQuickRepeaterPrivate::createItems()
if (!delegateValidated) {
delegateValidated = true;
QObject* delegate = q->delegate();
- qmlInfo(delegate ? delegate : q) << q->tr("Delegate must be of Item type");
+ qmlInfo(delegate ? delegate : q) << QQuickRepeater::tr("Delegate must be of Item type");
}
}
createFrom = ii;
diff --git a/src/quick/items/qquickrepeater_p_p.h b/src/quick/items/qquickrepeater_p_p.h
index f220eb4fcb..a642f6479a 100644
--- a/src/quick/items/qquickrepeater_p_p.h
+++ b/src/quick/items/qquickrepeater_p_p.h
@@ -73,7 +73,7 @@ public:
private:
void createItems();
- QQmlInstanceModel *model;
+ QPointer<QQmlInstanceModel> model;
QVariant dataSource;
QQmlGuard<QObject> dataSourceAsObject;
bool ownModel : 1;
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index 33a831acad..80080d8b88 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE
To use this type, you will need to import the module with the following line:
\code
- import QtQuick.Window 2.0
+ import QtQuick.Window 2.1
\endcode
It is a separate import in order to allow you to have a QML environment
without access to window system features.
@@ -80,6 +80,13 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \qmlattachedproperty String QtQuick.Window2::Screen::name
+ \readonly
+ \since Qt 5.1
+
+ The name of the screen.
+*/
+/*!
\qmlattachedproperty int QtQuick.Window2::Screen::width
\readonly
@@ -92,6 +99,43 @@ QT_BEGIN_NAMESPACE
This contains the height of the screen in pixels.
*/
/*!
+ \qmlattachedproperty int QtQuick.Window2::Screen::desktopAvailableWidth
+ \readonly
+ \since Qt 5.1
+
+ This contains the available width of the collection of screens which make
+ up the virtual desktop, in pixels, excluding window manager reserved areas
+ such as task bars and system menus. If you want to position a Window at
+ the right of the desktop, you can bind to it like this:
+
+ \qml
+ x: Screen.desktopAvailableWidth - width
+ \endqml
+*/
+/*!
+ \qmlattachedproperty int QtQuick.Window2::Screen::desktopAvailableHeight
+ \readonly
+ \since Qt 5.1
+
+ This contains the available height of the collection of screens which make
+ up the virtual desktop, in pixels, excluding window manager reserved areas
+ such as task bars and system menus. If you want to position a Window at
+ the bottom of the desktop, you can bind to it like this:
+
+ \qml
+ y: Screen.desktopAvailableHeight - height
+ \endqml
+*/
+/*!
+ \qmlattachedproperty real QtQuick.Window2::Screen::logicalPixelDensity
+ \readonly
+ \since Qt 5.1
+
+ The number of logical pixels per millimeter. Logical pixels are the
+ usual units in QML; on some systems they may be different than physical
+ pixels.
+*/
+/*!
\qmlattachedproperty Qt::ScreenOrientation QtQuick.Window2::Screen::primaryOrientation
\readonly
@@ -147,6 +191,13 @@ QQuickScreenAttached::QQuickScreenAttached(QObject* attachee)
}
}
+QString QQuickScreenAttached::name() const
+{
+ if (!m_screen)
+ return QString();
+ return m_screen->name();
+}
+
int QQuickScreenAttached::width() const
{
if (!m_screen)
@@ -161,6 +212,27 @@ int QQuickScreenAttached::height() const
return m_screen->size().height();
}
+int QQuickScreenAttached::desktopAvailableWidth() const
+{
+ if (!m_screen)
+ return 0;
+ return m_screen->availableVirtualSize().width();
+}
+
+int QQuickScreenAttached::desktopAvailableHeight() const
+{
+ if (!m_screen)
+ return 0;
+ return m_screen->availableVirtualSize().height();
+}
+
+qreal QQuickScreenAttached::logicalPixelDensity() const
+{
+ if (!m_screen)
+ return 0.0;
+ return m_screen->logicalDotsPerInch() / 25.4;
+}
+
Qt::ScreenOrientation QQuickScreenAttached::primaryOrientation() const
{
if (!m_screen)
@@ -209,12 +281,16 @@ void QQuickScreenAttached::screenChanged(QScreen *screen)
emit widthChanged();
emit heightChanged();
}
-
+ if (!oldScreen || screen->name() != oldScreen->name())
+ emit nameChanged();
if (!oldScreen || screen->orientation() != oldScreen->orientation())
emit orientationChanged();
if (!oldScreen || screen->primaryOrientation() != oldScreen->primaryOrientation())
emit primaryOrientationChanged();
-
+ if (!oldScreen || screen->availableVirtualGeometry() != oldScreen->availableVirtualGeometry())
+ emit desktopGeometryChanged();
+ if (!oldScreen || screen->logicalDotsPerInch() != oldScreen->logicalDotsPerInch())
+ emit logicalPixelDensityChanged();
connect(screen, SIGNAL(geometryChanged(QRect)),
this, SIGNAL(widthChanged()));
@@ -224,6 +300,10 @@ void QQuickScreenAttached::screenChanged(QScreen *screen)
this, SIGNAL(orientationChanged()));
connect(screen, SIGNAL(primaryOrientationChanged(Qt::ScreenOrientation)),
this, SIGNAL(primaryOrientationChanged()));
+ connect(screen, SIGNAL(virtualGeometryChanged(const QRect &)),
+ this, SIGNAL(desktopGeometryChanged()));
+ connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)),
+ this, SIGNAL(logicalPixelDensityChanged()));
}
}
diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h
index 98f38b7154..b35fd04e58 100644
--- a/src/quick/items/qquickscreen_p.h
+++ b/src/quick/items/qquickscreen_p.h
@@ -58,16 +58,24 @@ class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QObject
{
Q_OBJECT
+ Q_PROPERTY(QString name READ name NOTIFY nameChanged REVISION 1);
Q_PROPERTY(int width READ width NOTIFY widthChanged)
Q_PROPERTY(int height READ height NOTIFY heightChanged)
+ Q_PROPERTY(int desktopAvailableWidth READ desktopAvailableWidth NOTIFY desktopGeometryChanged REVISION 1)
+ Q_PROPERTY(int desktopAvailableHeight READ desktopAvailableHeight NOTIFY desktopGeometryChanged REVISION 1)
+ Q_PROPERTY(qreal logicalPixelDensity READ logicalPixelDensity NOTIFY logicalPixelDensityChanged REVISION 1)
Q_PROPERTY(Qt::ScreenOrientation primaryOrientation READ primaryOrientation NOTIFY primaryOrientationChanged)
Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged)
public:
QQuickScreenAttached(QObject* attachee);
+ QString name() const;
int width() const;
int height() const;
+ int desktopAvailableWidth() const;
+ int desktopAvailableHeight() const;
+ qreal logicalPixelDensity() const;
Qt::ScreenOrientation primaryOrientation() const;
Qt::ScreenOrientation orientation() const;
@@ -77,8 +85,11 @@ public:
void windowChanged(QQuickWindow*);
Q_SIGNALS:
+ Q_REVISION(1) void nameChanged();
void widthChanged();
void heightChanged();
+ Q_REVISION(1) void desktopGeometryChanged();
+ Q_REVISION(1) void logicalPixelDensityChanged();
void primaryOrientationChanged();
void orientationChanged();
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 102066704b..f39a15070c 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -912,8 +912,8 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
{
QQuickShaderEffectNode *node = static_cast<QQuickShaderEffectNode *>(oldNode);
- // In the case of a bad vertex shader, don't try to create a node...
- if (m_common.attributes.isEmpty()) {
+ // In the case of zero-size or a bad vertex shader, don't try to create a node...
+ if (m_common.attributes.isEmpty() || width() <= 0 || height() <= 0) {
if (node)
delete node;
return 0;
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 59b788643a..9debfe35b3 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -468,7 +468,7 @@ QImage QQuickShaderEffectTexture::toImage() const
\since QtQuick 2.0
\inherits Item
\ingroup qtquick-effects
- \brief Renders a QtQuick item into a texture and displays it
+ \brief Renders a \l {Qt Quick} item into a texture and displays it
The ShaderEffectSource type renders \l sourceItem into a texture and
displays it in the scene. \l sourceItem is drawn into the texture as though
@@ -478,7 +478,7 @@ QImage QQuickShaderEffectTexture::toImage() const
ShaderEffectSource can be used as:
\list
\li a texture source in a \l ShaderEffect.
- This allows you to apply custom shader effects to any QtQuick item.
+ This allows you to apply custom shader effects to any \l {Qt Quick} item.
\li a cache for a complex item.
The complex item can be rendered once into the texture, which can
then be animated freely without the need to render the complex item
@@ -942,7 +942,7 @@ void QQuickShaderEffectSource::releaseResources()
QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
- if (!m_sourceItem || m_sourceItem->width() == 0 || m_sourceItem->height() == 0) {
+ if (!m_sourceItem || m_sourceItem->width() <= 0 || m_sourceItem->height() <= 0) {
if (m_texture)
m_texture->setItem(0);
delete oldNode;
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 9a90b408c3..cc2cbb3cb3 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -107,6 +107,7 @@ void QQuickTextPrivate::init()
Q_Q(QQuickText);
q->setAcceptedMouseButtons(Qt::LeftButton);
q->setFlag(QQuickItem::ItemHasContents);
+ q->setAcceptHoverEvents(true);
}
QQuickTextDocumentWithImageResources::QQuickTextDocumentWithImageResources(QQuickItem *parent)
@@ -313,7 +314,8 @@ qreal QQuickTextPrivate::getImplicitHeight() const
combination with the NativeRendering render type will lend poor and sometimes pixelated
results.
- On HighDpi "retina" displays this property is ignored and QtRendering is always used.
+ On HighDpi "retina" displays and mobile and embedded platforms, this property is ignored
+ and QtRendering is always used.
*/
QQuickText::RenderType QQuickText::renderType() const
{
@@ -953,7 +955,10 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
// Create the remainder of the unwrapped lines up to maxLineCount to get the
// implicit width.
- if (line.isValid() && layoutText.at(line.textStart() + line.textLength()) != QChar::LineSeparator)
+ const int eol = line.isValid()
+ ? line.textStart() + line.textLength()
+ : layoutText.length();
+ if (eol < layoutText.length() && layoutText.at(eol) != QChar::LineSeparator)
line = layout.createLine();
for (; line.isValid() && unwrappedLineCount <= maxLineCount; ++unwrappedLineCount)
line = layout.createLine();
@@ -1334,10 +1339,10 @@ QQuickText::~QQuickText()
\snippet qml/text/onLinkActivated.qml 0
The example code will display the text
- "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
+ "See the \l{http://qt-project.org}{Qt Project website}."
Clicking on the highlighted link will output
- \tt{http://qt.nokia.com link activated} to the console.
+ \tt{http://qt-project.org link activated} to the console.
*/
/*!
@@ -1988,6 +1993,7 @@ void QQuickText::setTextFormat(TextFormat format)
d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
} else {
d->rightToLeftText = d->text.isRightToLeft();
+ d->textHasChanged = true;
}
d->determineHorizontalAlignment();
}
@@ -2150,9 +2156,10 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
goto geomChangeDone;
- if (effectiveHAlign() != QQuickText::AlignLeft && widthChanged) {
+ if ((effectiveHAlign() != QQuickText::AlignLeft && widthChanged)
+ || vAlign() != QQuickText::AlignTop && heightChanged) {
// If the width has changed and we're not left aligned do an update so the text is
- // repositioned even if a full layout isn't required.
+ // repositioned even if a full layout isn't required. And the same for vertical.
d->updateType = QQuickTextPrivate::UpdatePaintNode;
update();
}
@@ -2575,4 +2582,83 @@ void QQuickText::mouseReleaseEvent(QMouseEvent *event)
QQuickItem::mouseReleaseEvent(event);
}
+bool QQuickTextPrivate::isLinkHoveredConnected()
+{
+ Q_Q(QQuickText);
+ IS_SIGNAL_CONNECTED(q, QQuickText, linkHovered, (const QString &));
+}
+
+/*!
+ \qmlsignal QtQuick2::Text::onLinkHovered(string link)
+ \since QtQuick 2.2
+
+ This handler is called when the user hovers 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.
+
+ \sa hoveredLink
+*/
+
+/*!
+ \qmlproperty string QtQuick2::Text::hoveredLink
+ \since QtQuick 2.2
+
+ This property contains the link string when user hovers a link
+ embedded in the text. The link must be in rich text or HTML format
+ and the \a hoveredLink string provides access to the particular link.
+
+ \sa onLinkHovered
+*/
+
+QString QQuickText::hoveredLink() const
+{
+ Q_D(const QQuickText);
+ if (const_cast<QQuickTextPrivate *>(d)->isLinkHoveredConnected()) {
+ if (d->extra.isAllocated())
+ return d->extra->hoveredLink;
+ } else {
+#ifndef QT_NO_CURSOR
+ if (QQuickWindow *wnd = window()) {
+ QPointF pos = QCursor::pos(wnd->screen()) - wnd->position() - mapToScene(QPointF(0, 0));
+ return d->anchorAt(pos);
+ }
+#endif // QT_NO_CURSOR
+ }
+ return QString();
+}
+
+void QQuickTextPrivate::processHoverEvent(QHoverEvent *event)
+{
+ Q_Q(QQuickText);
+ QString link;
+ if (event->type() != QEvent::HoverLeave)
+ link = anchorAt(event->posF());
+
+ if ((!extra.isAllocated() && !link.isEmpty()) || (extra.isAllocated() && extra->hoveredLink != link)) {
+ extra.value().hoveredLink = link;
+ emit q->linkHovered(extra->hoveredLink);
+ }
+}
+
+void QQuickText::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickText);
+ if (d->isLinkHoveredConnected())
+ d->processHoverEvent(event);
+}
+
+void QQuickText::hoverMoveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickText);
+ if (d->isLinkHoveredConnected())
+ d->processHoverEvent(event);
+}
+
+void QQuickText::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickText);
+ if (d->isLinkHoveredConnected())
+ d->processHoverEvent(event);
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h
index 03b436b3fb..f34cf17e5d 100644
--- a/src/quick/items/qquicktext_p.h
+++ b/src/quick/items/qquicktext_p.h
@@ -90,6 +90,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickText : public QQuickImplicitSizeItem
Q_PROPERTY(int minimumPointSize READ minimumPointSize WRITE setMinimumPointSize NOTIFY minimumPointSizeChanged)
Q_PROPERTY(FontSizeMode fontSizeMode READ fontSizeMode WRITE setFontSizeMode NOTIFY fontSizeModeChanged)
Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged)
+ Q_PROPERTY(QString hoveredLink READ hoveredLink NOTIFY linkHovered REVISION 2)
public:
QQuickText(QQuickItem *parent=0);
@@ -207,9 +208,12 @@ public:
RenderType renderType() const;
void setRenderType(RenderType renderType);
+ QString hoveredLink() const;
+
Q_SIGNALS:
void textChanged(const QString &text);
void linkActivated(const QString &link);
+ Q_REVISION(2) void linkHovered(const QString &link);
void fontChanged(const QFont &font);
void colorChanged();
void linkColorChanged();
@@ -243,6 +247,10 @@ protected:
void updatePolish();
+ void hoverEnterEvent(QHoverEvent *event);
+ void hoverMoveEvent(QHoverEvent *event);
+ void hoverLeaveEvent(QHoverEvent *event);
+
private Q_SLOTS:
void q_imagesLoaded();
void triggerPreprocess();
diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h
index ff6b0f20be..7a31e77ae4 100644
--- a/src/quick/items/qquicktext_p_p.h
+++ b/src/quick/items/qquicktext_p_p.h
@@ -87,6 +87,8 @@ public:
QString elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine = 0) const;
void elideFormats(int start, int length, int offset, QList<QTextLayout::FormatRange> *elidedFormats);
+ void processHoverEvent(QHoverEvent *event);
+
QRectF layedOutTextRect;
struct ExtraData {
@@ -95,6 +97,7 @@ public:
qreal lineHeight;
QQuickTextDocumentWithImageResources *doc;
QString activeLink;
+ QString hoveredLink;
int minimumPixelSize;
int minimumPointSize;
int nbActiveDownloads;
@@ -167,6 +170,7 @@ public:
QRectF setupTextLayout(qreal * const baseline);
void setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset = 0);
bool isLinkActivatedConnected();
+ bool isLinkHoveredConnected();
static QString anchorAt(const QTextLayout *layout, const QPointF &mousePos);
QString anchorAt(const QPointF &pos) const;
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 9625aa5d5e..fce5e02b4d 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -298,6 +298,8 @@ void QQuickTextControlPrivate::setContent(Qt::TextFormat format, const QString &
bool previousUndoRedoState = doc->isUndoRedoEnabled();
doc->setUndoRedoEnabled(false);
+ const int oldCursorPos = cursor.position();
+
// avoid multiple textChanged() signals being emitted
qmlobject_disconnect(doc, QTextDocument, SIGNAL(contentsChanged()), q, QQuickTextControl, SIGNAL(textChanged()));
@@ -341,7 +343,8 @@ void QQuickTextControlPrivate::setContent(Qt::TextFormat format, const QString &
doc->setModified(false);
q->updateCursorRectangle(true);
- emit q->cursorPositionChanged();
+ if (cursor.position() != oldCursorPos)
+ emit q->cursorPositionChanged();
}
void QQuickTextControlPrivate::setCursorPosition(const QPointF &pos)
@@ -698,6 +701,9 @@ void QQuickTextControl::processEvent(QEvent *e, const QMatrix &matrix)
case QEvent::KeyPress:
d->keyPressEvent(static_cast<QKeyEvent *>(e));
break;
+ case QEvent::KeyRelease:
+ d->keyReleaseEvent(static_cast<QKeyEvent *>(e));
+ break;
case QEvent::MouseButtonPress: {
QMouseEvent *ev = static_cast<QMouseEvent *>(e);
d->mousePressEvent(ev, matrix.map(ev->localPos()));
@@ -714,6 +720,12 @@ void QQuickTextControl::processEvent(QEvent *e, const QMatrix &matrix)
QMouseEvent *ev = static_cast<QMouseEvent *>(e);
d->mouseDoubleClickEvent(ev, matrix.map(ev->localPos()));
break; }
+ case QEvent::HoverEnter:
+ case QEvent::HoverMove:
+ case QEvent::HoverLeave: {
+ QHoverEvent *ev = static_cast<QHoverEvent *>(e);
+ d->hoverEvent(ev, matrix.map(ev->posF()));
+ break; }
#ifndef QT_NO_IM
case QEvent::InputMethod:
d->inputMethodEvent(static_cast<QInputMethodEvent *>(e));
@@ -809,9 +821,25 @@ void QQuickTextControl::setHtml(const QString &text)
d->setContent(Qt::RichText, text);
}
+
+void QQuickTextControlPrivate::keyReleaseEvent(QKeyEvent *e)
+{
+ if (e->key() == Qt::Key_Back) {
+ e->ignore();
+ return;
+ }
+ return;
+}
+
void QQuickTextControlPrivate::keyPressEvent(QKeyEvent *e)
{
Q_Q(QQuickTextControl);
+
+ if (e->key() == Qt::Key_Back) {
+ e->ignore();
+ return;
+ }
+
#ifndef QT_NO_SHORTCUT
if (e == QKeySequence::SelectAll) {
e->accept();
@@ -1381,6 +1409,20 @@ void QQuickTextControlPrivate::focusEvent(QFocusEvent *e)
}
}
+void QQuickTextControlPrivate::hoverEvent(QHoverEvent *e, const QPointF &pos)
+{
+ Q_Q(QQuickTextControl);
+
+ QString link;
+ if (e->type() != QEvent::HoverLeave)
+ link = q->anchorAt(pos);
+
+ if (hoveredLink != link) {
+ hoveredLink = link;
+ emit q->linkHovered(link);
+ }
+}
+
bool QQuickTextControl::hasImState() const
{
Q_D(const QQuickTextControl);
@@ -1416,6 +1458,12 @@ QRectF QQuickTextControl::cursorRect() const
return cursorRect(d->cursor);
}
+QString QQuickTextControl::hoveredLink() const
+{
+ Q_D(const QQuickTextControl);
+ return d->hoveredLink;
+}
+
QString QQuickTextControl::anchorAt(const QPointF &pos) const
{
Q_D(const QQuickTextControl);
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index 7ec8a68b4c..bc5371b0c3 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -103,6 +103,7 @@ public:
QRectF selectionRect(const QTextCursor &cursor) const;
QRectF selectionRect() const;
+ QString hoveredLink() const;
QString anchorAt(const QPointF &pos) const;
void setCursorWidth(int width);
@@ -151,6 +152,7 @@ Q_SIGNALS:
void updateRequest();
void cursorRectangleChanged();
void linkActivated(const QString &link);
+ void linkHovered(const QString &link);
public:
virtual void processEvent(QEvent *e, const QMatrix &matrix);
diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h
index fbb88bd255..e0bcbc2191 100644
--- a/src/quick/items/qquicktextcontrol_p_p.h
+++ b/src/quick/items/qquicktextcontrol_p_p.h
@@ -108,6 +108,7 @@ public:
QRectF rectForPosition(int position) const;
void keyPressEvent(QKeyEvent *e);
+ void keyReleaseEvent(QKeyEvent *e);
void mousePressEvent(QMouseEvent *event, const QPointF &pos);
void mouseMoveEvent(QMouseEvent *event, const QPointF &pos);
void mouseReleaseEvent(QMouseEvent *event, const QPointF &pos);
@@ -117,6 +118,7 @@ public:
#ifndef QT_NO_IM
void inputMethodEvent(QInputMethodEvent *);
#endif
+ void hoverEvent(QHoverEvent *e, const QPointF &pos);
void activateLinkUnderCursor(QString href = QString());
@@ -137,6 +139,7 @@ public:
QTextCursor selectedBlockOnTripleClick;
QString anchorOnMousePress;
QString linkToCopy;
+ QString hoveredLink;
QBasicTimer cursorBlinkTimer;
QBasicTimer tripleClickTimer;
diff --git a/src/quick/items/qquicktextdocument.h b/src/quick/items/qquicktextdocument.h
index 25d3bbeaf0..7c22c01d5a 100644
--- a/src/quick/items/qquicktextdocument.h
+++ b/src/quick/items/qquicktextdocument.h
@@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE
The class has to be used from C++ directly, using the property of the \l TextEdit.
- Warning: The QTextDocument provided is used internally by QtQuick elements to provide text manipulation primitives.
+ Warning: The QTextDocument provided is used internally by \l {Qt Quick} elements to provide text manipulation primitives.
You are not allowed to perform any modification of the internal state of the QTextDocument. If you do, the element
in question may stop functioning or crash.
*/
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index dde3587018..6e2262831d 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -55,6 +55,7 @@
#include <QtGui/qevent.h>
#include <QtGui/qpainter.h>
#include <QtGui/qtextobject.h>
+#include <QtGui/qtexttable.h>
#include <QtCore/qmath.h>
#include <QtCore/qalgorithms.h>
@@ -271,6 +272,12 @@ QString QQuickTextEdit::text() const
The text to display. If the text format is AutoText the text edit will
automatically determine whether the text should be treated as
rich text. This determination is made using Qt::mightBeRichText().
+
+ The text-property is mostly suitable for setting the initial content and
+ handling modifications to relatively small text content. The append(),
+ insert() and remove() methods provide more fine-grained control and
+ remarkably better performance for modifying especially large rich text
+ content.
*/
void QQuickTextEdit::setText(const QString &text)
{
@@ -380,7 +387,8 @@ void QQuickTextEdit::setTextFormat(TextFormat format)
combination with the NativeRendering render type will lend poor and sometimes pixelated
results.
- On HighDpi "retina" displays this property is ignored and QtRendering is always used.
+ On HighDpi "retina" displays and mobile and embedded platforms, this property is ignored
+ and QtRendering is always used.
*/
QQuickTextEdit::RenderType QQuickTextEdit::renderType() const
{
@@ -1709,6 +1717,13 @@ static bool comesBefore(TextNode* n1, TextNode* n2)
return n1->startPos() < n2->startPos();
}
+static inline void updateNodeTransform(QQuickTextNode* node, const QPointF &topLeft)
+{
+ QMatrix4x4 transformMatrix;
+ transformMatrix.translate(topLeft.x(), topLeft.y());
+ node->setMatrix(transformMatrix);
+}
+
QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
{
Q_UNUSED(updatePaintNodeData);
@@ -1749,17 +1764,12 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
rootNode->removeChildNode(d->frameDecorationsNode);
delete d->frameDecorationsNode;
}
- d->frameDecorationsNode = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
- d->frameDecorationsNode->initEngine(QColor(), QColor(), QColor());
-
-
- QQuickTextNode *node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
- node->setUseNativeRenderer(d->renderType == NativeRendering && d->window->devicePixelRatio() <= 1);
- node->initEngine(d->color, d->selectedTextColor, d->selectionColor);
+ d->frameDecorationsNode = d->createTextNode();
+ QQuickTextNode *node = 0;
- int sizeCounter = 0;
- int prevBlockStart = firstDirtyPos;
+ int currentNodeSize = 0;
+ int nodeStart = firstDirtyPos;
QPointF basePosition(d->xoff, d->yoff);
QPointF nodeOffset;
TextNode *firstCleanNode = (nodeIterator != d->textNodeMap.end()) ? *nodeIterator : 0;
@@ -1772,16 +1782,14 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
frames.append(textFrame->childFrames());
d->frameDecorationsNode->m_engine->addFrameDecorations(d->document, textFrame);
+
+ if (textFrame->lastPosition() < firstDirtyPos || (firstCleanNode && textFrame->firstPosition() >= firstCleanNode->startPos()))
+ continue;
+ node = d->createTextNode();
+
if (textFrame->firstPosition() > textFrame->lastPosition()
&& textFrame->frameFormat().position() != QTextFrameFormat::InFlow) {
- QRectF rect = d->document->documentLayout()->frameBoundingRect(textFrame);
-
- if (!node->m_engine->hasContents()) {
- nodeOffset = rect.topLeft();
- QMatrix4x4 transformMatrix;
- transformMatrix.translate(nodeOffset.x(), nodeOffset.y());
- node->setMatrix(transformMatrix);
- }
+ updateNodeTransform(node, d->document->documentLayout()->frameBoundingRect(textFrame).topLeft());
const int pos = textFrame->firstPosition() - 1;
ProtectedLayoutAccessor *a = static_cast<ProtectedLayoutAccessor *>(d->document->documentLayout());
QTextCharFormat format = a->formatAccessor(pos);
@@ -1789,10 +1797,23 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
node->m_engine->setCurrentLine(block.layout()->lineForTextPosition(pos - block.position()));
node->m_engine->addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document,
pos, textFrame->frameFormat().position());
+ nodeStart = pos;
+ } else if (qobject_cast<QTextTable*>(textFrame)) { // To keep things simple, map text tables as one text node
+ QTextFrame::iterator it = textFrame->begin();
+ nodeOffset = d->document->documentLayout()->frameBoundingRect(textFrame).topLeft();
+ updateNodeTransform(node, nodeOffset);
+ while (!it.atEnd())
+ node->m_engine->addTextBlock(d->document, (it++).currentBlock(), basePosition - nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1);
+ nodeStart = textFrame->firstPosition();
} else {
+ // Having nodes spanning across frame boundaries will break the current bookkeeping mechanism. We need to prevent that.
+ QList<int> frameBoundaries;
+ frameBoundaries.reserve(frames.size());
+ Q_FOREACH (QTextFrame *frame, frames)
+ frameBoundaries.append(frame->firstPosition());
+ std::sort(frameBoundaries.begin(), frameBoundaries.end());
QTextFrame::iterator it = textFrame->begin();
-
while (!it.atEnd()) {
QTextBlock block = it.currentBlock();
++it;
@@ -1801,35 +1822,27 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
if (!node->m_engine->hasContents()) {
nodeOffset = d->document->documentLayout()->blockBoundingRect(block).topLeft();
- QMatrix4x4 transformMatrix;
- transformMatrix.translate(nodeOffset.x(), nodeOffset.y());
- node->setMatrix(transformMatrix);
+ updateNodeTransform(node, nodeOffset);
+ nodeStart = block.position();
}
node->m_engine->addTextBlock(d->document, block, basePosition - nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1);
- sizeCounter += block.length();
+ currentNodeSize += block.length();
- if ((it.atEnd() && frames.isEmpty()) || (firstCleanNode && block.next().position() >= firstCleanNode->startPos())) // last node that needed replacing or last block of the last frame
+ if ((it.atEnd()) || (firstCleanNode && block.next().position() >= firstCleanNode->startPos())) // last node that needed replacing or last block of the frame
break;
- if (sizeCounter > nodeBreakingSize) {
- sizeCounter = 0;
- node->m_engine->addToSceneGraph(node, QQuickText::Normal, QColor());
- nodeIterator = d->textNodeMap.insert(nodeIterator, new TextNode(prevBlockStart, node));
- ++nodeIterator;
- rootNode->appendChildNode(node);
- prevBlockStart = block.next().position();
- node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
- node->setUseNativeRenderer(d->renderType == NativeRendering && d->window->devicePixelRatio() <= 1);
- node->initEngine(d->color, d->selectedTextColor, d->selectionColor);
+ QList<int>::const_iterator lowerBound = qLowerBound(frameBoundaries, block.next().position());
+ if (currentNodeSize > nodeBreakingSize || *lowerBound > nodeStart) {
+ currentNodeSize = 0;
+ d->addCurrentTextNodeToRoot(rootNode, node, nodeIterator, nodeStart);
+ node = d->createTextNode();
+ nodeStart = block.next().position();
}
}
}
+ d->addCurrentTextNodeToRoot(rootNode, node, nodeIterator, nodeStart);
}
- node->m_engine->addToSceneGraph(node, QQuickText::Normal, QColor());
- nodeIterator = d->textNodeMap.insert(nodeIterator, new TextNode(prevBlockStart, node));
- ++nodeIterator;
- rootNode->appendChildNode(node);
d->frameDecorationsNode->m_engine->addToSceneGraph(d->frameDecorationsNode, QQuickText::Normal, QColor());
// Now prepend the frame decorations since we want them rendered first, with the text nodes and cursor in front.
rootNode->prependChildNode(d->frameDecorationsNode);
@@ -1848,6 +1861,10 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
}
}
+
+ // Since we iterate over blocks from different text frames that are potentially not sorted
+ // we need to ensure that our list of nodes is sorted again:
+ std::sort(d->textNodeMap.begin(), d->textNodeMap.end(), &comesBefore);
}
if (d->cursorComponent == 0 && !isReadOnly()) {
@@ -1942,6 +1959,8 @@ void QQuickTextEditPrivate::init()
#endif
q->setFlag(QQuickItem::ItemHasContents);
+ q->setAcceptHoverEvents(true);
+
document = new QQuickTextDocumentWithImageResources(q);
control = new QQuickTextControl(document, q);
@@ -1956,6 +1975,7 @@ void QQuickTextEditPrivate::init()
qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SIGNAL(cursorPositionChanged()));
qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate()));
qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString)));
+ qmlobject_connect(control, QQuickTextControl, SIGNAL(linkHovered(QString)), q, QQuickTextEdit, SIGNAL(linkHovered(QString)));
qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged()));
#ifndef QT_NO_CLIPBOARD
qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()), q, QQuickTextEdit, SLOT(q_canPasteChanged()));
@@ -1994,11 +2014,16 @@ void QQuickTextEdit::markDirtyNodesForRange(int start, int end, int charDelta)
Q_D(QQuickTextEdit);
if (start == end)
return;
+
TextNode dummyNode(start, 0);
TextNodeIterator it = qLowerBound(d->textNodeMap.begin(), d->textNodeMap.end(), &dummyNode, &comesBefore);
- // qLowerBound gives us the first node past the start of the affected portion, rewind by one if we can.
- if (it != d->textNodeMap.begin())
+ // qLowerBound gives us the first node past the start of the affected portion, rewind to the first node
+ // that starts at the last position before the edit position. (there might be several because of images)
+ if (it != d->textNodeMap.begin()) {
--it;
+ TextNode otherDummy((*it)->startPos(), 0);
+ it = qLowerBound(d->textNodeMap.begin(), d->textNodeMap.end(), &otherDummy, &comesBefore);
+ }
// mark the affected nodes as dirty
while (it != d->textNodeMap.constEnd()) {
@@ -2148,8 +2173,10 @@ void QQuickTextEdit::updateSize()
if (d->inLayout) // probably the result of a binding loop, but by letting it
return; // get this far we'll get a warning to that effect.
}
- if (d->document->textWidth() != width())
+ if (d->document->textWidth() != width()) {
d->document->setTextWidth(width());
+ newWidth = d->document->idealWidth();
+ }
//### need to confirm cost of always setting these
} else if (d->wrapMode == NoWrap && d->document->textWidth() != newWidth) {
d->document->setTextWidth(newWidth); // ### Text does not align if width is not set or the idealWidth exceeds the textWidth (QTextDoc bug)
@@ -2305,6 +2332,23 @@ void QQuickTextEditPrivate::handleFocusEvent(QFocusEvent *event)
}
}
+void QQuickTextEditPrivate::addCurrentTextNodeToRoot(QSGTransformNode *root, QQuickTextNode *node, TextNodeIterator &it, int startPos)
+{
+ node->m_engine->addToSceneGraph(node, QQuickText::Normal, QColor());
+ it = textNodeMap.insert(it, new TextNode(startPos, node));
+ ++it;
+ root->appendChildNode(node);
+}
+
+QQuickTextNode *QQuickTextEditPrivate::createTextNode()
+{
+ Q_Q(QQuickTextEdit);
+ QQuickTextNode* node = new QQuickTextNode(QQuickItemPrivate::get(q)->sceneGraphContext(), q);
+ node->setUseNativeRenderer(renderType == QQuickTextEdit::NativeRendering && window->devicePixelRatio() <= 1);
+ node->initEngine(color, selectedTextColor, selectionColor);
+ return node;
+}
+
void QQuickTextEdit::q_canPasteChanged()
{
Q_D(QQuickTextEdit);
@@ -2433,4 +2477,102 @@ QQuickTextDocument *QQuickTextEdit::textDocument()
return d->quickDocument;
}
+bool QQuickTextEditPrivate::isLinkHoveredConnected()
+{
+ Q_Q(QQuickTextEdit);
+ IS_SIGNAL_CONNECTED(q, QQuickTextEdit, linkHovered, (const QString &));
+}
+
+/*!
+ \qmlsignal QtQuick2::TextEdit::onLinkHovered(string link)
+ \since QtQuick 2.2
+
+ This handler is called when the user hovers 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.
+
+ \sa hoveredLink
+*/
+
+/*!
+ \qmlproperty string QtQuick2::TextEdit::hoveredLink
+ \since QtQuick 2.2
+
+ This property contains the link string when user hovers a link
+ embedded in the text. The link must be in rich text or HTML format
+ and the link string provides access to the particular link.
+
+ \sa onLinkHovered
+*/
+
+QString QQuickTextEdit::hoveredLink() const
+{
+ Q_D(const QQuickTextEdit);
+ if (const_cast<QQuickTextEditPrivate *>(d)->isLinkHoveredConnected()) {
+ return d->control->hoveredLink();
+ } else {
+#ifndef QT_NO_CURSOR
+ if (QQuickWindow *wnd = window()) {
+ QPointF pos = QCursor::pos(wnd->screen()) - wnd->position() - mapToScene(QPointF(0, 0));
+ return d->control->anchorAt(pos);
+ }
+#endif // QT_NO_CURSOR
+ }
+ return QString();
+}
+
+void QQuickTextEdit::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickTextEdit);
+ if (d->isLinkHoveredConnected())
+ d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+}
+
+void QQuickTextEdit::hoverMoveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickTextEdit);
+ if (d->isLinkHoveredConnected())
+ d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+}
+
+void QQuickTextEdit::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickTextEdit);
+ if (d->isLinkHoveredConnected())
+ d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+}
+
+/*!
+ \qmlmethod void QtQuick2::TextEdit::append(string text)
+ \since QtQuick 2.2
+
+ Appends a new paragraph with \a text to the end of the TextEdit.
+
+ In order to append without inserting a new paragraph,
+ call \c myTextEdit.insert(myTextEdit.length, text) instead.
+*/
+void QQuickTextEdit::append(const QString &text)
+{
+ Q_D(QQuickTextEdit);
+ QTextCursor cursor(d->document);
+ cursor.beginEditBlock();
+ cursor.movePosition(QTextCursor::End);
+
+ if (!d->document->isEmpty())
+ cursor.insertBlock();
+
+#ifndef QT_NO_TEXTHTMLPARSER
+ if (d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text))) {
+ cursor.insertHtml(text);
+ } else {
+ cursor.insertText(text);
+ }
+#else
+ cursor.insertText(text);
+#endif // QT_NO_TEXTHTMLPARSER
+
+ cursor.endEditBlock();
+ d->control->updateCursorRectangle(false);
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index 4e09eafcac..69ffad7e70 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -102,6 +102,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem
Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl RESET resetBaseUrl NOTIFY baseUrlChanged)
Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged)
Q_PROPERTY(QQuickTextDocument *textDocument READ textDocument FINAL REVISION 1)
+ Q_PROPERTY(QString hoveredLink READ hoveredLink NOTIFY linkHovered REVISION 2)
public:
QQuickTextEdit(QQuickItem *parent=0);
@@ -255,6 +256,8 @@ public:
QQuickTextDocument *textDocument();
+ QString hoveredLink() const;
+
Q_SIGNALS:
void textChanged();
void contentSizeChanged();
@@ -282,6 +285,7 @@ Q_SIGNALS:
void selectByMouseChanged(bool selectByMouse);
void mouseSelectionModeChanged(SelectionMode mode);
void linkActivated(const QString &link);
+ Q_REVISION(2) void linkHovered(const QString &link);
void canPasteChanged();
void canUndoChanged();
void canRedoChanged();
@@ -310,6 +314,7 @@ public Q_SLOTS:
void redo();
void insert(int position, const QString &text);
void remove(int start, int end);
+ Q_REVISION(2) void append(const QString &text);
private Q_SLOTS:
void q_textChanged();
@@ -338,6 +343,10 @@ protected:
void focusInEvent(QFocusEvent *event);
void focusOutEvent(QFocusEvent *event);
+ void hoverEnterEvent(QHoverEvent *event);
+ void hoverMoveEvent(QHoverEvent *event);
+ void hoverLeaveEvent(QHoverEvent *event);
+
// mouse filter?
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h
index feb7e98873..ec3cf1cec5 100644
--- a/src/quick/items/qquicktextedit_p_p.h
+++ b/src/quick/items/qquicktextedit_p_p.h
@@ -87,6 +87,7 @@ public:
QQuickTextNode* m_node;
bool m_dirty;
};
+ typedef QList<Node*>::iterator TextNodeIterator;
QQuickTextEditPrivate()
@@ -123,9 +124,12 @@ public:
void mirrorChange();
qreal getImplicitWidth() const;
Qt::LayoutDirection textDirection(const QString &text) const;
+ bool isLinkHoveredConnected();
void setNativeCursorEnabled(bool enabled) { control->setCursorWidth(enabled ? 1 : 0); }
void handleFocusEvent(QFocusEvent *event);
+ void addCurrentTextNodeToRoot(QSGTransformNode *, QQuickTextNode*, TextNodeIterator&, int startPos);
+ QQuickTextNode* createTextNode();
#ifndef QT_NO_IM
Qt::InputMethodHints effectiveInputMethodHints() const;
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 989c0db3ab..2bd3a3da37 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -155,7 +155,8 @@ void QQuickTextInput::setText(const QString &s)
combination with the NativeRendering render type will lend poor and sometimes pixelated
results.
- On HighDpi "retina" displays this property is ignored and QtRendering is always used.
+ On HighDpi "retina" displays and mobile and embedded platforms, this property is ignored
+ and QtRendering is always used.
*/
QQuickTextInput::RenderType QQuickTextInput::renderType() const
{
@@ -778,7 +779,10 @@ QRectF QQuickTextInput::cursorRectangle() const
QTextLine l = d->m_textLayout.lineForTextPosition(c);
if (!l.isValid())
return QRectF();
- return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height());
+ qreal x = l.cursorToX(c) - d->hscroll;
+ qreal y = l.y() - d->vscroll;
+ qreal height = l.ascent() + l.descent();
+ return QRectF(x, y, 1, height);
}
/*!
@@ -1227,10 +1231,11 @@ Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
Specifies how the text should be displayed in the TextInput.
\list
\li TextInput.Normal - Displays the text as it is. (Default)
- \li TextInput.Password - Displays asterisks instead of characters.
+ \li TextInput.Password - Displays platform-dependent password mask
+ characters instead of the actual characters.
\li TextInput.NoEcho - Displays nothing.
\li TextInput.PasswordEchoOnEdit - Displays characters as they are entered
- while editing, otherwise displays asterisks.
+ while editing, otherwise identical to \c TextInput.Password.
\endlist
*/
QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
@@ -1372,9 +1377,12 @@ QRectF QQuickTextInput::positionToRectangle(int pos) const
pos += d->preeditAreaText().length();
#endif
QTextLine l = d->m_textLayout.lineForTextPosition(pos);
- return l.isValid()
- ? QRectF(l.cursorToX(pos) - d->hscroll, l.y() - d->vscroll, 1, l.height())
- : QRectF();
+ if (!l.isValid())
+ return QRectF();
+ qreal x = l.cursorToX(pos) - d->hscroll;
+ qreal y = l.y() - d->vscroll;
+ qreal height = l.ascent() + l.descent();
+ return QRectF(x, y, 1, height);
}
/*!
@@ -1465,7 +1473,7 @@ void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
int cursorPosition = d->m_cursor;
if (cursorPosition == 0)
ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
- if (!ignore && cursorPosition == text().length())
+ if (!ignore && cursorPosition == d->m_text.length())
ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
}
if (ignore) {
@@ -2194,7 +2202,8 @@ void QQuickTextInput::selectWord()
\qmlproperty string QtQuick2::TextInput::passwordCharacter
This is the character displayed when echoMode is set to Password or
- PasswordEchoOnEdit. By default it is an asterisk.
+ PasswordEchoOnEdit. By default it is the password character used by
+ the platform theme.
If this property is set to a string with more than one character,
the first character is used. If the string is empty, the value
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index 57eff175a2..11096cfa1d 100644
--- a/src/quick/items/qquicktextinput_p_p.h
+++ b/src/quick/items/qquicktextinput_p_p.h
@@ -110,7 +110,7 @@ public:
, updateType(UpdatePaintNode)
, mouseSelectionMode(QQuickTextInput::SelectCharacters)
, m_layoutDirection(Qt::LayoutDirectionAuto)
- , m_passwordCharacter(QLatin1Char('*'))
+ , m_passwordCharacter(qApp->styleHints()->passwordMaskCharacter())
, focusOnPress(true)
, cursorVisible(false)
, cursorPending(false)
diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp
index 4952a37082..d8040a1110 100644
--- a/src/quick/items/qquicktextnode.cpp
+++ b/src/quick/items/qquicktextnode.cpp
@@ -176,7 +176,7 @@ void QQuickTextNode::setCursor(const QRectF &rect, const QColor &color)
appendChildNode(m_cursorNode);
}
-void QQuickTextNode::initEngine(const QColor& textColor, const QColor& selectedTextColor, const QColor& selectionColor, const QColor& anchorColor)
+void QQuickTextNode::initEngine(const QColor& textColor, const QColor& selectedTextColor, const QColor& selectionColor, const QColor& anchorColor, const QPointF &position)
{
m_engine.reset(new QQuickTextNodeEngine);
m_engine->m_hasContents = false;
@@ -184,6 +184,7 @@ void QQuickTextNode::initEngine(const QColor& textColor, const QColor& selectedT
m_engine->setSelectedTextColor(selectedTextColor);
m_engine->setSelectionColor(selectionColor);
m_engine->setAnchorColor(anchorColor);
+ m_engine->setPosition(position);
}
void QQuickTextNode::addImage(const QRectF &rect, const QImage &image)
@@ -249,8 +250,7 @@ void QQuickTextNode::addTextLayout(const QPointF &position, QTextLayout *textLay
int selectionStart, int selectionEnd,
int lineStart, int lineCount)
{
- Q_UNUSED(position);
- initEngine(color, selectedTextColor, selectionColor, anchorColor);
+ initEngine(color, selectedTextColor, selectionColor, anchorColor, position);
#ifndef QT_NO_IM
int preeditLength = textLayout->preeditAreaText().length();
diff --git a/src/quick/items/qquicktextnode_p.h b/src/quick/items/qquicktextnode_p.h
index 16da3ce685..f5de6cc9b6 100644
--- a/src/quick/items/qquicktextnode_p.h
+++ b/src/quick/items/qquicktextnode_p.h
@@ -107,8 +107,8 @@ public:
void setUseNativeRenderer(bool on) { m_useNativeRenderer = on; }
private:
- void initEngine(const QColor &textColor, const QColor &selectedTextColor, const QColor &selectionColor, const QColor& anchorColor = QColor());
-
+ void initEngine(const QColor &textColor, const QColor &selectedTextColor, const QColor &selectionColor, const QColor& anchorColor = QColor()
+ , const QPointF &position = QPointF());
QSGContext *m_context;
QSGSimpleRectNode *m_cursorNode;
@@ -118,6 +118,7 @@ private:
QScopedPointer<QQuickTextNodeEngine> m_engine;
friend class QQuickTextEdit;
+ friend class QQuickTextEditPrivate;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index 65343cdc52..cc32c40aa3 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -494,7 +494,7 @@ void QQuickViewPrivate::setRootObject(QObject *obj)
<< "loaded has 'import QtQuick 1.0' or 'import Qt 4.7', this error will occur." << endl
<< endl
<< "To load files with 'import QtQuick 1.0' or 'import Qt 4.7', use the" << endl
- << "QDeclarativeView class in the qtquick1 module." << endl;
+ << "QDeclarativeView class in the Qt Quick 1 module." << endl;
delete obj;
root = 0;
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 4789314e01..619c72afb8 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -72,6 +72,10 @@
QT_BEGIN_NAMESPACE
+extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
+
+bool QQuickWindowPrivate::defaultAlphaBuffer(0);
+
void QQuickWindowPrivate::updateFocusItemTransform()
{
Q_Q(QQuickWindow);
@@ -85,44 +89,49 @@ void QQuickWindowPrivate::updateFocusItemTransform()
#endif
}
-
class QQuickWindowIncubationController : public QObject, public QQmlIncubationController
{
Q_OBJECT
public:
- QQuickWindowIncubationController(const QQuickWindow *window)
- : m_window(QQuickWindowPrivate::get(const_cast<QQuickWindow *>(window)))
+ QQuickWindowIncubationController(QSGRenderLoop *loop)
+ : m_renderLoop(loop), m_timer(0)
{
// Allow incubation for 1/3 of a frame.
m_incubation_time = qMax(1, int(1000 / QGuiApplication::primaryScreen()->refreshRate()) / 3);
- m_animation_driver = m_window->windowManager->animationDriver();
+ m_animation_driver = m_renderLoop->animationDriver();
if (m_animation_driver) {
connect(m_animation_driver, SIGNAL(stopped()), this, SLOT(animationStopped()));
- connect(window, SIGNAL(frameSwapped()), this, SLOT(incubate()));
+ connect(m_renderLoop, SIGNAL(timeToIncubate()), this, SLOT(incubate()));
}
}
protected:
- virtual bool event(QEvent *e)
+ void timerEvent(QTimerEvent *)
{
- if (e->type() == QEvent::User) {
- incubate();
- return true;
+ killTimer(m_timer);
+ m_timer = 0;
+ incubate();
+ }
+
+ void incubateAgain() {
+ if (m_timer == 0) {
+ // Wait for a while before processing the next batch. Using a
+ // timer to avoid starvation of system events.
+ m_timer = startTimer(m_incubation_time);
}
- return QObject::event(e);
}
public slots:
void incubate() {
if (incubatingObjectCount()) {
- if (m_animation_driver && m_animation_driver->isRunning()) {
+ if (m_renderLoop->interleaveIncubation()) {
incubateFor(m_incubation_time);
} else {
incubateFor(m_incubation_time * 2);
if (incubatingObjectCount())
- QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+ incubateAgain();
}
}
}
@@ -132,14 +141,15 @@ public slots:
protected:
virtual void incubatingObjectCountChanged(int count)
{
- if (count && (!m_animation_driver || !m_animation_driver->isRunning()))
- QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+ if (count && !m_renderLoop->interleaveIncubation())
+ incubateAgain();
}
private:
- QQuickWindowPrivate *m_window;
+ QSGRenderLoop *m_renderLoop;
int m_incubation_time;
QAnimationDriver *m_animation_driver;
+ int m_timer;
};
#include "qquickwindow.moc"
@@ -149,8 +159,6 @@ private:
/*!
Returns an accessibility interface for this window, or 0 if such an
interface cannot be created.
-
- \warning The caller is responsible for deleting the returned interface.
*/
QAccessibleInterface *QQuickWindow::accessibleRoot() const
{
@@ -258,29 +266,6 @@ void QQuickWindowPrivate::polishItems()
updateFocusItemTransform();
}
-/**
- * This parameter enables that this window can be rendered without
- * being shown on screen. This feature is very limited in what it supports.
- *
- * For this feature to be useful one needs to hook into beforeRender()
- * and set the render target.
- *
- */
-void QQuickWindowPrivate::setRenderWithoutShowing(bool render)
-{
- if (render == renderWithoutShowing)
- return;
-
- Q_Q(QQuickWindow);
- renderWithoutShowing = render;
-
- if (render)
- windowManager->show(q);
- else
- windowManager->hide(q);
-}
-
-
/*!
* Schedules the window to render another frame.
*
@@ -361,7 +346,6 @@ QQuickWindowPrivate::QQuickWindowPrivate()
#endif
, touchMouseId(-1)
, touchMousePressTimestamp(0)
- , renderWithoutShowing(false)
, dirtyItemList(0)
, context(0)
, renderer(0)
@@ -371,6 +355,7 @@ QQuickWindowPrivate::QQuickWindowPrivate()
, persistentGLContext(true)
, persistentSceneGraph(true)
, lastWheelEventAccepted(false)
+ , componentCompleted(true)
, renderTarget(0)
, renderTargetId(0)
, incubationController(0)
@@ -414,7 +399,10 @@ void QQuickWindowPrivate::init(QQuickWindow *c)
QQmlListProperty<QObject> QQuickWindowPrivate::data()
{
initContentItem();
- return QQuickItemPrivate::get(contentItem)->data();
+ return QQmlListProperty<QObject>(q_func(), 0, QQuickWindowPrivate::data_append,
+ QQuickWindowPrivate::data_count,
+ QQuickWindowPrivate::data_at,
+ QQuickWindowPrivate::data_clear);
}
void QQuickWindowPrivate::initContentItem()
@@ -432,7 +420,7 @@ static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::Touc
{
// The touch point local position and velocity are not yet transformed.
QMouseEvent *me = new QMouseEvent(type, transformNeeded ? item->mapFromScene(p.scenePos()) : p.pos(), p.scenePos(), p.screenPos(),
- Qt::LeftButton, Qt::LeftButton, event->modifiers());
+ Qt::LeftButton, (type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton), event->modifiers());
me->setAccepted(true);
me->setTimestamp(event->timestamp());
QVector2D transformedVelocity = p.velocity();
@@ -838,15 +826,34 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
\ingroup qtquick-visual
\brief Creates a new top-level window
- The Window object creates a new top-level window for a QtQuick scene. It automatically sets up the
- window for use with QtQuick 2.x graphical types.
+ The Window object creates a new top-level window for a Qt Quick scene. It automatically sets up the
+ window for use with \c {QtQuick 2.x} graphical types.
To use this type, you will need to import the module with the following line:
\code
import QtQuick.Window 2.1
\endcode
- Restricting this import will allow you to have a QML environment without access to window system features.
+ Omitting this import will allow you to have a QML environment without
+ access to window system features.
+
+ A Window can be declared inside an Item or inside another Window; in that
+ case the inner Window will automatically become "transient for" the outer
+ Window: that is, most platforms will show it centered upon the outer window
+ by default, and there may be other platform-dependent behaviors, depending
+ also on the \l flags. If the nested window is intended to be a dialog in
+ your application, you should also set \l flags to Qt.Dialog, because some
+ window managers will not provide the centering behavior without that flag.
+ You can also declare multiple windows inside a top-level \l QtObject, in which
+ case the windows will have no transient relationship.
+
+ Alternatively you can set or bind \l x and \l y to position the Window
+ explicitly on the screen.
+
+ When the user attempts to close a window, the \a closing signal will be
+ emitted. You can force the window to stay open (for example to prompt the
+ user to save changes) by writing an onClosing handler and setting
+ close.accepted = false.
*/
/*!
\class QQuickWindow
@@ -1094,7 +1101,10 @@ QQuickItem *QQuickWindow::contentItem() const
}
/*!
- Returns the item which currently has active focus.
+ \property QQuickWindow::activeFocusItem
+
+ \brief The item which currently has active focus or \c null if there is
+ no item with active focus.
*/
QQuickItem *QQuickWindow::activeFocusItem() const
{
@@ -1178,6 +1188,14 @@ bool QQuickWindow::event(QEvent *e)
case QEvent::WindowDeactivate:
contentItem()->windowDeactivateEvent();
break;
+ case QEvent::Close: {
+ // TOOD Qt 6 (binary incompatible)
+ // closeEvent(static_cast<QCloseEvent *>(e));
+ QQuickCloseEvent qev;
+ qev.setAccepted(e->isAccepted());
+ emit closing(&qev);
+ e->setAccepted(qev.isAccepted());
+ } break;
case QEvent::FocusAboutToChange:
#ifndef QT_NO_IM
if (d->activeFocusItem)
@@ -2037,16 +2055,68 @@ bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent
return overThreshold;
}
+/*!
+ \qmlproperty list<Object> QtQuick.Window2::Window::data
+ \default
+
+ The data property allows you to freely mix visual children, resources
+ and other Windows in a Window.
+
+ If you assign another Window to the data list, the nested window will
+ become "transient for" the outer Window.
+
+ If you assign an \l Item to the data list, it becomes a child of the
+ Window's \l contentItem, so that it appears inside the window. The item's
+ parent will be the window's contentItem, which is the root of the Item
+ ownership tree within that Window.
+
+ If you assign any other object type, it is added as a resource.
+
+ It should not generally be necessary to refer to the \c data property,
+ as it is the default property for Window and thus all child items are
+ automatically assigned to this property.
+
+ \sa QWindow::transientParent()
+ */
+
+void QQuickWindowPrivate::data_append(QQmlListProperty<QObject> *property, QObject *o)
+{
+ if (!o)
+ return;
+ QQuickWindow *that = static_cast<QQuickWindow *>(property->object);
+ if (QQuickWindow *window = qmlobject_cast<QQuickWindow *>(o))
+ window->setTransientParent(that);
+ QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(that->contentItem())->data();
+ itemProperty.append(&itemProperty, o);
+}
+
+int QQuickWindowPrivate::data_count(QQmlListProperty<QObject> *property)
+{
+ QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
+ if (!win || !win->contentItem() || !QQuickItemPrivate::get(win->contentItem())->data().count)
+ return 0;
+ QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
+ return itemProperty.count(&itemProperty);
+}
+
+QObject *QQuickWindowPrivate::data_at(QQmlListProperty<QObject> *property, int i)
+{
+ QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
+ QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
+ return itemProperty.at(&itemProperty, i);
+}
+
+void QQuickWindowPrivate::data_clear(QQmlListProperty<QObject> *property)
+{
+ QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
+ QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
+ itemProperty.clear(&itemProperty);
+}
+
bool QQuickWindowPrivate::isRenderable() const
{
- const QQuickWindow *q = q_func();
- QRect geom = q->geometry();
- if (geom.width() <= 0 || geom.height() <= 0)
- return false;
- // Change to be applied after the visibility property is integrated in qtbase:
-// return visibility != QWindow::Hidden || (renderWithoutShowing && platformWindow);
- // Temporary version which is implementation-agnostic but slightly less efficient:
- return q->isVisible() || (renderWithoutShowing && platformWindow);
+ Q_Q(const QQuickWindow);
+ return q->isExposed() && q->isVisible() && q->geometry().isValid();
}
/*!
@@ -2456,6 +2526,13 @@ void QQuickWindow::cleanupSceneGraph()
d->renderer = 0;
}
+void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
+{
+ setTransientParent(window);
+ disconnect(sender(), SIGNAL(windowChanged(QQuickWindow*)),
+ this, SLOT(setTransientParent_helper(QQuickWindow*)));
+}
+
/*!
Returns the opengl context used for rendering.
@@ -2503,6 +2580,57 @@ QOpenGLContext *QQuickWindow::openglContext() const
This signal will be emitted from the scene graph rendering thread.
*/
+/*!
+ \class QQuickCloseEvent
+ \internal
+ \since QtQuick 2.1
+
+ \inmodule QtQuick.Window
+
+ \brief Notification that a \l QQuickWindow is about to be closed
+*/
+/*!
+ \qmltype CloseEvent
+ \instantiates QQuickCloseEvent
+ \inqmlmodule QtQuick.Window 2
+ \ingroup qtquick-visual
+ \brief Notification that a \l Window is about to be closed
+ \since Qt 5.1
+
+ Notification that a window is about to be closed by the windowing system
+ (e.g. the user clicked the titlebar close button). The CloseEvent contains
+ an accepted property which can be set to false to abort closing the window.
+
+ \sa Window.closing()
+*/
+
+/*!
+ \qmlproperty bool QtQuick.Window2::CloseEvent::accepted
+
+ This property indicates whether the application will allow the user to
+ close the window. It is true by default.
+*/
+
+/*!
+ \fn void QQuickWindow::closing()
+ \since QtQuick 2.1
+
+ This signal is emitted when the window receives a QCloseEvent from the
+ windowing system.
+*/
+
+/*!
+ \qmlsignal QtQuick.Window2::closing(CloseEvent close)
+ \since Qt 5.1
+
+ This signal is emitted when the user tries to close the window.
+
+ This signal includes a closeEvent parameter. The \a close \l accepted
+ property is true by default so that the window is allowed to close; but you
+ can implement an onClosing() handler and set close.accepted = false if
+ you need to do something else before the window can be closed.
+ */
+
/*!
Sets the render target for this window to be \a fbo.
@@ -2600,7 +2728,10 @@ QOpenGLFramebufferObject *QQuickWindow::renderTarget() const
/*!
Grabs the contents of the window and returns it as an image.
- This function might not work if the window is not visible.
+ It is possible to call the grabWindow() function when the window is not
+ visible. This requires that the window is \l{QWindow::create} {created}
+ and has a valid size and that no other QQuickWindow instances are rendering
+ in the same process.
\warning Calling this function will cause performance problems.
@@ -2609,6 +2740,36 @@ QOpenGLFramebufferObject *QQuickWindow::renderTarget() const
QImage QQuickWindow::grabWindow()
{
Q_D(QQuickWindow);
+ if (!isVisible()) {
+
+ if (d->context->isReady()) {
+ qWarning("QQuickWindow::grabWindow: scene graph already in use");
+ return QImage();
+ }
+
+ if (!handle() || !size().isValid()) {
+ qWarning("QQuickWindow::grabWindow: window must be created and have a valid size");
+ return QImage();
+ }
+
+ QOpenGLContext context;
+ context.setFormat(requestedFormat());
+ context.create();
+ context.makeCurrent(this);
+ d->context->initialize(&context);
+
+ d->polishItems();
+ d->syncSceneGraph();
+ d->renderSceneGraph(size());
+
+ QImage image = qt_gl_read_framebuffer(size(), false, false);
+ d->cleanupNodesOnShutdown();
+ d->context->invalidate();
+ context.doneCurrent();
+
+ return image;
+ }
+
return d->windowManager->grab(this);
}
@@ -2625,7 +2786,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
Q_D(const QQuickWindow);
if (!d->incubationController)
- d->incubationController = new QQuickWindowIncubationController(this);
+ d->incubationController = new QQuickWindowIncubationController(d->windowManager);
return d->incubationController;
}
@@ -2817,7 +2978,7 @@ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, Create
Setting the clear color has no effect when clearing is disabled.
By default, the clear color is white.
- \sa setClearBeforeRendering()
+ \sa setClearBeforeRendering(), setDefaultAlphaBuffer()
*/
void QQuickWindow::setColor(const QColor &color)
@@ -2827,7 +2988,7 @@ void QQuickWindow::setColor(const QColor &color)
return;
if (color.alpha() != d->clearColor.alpha()) {
- QSurfaceFormat fmt = format();
+ QSurfaceFormat fmt = requestedFormat();
if (color.alpha() < 255)
fmt.setAlphaBufferSize(8);
else
@@ -2845,6 +3006,31 @@ QColor QQuickWindow::color() const
}
/*!
+ \brief Returns whether to use alpha transparency on newly created windows.
+
+ \since Qt 5.1
+ \sa setDefaultAlphaBuffer()
+ */
+bool QQuickWindow::hasDefaultAlphaBuffer()
+{
+ return QQuickWindowPrivate::defaultAlphaBuffer;
+}
+
+/*!
+ \brief \a useAlpha specifies whether to use alpha transparency on newly created windows.
+ \since Qt 5.1
+
+ In any application which expects to create translucent windows, it's
+ necessary to set this to true before creating the first QQuickWindow,
+ because all windows will share the same \l QOpenGLContext. The default
+ value is false.
+ */
+void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha)
+{
+ QQuickWindowPrivate::defaultAlphaBuffer = useAlpha;
+}
+
+/*!
\qmlproperty string QtQuick.Window2::Window::title
The window's title in the windowing system.
@@ -2994,6 +3180,22 @@ QColor QQuickWindow::color() const
no item with active focus.
*/
+/*!
+ \qmlproperty QtQuick.Window2::Window::active
+ \since Qt 5.1
+
+ The active status of the window.
+
+ \sa requestActivate()
+ */
+
+/*!
+ \qmlmethod QtQuick2::Window::requestActivate()
+ \since QtQuick 2.1
+
+ Requests the window to be activated, i.e. receive keyboard focus.
+ */
+
#include "moc_qquickwindow.cpp"
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index a2ba9e9fe0..a0bc832334 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -57,6 +57,7 @@ class QQuickWindowPrivate;
class QOpenGLFramebufferObject;
class QQmlIncubationController;
class QInputMethodEvent;
+class QQuickCloseEvent;
class Q_QUICK_EXPORT QQuickWindow : public QWindow
{
@@ -114,6 +115,9 @@ public:
void setColor(const QColor &color);
QColor color() const;
+ static bool hasDefaultAlphaBuffer();
+ static void setDefaultAlphaBuffer(bool useAlpha);
+
void setPersistentOpenGLContext(bool persistent);
bool isPersistentOpenGLContext() const;
@@ -129,6 +133,7 @@ Q_SIGNALS:
void beforeSynchronizing();
void beforeRendering();
void afterRendering();
+ Q_REVISION(1) void closing(QQuickCloseEvent *close);
void colorChanged(const QColor &);
Q_REVISION(1) void activeFocusItemChanged();
@@ -144,6 +149,7 @@ protected:
virtual void showEvent(QShowEvent *);
virtual void hideEvent(QHideEvent *);
+ // TODO Qt 6: reimplement QWindow::closeEvent to emit closing
virtual void focusInEvent(QFocusEvent *);
virtual void focusOutEvent(QFocusEvent *);
@@ -162,6 +168,7 @@ protected:
private Q_SLOTS:
void maybeUpdate();
void cleanupSceneGraph();
+ void setTransientParent_helper(QQuickWindow *window);
private:
friend class QQuickItem;
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index ab772ca2bc..2dddd9ab68 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -178,9 +178,6 @@ public:
bool isRenderable() const;
- bool renderWithoutShowing;
- void setRenderWithoutShowing(bool enabled);
-
QQuickItem::UpdatePaintNodeData updatePaintNodeData;
QQuickItem *dirtyItemList;
@@ -212,6 +209,7 @@ public:
uint persistentSceneGraph : 1;
uint lastWheelEventAccepted : 1;
+ bool componentCompleted : 1;
QOpenGLFramebufferObject *renderTarget;
uint renderTargetId;
@@ -222,15 +220,40 @@ public:
mutable QQuickWindowIncubationController *incubationController;
+ static bool defaultAlphaBuffer;
+
static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event);
+ // data property
+ static void data_append(QQmlListProperty<QObject> *, QObject *);
+ static int data_count(QQmlListProperty<QObject> *);
+ static QObject *data_at(QQmlListProperty<QObject> *, int);
+ static void data_clear(QQmlListProperty<QObject> *);
+
private:
static void cleanupNodesOnShutdown(QQuickItem *);
};
+class Q_QUICK_PRIVATE_EXPORT QQuickCloseEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ QQuickCloseEvent()
+ : _accepted(true) {}
+
+ bool isAccepted() { return _accepted; }
+ void setAccepted(bool accepted) { _accepted = accepted; }
+
+private:
+ bool _accepted;
+};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickWindowPrivate::FocusOptions)
QT_END_NAMESPACE
+QML_DECLARE_TYPE(QQuickCloseEvent)
+
#endif // QQUICKWINDOW_P_H
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index f826a53a29..b91edc2fd5 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -42,18 +42,40 @@
#include "qquickwindowmodule_p.h"
#include "qquickscreen_p.h"
#include <QtQuick/QQuickWindow>
+#include <QtCore/QCoreApplication>
+#include <QtQml/QQmlEngine>
QT_BEGIN_NAMESPACE
+class QQuickWindowQmlImpl : public QQuickWindow, public QQmlParserStatus
+{
+ Q_INTERFACES(QQmlParserStatus)
+ Q_OBJECT
+protected:
+ void classBegin() {
+ //Give QQuickView behavior when created from QML with QQmlApplicationEngine
+ if (QCoreApplication::instance()->property("__qml_using_qqmlapplicationengine") == QVariant(true)) {
+ QQmlEngine* e = qmlEngine(this);
+ if (e && !e->incubationController())
+ e->setIncubationController(incubationController());
+ }
+ }
+
+ void componentComplete() {}
+};
+
void QQuickWindowModule::defineModule()
{
const char uri[] = "QtQuick.Window";
qmlRegisterType<QQuickWindow>(uri, 2, 0, "Window");
qmlRegisterRevision<QWindow,1>(uri, 2, 1);
- qmlRegisterType<QQuickWindow,1>(uri, 2, 1, "Window");
+ qmlRegisterRevision<QQuickWindow,1>(uri, 2, 1);//Type moved to a subclass, but also has new members
+ qmlRegisterType<QQuickWindowQmlImpl>(uri, 2, 1, "Window");
qmlRegisterUncreatableType<QQuickScreen>(uri, 2, 0, "Screen", QStringLiteral("Screen can only be used via the attached property."));
}
+#include "qquickwindowmodule.moc"
+
QT_END_NAMESPACE