/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the Qt scene graph research project. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qxborderimage_p.h" #include "qxborderimage_p_p.h" #include "nodes/qxninepatchnode_p.h" #include "adaptationlayer.h" #include #include #include #include #include QxBorderImage::QxBorderImage(QxItem *parent) : QxImageBase(*(new QxBorderImagePrivate), parent) { } QxBorderImage::~QxBorderImage() { Q_D(QxBorderImage); if (d->sciReply) d->sciReply->deleteLater(); delete d->node; } void QxBorderImage::setSource(const QUrl &url) { Q_D(QxBorderImage); //equality is fairly expensive, so we bypass for simple, common case if ((d->url.isEmpty() == url.isEmpty()) && url == d->url) return; if (d->sciReply) { d->sciReply->deleteLater(); d->sciReply = 0; } d->url = url; d->sciurl = QUrl(); emit sourceChanged(d->url); if (isComponentComplete()) load(); } void QxBorderImage::load() { Q_D(QxBorderImage); if (d->progress != 0.0) { d->progress = 0.0; emit progressChanged(d->progress); } if (d->url.isEmpty()) { d->pix.clear(this); d->status = Null; setImplicitWidth(0); setImplicitHeight(0); emit statusChanged(d->status); d->updateNode(); } else { d->status = Loading; if (d->url.path().endsWith(QLatin1String("sci"))) { #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url); if (!lf.isEmpty()) { QFile file(lf); file.open(QIODevice::ReadOnly); setGridScaledImage(QDeclarativeGridScaledImage(&file)); } else #endif { QNetworkRequest req(d->url); d->sciReply = qmlEngine(this)->networkAccessManager()->get(req); static int sciReplyFinished = -1; static int thisSciRequestFinished = -1; if (sciReplyFinished == -1) { sciReplyFinished = QNetworkReply::staticMetaObject.indexOfSignal("finished()"); thisSciRequestFinished = QxBorderImage::staticMetaObject.indexOfSlot("sciRequestFinished()"); } QMetaObject::connect(d->sciReply, sciReplyFinished, this, thisSciRequestFinished, Qt::DirectConnection); } } else { d->pix.load(qmlEngine(this), d->url, d->async); if (d->pix.isLoading()) { d->pix.connectFinished(this, SLOT(requestFinished())); d->pix.connectDownloadProgress(this, SLOT(requestProgress(qint64,qint64))); } else { QSize impsize = d->pix.implicitSize(); setImplicitWidth(impsize.width()); setImplicitHeight(impsize.height()); if (d->pix.isReady()) { d->status = Ready; } else { d->status = Error; qmlInfo(this) << d->pix.error(); } d->progress = 1.0; emit statusChanged(d->status); emit progressChanged(d->progress); d->updatePixmap(); } } } emit statusChanged(d->status); } QDeclarativeScaleGrid *QxBorderImage::border() { Q_D(QxBorderImage); return d->getScaleGrid(); } QxBorderImage::TileMode QxBorderImage::horizontalTileMode() const { Q_D(const QxBorderImage); return d->horizontalTileMode; } void QxBorderImage::setHorizontalTileMode(TileMode t) { Q_D(QxBorderImage); if (t != d->horizontalTileMode) { d->horizontalTileMode = t; emit horizontalTileModeChanged(); d->updateNode(); } } QxBorderImage::TileMode QxBorderImage::verticalTileMode() const { Q_D(const QxBorderImage); return d->verticalTileMode; } void QxBorderImage::setVerticalTileMode(TileMode t) { Q_D(QxBorderImage); if (t != d->verticalTileMode) { d->verticalTileMode = t; emit verticalTileModeChanged(); d->updateNode(); } } void QxBorderImage::setGridScaledImage(const QDeclarativeGridScaledImage& sci) { Q_D(QxBorderImage); if (!sci.isValid()) { d->status = Error; emit statusChanged(d->status); } else { QDeclarativeScaleGrid *sg = border(); sg->setTop(sci.gridTop()); sg->setBottom(sci.gridBottom()); sg->setLeft(sci.gridLeft()); sg->setRight(sci.gridRight()); d->horizontalTileMode = (QxBorderImage::TileMode)sci.horizontalTileRule(); d->verticalTileMode = (QxBorderImage::TileMode)sci.verticalTileRule(); d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl())); d->pix.load(qmlEngine(this), d->sciurl, d->async); if (d->pix.isLoading()) { static int thisRequestProgress = -1; static int thisRequestFinished = -1; if (thisRequestProgress == -1) { thisRequestProgress = QxBorderImage::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)"); thisRequestFinished = QxBorderImage::staticMetaObject.indexOfSlot("requestFinished()"); } d->pix.connectFinished(this, thisRequestFinished); d->pix.connectDownloadProgress(this, thisRequestProgress); } else { QSize impsize = d->pix.implicitSize(); setImplicitWidth(impsize.width()); setImplicitHeight(impsize.height()); if (d->pix.isReady()) { d->status = Ready; } else { d->status = Error; qmlInfo(this) << d->pix.error(); } d->progress = 1.0; emit statusChanged(d->status); emit progressChanged(1.0); d->updatePixmap(); } } } void QxBorderImage::requestFinished() { Q_D(QxBorderImage); QSize impsize = d->pix.implicitSize(); if (d->pix.isError()) { d->status = Error; qmlInfo(this) << d->pix.error(); } else { d->status = Ready; } setImplicitWidth(impsize.width()); setImplicitHeight(impsize.height()); d->progress = 1.0; emit statusChanged(d->status); emit progressChanged(1.0); d->updatePixmap(); } #define BORDERIMAGE_MAX_REDIRECT 16 void QxBorderImage::sciRequestFinished() { Q_D(QxBorderImage); d->redirectCount++; if (d->redirectCount < BORDERIMAGE_MAX_REDIRECT) { QVariant redirect = d->sciReply->attribute(QNetworkRequest::RedirectionTargetAttribute); if (redirect.isValid()) { QUrl url = d->sciReply->url().resolved(redirect.toUrl()); setSource(url); return; } } d->redirectCount=0; if (d->sciReply->error() != QNetworkReply::NoError) { d->status = Error; d->sciReply->deleteLater(); d->sciReply = 0; emit statusChanged(d->status); } else { QDeclarativeGridScaledImage sci(d->sciReply); d->sciReply->deleteLater(); d->sciReply = 0; setGridScaledImage(sci); } } #if 0 void QxBorderImage::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) { Q_D(QxBorderImage); if (d->pix.isNull()) return; bool oldAA = p->testRenderHint(QPainter::Antialiasing); bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform); if (d->smooth) p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth); const QDeclarativeScaleGrid *border = d->getScaleGrid(); QMargins margins(border->left(), border->top(), border->right(), border->bottom()); QTileRules rules((Qt::TileRule)d->horizontalTileMode, (Qt::TileRule)d->verticalTileMode); qDrawBorderPixmap(p, QRect(0, 0, (int)d->width(), (int)d->height()), margins, d->pix, d->pix.rect(), margins, rules); if (d->smooth) { p->setRenderHint(QPainter::Antialiasing, oldAA); p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth); } } #endif void QxBorderImagePrivate::updatePixmap() { Q_Q(QxBorderImage); if (!q->isComponentComplete()) return; if (node) { q->setPaintNode(0); delete node; } if (!pix.isNull()) { // XXX akennedy // Doesn't support all the tiling modes const QDeclarativeScaleGrid *border = getScaleGrid(); QRect inner(border->left(), border->top(), pix.width() - border->right() - border->left(), pix.height() - border->bottom() - border->top()); texture = QSGContext::current->textureManager()->upload(pix.pixmap().toImage()); node = new QxNinePatchNode(QRectF(0, 0, q->width(), q->height()), texture, inner, q->renderOpacity(), smooth); q->setPaintNode(node); } } void QxBorderImagePrivate::updateNode() { Q_Q(QxBorderImage); if (!q->isComponentComplete()) return; if (node) { if (node->rect() != QRectF(0, 0, q->width(), q->height())) { node->setRect(QRectF(0, 0, q->width(), q->height())); q->setPaintNode(node); // Indicate that the geometry has changed so that the clip can be updated. } if (node->opacity() != renderOpacity) node->setOpacity(renderOpacity); if (node->linearFiltering() != smooth) node->setLinearFiltering(smooth); } } void QxBorderImage::componentComplete() { QxImageBase::componentComplete(); Q_D(QxBorderImage); d->updatePixmap(); } void QxBorderImage::renderOpacityChanged(qreal newOpacity, qreal oldOpacity) { Q_D(QxBorderImage); QxImageBase::renderOpacityChanged(newOpacity, oldOpacity); d->updateNode(); } void QxBorderImage::geometryChanged(const QRectF &newR, const QRectF &oldR) { Q_D(QxBorderImage); QxImageBase::geometryChanged(newR, oldR); d->updateNode(); } void QxBorderImage::smoothChange(bool newSmooth, bool oldSmooth) { Q_D(QxBorderImage); QxImageBase::smoothChange(newSmooth, oldSmooth); d->updateNode(); }