From 327d212f5cff81f1c21b7be5c54b3e1eab4f0ac5 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 24 Feb 2010 16:26:09 +0100 Subject: Add QDeclarativeGraphicsWidget, a QGraphicsWidget version of QmlView Could use to be renamed. Possibly to -QDeclarativeViewGraphicsWidget -QGraphicsDeclarativeViewWidget (Or QGraphicsD20, in the spirit of i18n) But those aren't any shorter. Task-number: QTBUG-7067 --- doc/src/declarative/integrating.qdoc | 10 + .../util/qdeclarativegraphicswidget.cpp | 457 +++++++++++++++++++++ src/declarative/util/qdeclarativegraphicswidget.h | 113 +++++ src/declarative/util/util.pri | 6 +- 4 files changed, 584 insertions(+), 2 deletions(-) create mode 100644 src/declarative/util/qdeclarativegraphicswidget.cpp create mode 100644 src/declarative/util/qdeclarativegraphicswidget.h diff --git a/doc/src/declarative/integrating.qdoc b/doc/src/declarative/integrating.qdoc index c685d3d..09ed178 100644 --- a/doc/src/declarative/integrating.qdoc +++ b/doc/src/declarative/integrating.qdoc @@ -86,6 +86,9 @@ QGraphicsObject *object = scene->addItem(object); \endcode +There is a convenience QGraphicsWidget subclass, QDeclarativeGraphicsWidget, which takes care of the engine +and component instantiation for you. + The following QGraphicsView options are recommended for optimal performance of QML UIs: @@ -95,6 +98,13 @@ of QML UIs: \o QGraphicsScene::setItemIndexMethod(QGraphicsScene::NoIndex); \endlist +And the following QGraphicsView options are required for QML key handling to work: + +\list +\o QGraphicsView::viewport()->setFocusPolicy(Qt::NoFocus); +\o QGraphicsScene::setStickyFocus(true); +\endlist + \section1 Using existing QGraphicsWidgets in QML Another way of integrating with a QGraphicsView based UI is to expose your existing QGraphicsWidgets to QML, and constructing your scene in QML. Note that diff --git a/src/declarative/util/qdeclarativegraphicswidget.cpp b/src/declarative/util/qdeclarativegraphicswidget.cpp new file mode 100644 index 0000000..1d0d468 --- /dev/null +++ b/src/declarative/util/qdeclarativegraphicswidget.cpp @@ -0,0 +1,457 @@ +/**************************************************************************** +** +** 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 QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativegraphicswidget.h" + +#include "qperformancelog_p_p.h" +#include "qfxperf_p_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDeclarativeGraphicsWidgetSharedQDeclarativeEngine +{ +public: + QDeclarativeGraphicsWidgetSharedQDeclarativeEngine(){} + + static QDeclarativeEngine* sharedEngine(){ + if(!references) + return 0; + return &QDeclarativeGraphicsWidgetSharedQDeclarativeEngine::m_instance->engine; + } + static void attach(){ + if(!references++) + m_instance = new QDeclarativeGraphicsWidgetSharedQDeclarativeEngine(); + } + + static void detach(){ + if(!--references) + delete m_instance; + } + +private: + static QDeclarativeGraphicsWidgetSharedQDeclarativeEngine* m_instance; + static int references; + QDeclarativeEngine engine; +}; + +int QDeclarativeGraphicsWidgetSharedQDeclarativeEngine::references = 0; +QDeclarativeGraphicsWidgetSharedQDeclarativeEngine* QDeclarativeGraphicsWidgetSharedQDeclarativeEngine::m_instance = 0; + +class QDeclarativeGraphicsWidgetPrivate +{ +public: + QDeclarativeGraphicsWidgetPrivate() + : root(0), component(0), + resizeMode(QDeclarativeGraphicsWidget::SizeViewToRootObject) + { + QDeclarativeGraphicsWidgetSharedQDeclarativeEngine::attach(); + engine = QDeclarativeGraphicsWidgetSharedQDeclarativeEngine::sharedEngine(); + } + + ~QDeclarativeGraphicsWidgetPrivate() + { + QDeclarativeGraphicsWidgetSharedQDeclarativeEngine::detach(); + } + + QGuard root; + QGuard declarativeRoot; + + QUrl source; + + QDeclarativeEngine* engine; + QDeclarativeComponent *component; + QBasicTimer resizetimer; + + mutable QSize initialSize; + QDeclarativeGraphicsWidget::ResizeMode resizeMode; + + void init(); + +}; + +/*! + \class QDeclarativeGraphicsWidget + \brief The QDeclarativeGraphicsWidget class provides a QGraphicsWidget for displaying a Qt Declarative user interface. + + Any QGraphicsObject or QDeclarativeGraphicsItem + created via Qt Declarative can be placed on a standard QGraphicsScene and viewed with a standard + QGraphicsView. + + QDeclarativeGraphicsWidget is a convenience class which handles QDeclarativeComponent loading and object creation. + It shares the same QDeclarativeEngine between all QDeclarativeGraphicsWidgets in the application, to minimize overhead. + + QDeclarativeGraphicsWidget is ideal for when you have many small components styled with Qt Declarative, and want to integrate + them into a larger QGraphicsItem based scene. If your interface is primarily Qt Declarative based, consider using QDeclarativeView + instead. + + Note that the following settings on your QGraphicsScene/View are recommended for optimal performance with Qt Declarative: + \list + \o QGraphicsView::setOptimizationFlags(QGraphicsView::DontSavePainterState); + \o QGraphicsView::setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + \o QGraphicsScene::setItemIndexMethod(QGraphicsScene::NoIndex); + \endlist + Also note that the following settings on your QGraphicsScene/View are required for key handling in Qt Declarative to work: + \list + \o QGraphicsView::viewport()->setFocusPolicy(Qt::NoFocus); + \o QGraphicsScene::setStickyFocus(true); + \endlist + + To receive errors related to loading and executing declarative files with QDeclarativeGraphicsWidget, + you can connect to the statusChanged() signal and monitor for QDeclarativeGraphicsWidget::Error. + The errors are available via QDeclarativeGraphicsWidget::errors(). +*/ + + +/*! \fn void QDeclarativeGraphicsWidget::sceneResized(QSize size) + This signal is emitted when the view is resized to \a size. +*/ + +/*! \fn void QDeclarativeGraphicsWidget::statusChanged(QDeclarativeGraphicsWidget::Status status) + This signal is emitted when the component's current \l{QDeclarativeGraphicsWidget::Status} {status} changes. +*/ + +/*! + \fn QDeclarativeGraphicsWidget::QDeclarativeGraphicsWidget(QGraphicsItem *parent) + + Constructs a QDeclarativeGraphicsWidget with the given \a parent. +*/ +QDeclarativeGraphicsWidget::QDeclarativeGraphicsWidget(QGraphicsItem *parent) +: QGraphicsWidget(parent), d(new QDeclarativeGraphicsWidgetPrivate) +{ + setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred); + d->init(); +} + +void QDeclarativeGraphicsWidgetPrivate::init() +{ +} + +/*! + The destructor clears the view's \l {QGraphicsObject} {items} and + deletes the internal representation. + */ +QDeclarativeGraphicsWidget::~QDeclarativeGraphicsWidget() +{ + delete d->root; + delete d; +} + +/*! + Sets the source to the \a url. + + Will also load the QML file and instantiate the component. + + */ +void QDeclarativeGraphicsWidget::setSource(const QUrl& url) +{ + d->source = url; + + //Execute + if(d->root) + delete d->root; + if(d->component) + delete d->component; + d->component = new QDeclarativeComponent(d->engine, d->source, this); + + if (!d->component->isLoading()) { + continueExecute(); + } else { + connect(d->component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), this, SLOT(continueExecute())); + } +} + +/*! + Returns the source URL, if set. + + \sa setSource() + */ +QUrl QDeclarativeGraphicsWidget::source() const +{ + return d->source; +} + +/*! + Returns a pointer to the QDeclarativeEngine used for instantiating + Qt Declarative Components. + */ +QDeclarativeEngine* QDeclarativeGraphicsWidget::engine() +{ + return d->engine; +} + +/*! + This function returns the root of the context hierarchy. Each declarative + component is instantiated in a QDeclarativeContext. QDeclarativeContext's are + essential for passing data to declarative components. In Qt Declarative, contexts are + arranged hierarchically and this hierarchy is managed by the + QDeclarativeEngine. + */ +QDeclarativeContext* QDeclarativeGraphicsWidget::rootContext() +{ + return d->engine->rootContext(); +} + + +/*! + \enum QDeclarativeGraphicsWidget::Status + + Specifies the loading status of the QDeclarativeGraphicsWidget. + + \value Null This QDeclarativeGraphicsWidget has no source set. + \value Ready This QDeclarativeGraphicsWidget has loaded and created the declarative component. + \value Loading This QDeclarativeGraphicsWidget is loading network data. + \value Error An error has occured. Calling errorDescription() to retrieve a description. +*/ + +/*! + \property QDeclarativeGraphicsWidget::status + The component's current \l{QDeclarativeGraphicsWidget::Status} {status}. +*/ + +QDeclarativeGraphicsWidget::Status QDeclarativeGraphicsWidget::status() const +{ + if (!d->component) + return QDeclarativeGraphicsWidget::Null; + + return QDeclarativeGraphicsWidget::Status(d->component->status()); +} + +/*! + Return the list of errors that occured during the last compile or create + operation. An empty list is returned if isError() is not set. +*/ +QList QDeclarativeGraphicsWidget::errors() const +{ + if (d->component) + return d->component->errors(); + return QList(); +} + + +/*! + \property QDeclarativeGraphicsWidget::resizeMode + \brief whether the view should resize the canvas contents + + If this property is set to SizeViewToRootObject (the default), the view + resizes with the root item in the declarative file. + + If this property is set to SizeRootObjectToView, the view will + automatically resize the root item. + + Regardless of this property, the sizeHint of the view + is the initial size of the root item. Note though that + since declarative files may load dynamically, that size may change. + + \sa initialSize() +*/ + +void QDeclarativeGraphicsWidget::setResizeMode(ResizeMode mode) +{ + if (d->resizeMode == mode) + return; + + d->resizeMode = mode; + if (d->declarativeRoot) { + if (d->resizeMode == SizeRootObjectToView) { + d->declarativeRoot->setWidth(size().width()); + d->declarativeRoot->setHeight(size().height()); + } else { + d->declarativeRoot->setWidth(d->initialSize.width()); + d->declarativeRoot->setHeight(d->initialSize.height()); + } + } +} + +QDeclarativeGraphicsWidget::ResizeMode QDeclarativeGraphicsWidget::resizeMode() const +{ + return d->resizeMode; +} + +/*! + \internal + */ +void QDeclarativeGraphicsWidget::continueExecute() +{ + + disconnect(d->component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), this, SLOT(continueExecute())); + + if (d->component->isError()) { + QList errorList = d->component->errors(); + foreach (const QDeclarativeError &error, errorList) { + qWarning() << error; + } + emit statusChanged(status()); + return; + } + + QObject *obj = d->component->create(); + + if(d->component->isError()) { + QList errorList = d->component->errors(); + foreach (const QDeclarativeError &error, errorList) { + qWarning() << error; + } + emit statusChanged(status()); + return; + } + + if (obj) { + if (QDeclarativeItem *item = qobject_cast(obj)) { + + item->QGraphicsItem::setParentItem(this); + item->QObject::setParent(this); + + d->root = item; + d->declarativeRoot = item; + connect(item, SIGNAL(widthChanged()), this, SLOT(sizeChanged())); + connect(item, SIGNAL(heightChanged()), this, SLOT(sizeChanged())); + if (d->initialSize.height() <= 0 && d->declarativeRoot->width() > 0) + d->initialSize.setWidth(d->declarativeRoot->width()); + if (d->initialSize.height() <= 0 && d->declarativeRoot->height() > 0) + d->initialSize.setHeight(d->declarativeRoot->height()); + resize(d->initialSize); + + if (d->resizeMode == SizeRootObjectToView) { + d->declarativeRoot->setWidth(size().width()); + d->declarativeRoot->setHeight(size().height()); + } else { + QSizeF sz(d->declarativeRoot->width(),d->declarativeRoot->height()); + emit sceneResized(sz); + resize(sz); + } + updateGeometry(); + } else if (QGraphicsObject *item = qobject_cast(obj)) { + item->setParent(this); + qWarning() << "QDeclarativeGraphicsWidget::resizeMode is not honored for components of type QGraphicsObject"; + } else if (qobject_cast(obj)) { + qWarning() << "QDeclarativeGraphicsWidget does not support loading QML files containing QWidgets"; + } + } + emit statusChanged(status()); +} + +/*! + \internal + */ +void QDeclarativeGraphicsWidget::sizeChanged() +{ + // delay, so we catch both width and height changing. + d->resizetimer.start(0,this); +} + +/*! + \internal + If the \l {QTimerEvent} {timer event} \a e is this + view's resize timer, sceneResized() is emitted. + */ +void QDeclarativeGraphicsWidget::timerEvent(QTimerEvent* e) +{ + if (!e || e->timerId() == d->resizetimer.timerId()) { + if (d->declarativeRoot) { + QSize sz(d->declarativeRoot->width(),d->declarativeRoot->height()); + emit sceneResized(sz); + } + d->resizetimer.stop(); + updateGeometry(); + } +} + +/*! + \internal + The size hint is the size of the root item. +*/ +QSizeF QDeclarativeGraphicsWidget::sizeHint() const +{ + if (d->declarativeRoot) { + if (d->initialSize.width() <= 0) + d->initialSize.setWidth(d->declarativeRoot->width()); + if (d->initialSize.height() <= 0) + d->initialSize.setHeight(d->declarativeRoot->height()); + } + return d->initialSize; +} + +/*! + Returns the view's root \l {QGraphicsObject} {item}. + */ +QGraphicsObject *QDeclarativeGraphicsWidget::rootObject() const +{ + return d->root; +} + +/*! + \internal + This function handles the \l {QGraphicsSceneResizeEvent} {resize event} + \a e. + */ +void QDeclarativeGraphicsWidget::resizeEvent(QGraphicsSceneResizeEvent *e) +{ + if (d->resizeMode == SizeRootObjectToView && d->declarativeRoot) { + d->declarativeRoot->setWidth(size().width()); + d->declarativeRoot->setHeight(size().height()); + } + QGraphicsWidget::resizeEvent(e); +} + +QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativegraphicswidget.h b/src/declarative/util/qdeclarativegraphicswidget.h new file mode 100644 index 0000000..33ebc7b --- /dev/null +++ b/src/declarative/util/qdeclarativegraphicswidget.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** 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 QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEGRAPHICSWIDGET_H +#define QDECLARATIVEGRAPHICSWIDGET_H + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QGraphicsObject; +class QDeclarativeEngine; +class QDeclarativeContext; +class QDeclarativeError; + +class QDeclarativeGraphicsWidgetPrivate; + +class Q_DECLARATIVE_EXPORT QDeclarativeGraphicsWidget : public QGraphicsWidget +{ + Q_OBJECT + Q_PROPERTY(ResizeMode resizeMode READ resizeMode WRITE setResizeMode) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(QUrl source READ source WRITE setSource) + +public: + explicit QDeclarativeGraphicsWidget(QGraphicsItem *parent = 0); + virtual ~QDeclarativeGraphicsWidget(); + + QUrl source() const; + void setSource(const QUrl&); + + QDeclarativeEngine* engine(); + QDeclarativeContext* rootContext(); + + QGraphicsObject *rootObject() const; + + enum ResizeMode { SizeViewToRootObject, SizeRootObjectToView }; + ResizeMode resizeMode() const; + void setResizeMode(ResizeMode); + QSizeF sizeHint() const; + + enum Status { Null, Ready, Loading, Error }; + Status status() const; + + QList errors() const; + +Q_SIGNALS: + void sceneResized(QSizeF size); + void statusChanged(QDeclarativeGraphicsWidget::Status); + +private Q_SLOTS: + void continueExecute(); + void sizeChanged(); + +protected: + virtual void resizeEvent(QGraphicsSceneResizeEvent *); + void timerEvent(QTimerEvent*); + +private: + QDeclarativeGraphicsWidgetPrivate* d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEGRAPHICSWIDGET_H diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri index 610eb3f..46126e5 100644 --- a/src/declarative/util/util.pri +++ b/src/declarative/util/util.pri @@ -30,7 +30,8 @@ SOURCES += \ $$PWD/qdeclarativedatetimeformatter.cpp \ $$PWD/qdeclarativebehavior.cpp \ $$PWD/qdeclarativefontloader.cpp \ - $$PWD/qdeclarativestyledtext.cpp + $$PWD/qdeclarativestyledtext.cpp \ + $$PWD/qdeclarativegraphicswidget.cpp HEADERS += \ $$PWD/qdeclarativeutilmodule_p.h\ @@ -65,7 +66,8 @@ HEADERS += \ $$PWD/qdeclarativedatetimeformatter_p.h \ $$PWD/qdeclarativebehavior_p.h \ $$PWD/qdeclarativefontloader_p.h \ - $$PWD/qdeclarativestyledtext_p.h + $$PWD/qdeclarativestyledtext_p.h \ + $$PWD/qdeclarativegraphicswidget.h contains(QT_CONFIG, xmlpatterns) { QT+=xmlpatterns -- cgit v0.12