diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-09-08 05:30:38 (GMT) |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2009-09-08 05:30:38 (GMT) |
commit | cad3b0bdacdbdf407dfbdda5f6dc9cb7d96fa709 (patch) | |
tree | 37a16ff73fe102ac0cd169b20f9b12135903d33a /src/declarative | |
parent | 5305831c3b0d58a61efadc1c1d3ce9ce4d6e8c77 (diff) | |
parent | b9a924a1e77faeeba595d0619afb14e8fdbb2dd4 (diff) | |
download | Qt-cad3b0bdacdbdf407dfbdda5f6dc9cb7d96fa709.zip Qt-cad3b0bdacdbdf407dfbdda5f6dc9cb7d96fa709.tar.gz Qt-cad3b0bdacdbdf407dfbdda5f6dc9cb7d96fa709.tar.bz2 |
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Diffstat (limited to 'src/declarative')
25 files changed, 575 insertions, 52 deletions
diff --git a/src/declarative/QmlChanges.txt b/src/declarative/QmlChanges.txt index 95c81c7..9bf4b10 100644 --- a/src/declarative/QmlChanges.txt +++ b/src/declarative/QmlChanges.txt @@ -66,6 +66,7 @@ MouseRegion: add "hoverEnabled" property MouseRegion: add "pressedButtons" property Timer: add start() and stop() slots WebView: add newWindowComponent and newWindowParent properties +Loader: add status() and progress() properties Deletions: Column/VerticalPositioner: lost "margins" property diff --git a/src/declarative/fx/qfxflickable.cpp b/src/declarative/fx/qfxflickable.cpp index 007fa0e..5fe9617 100644 --- a/src/declarative/fx/qfxflickable.cpp +++ b/src/declarative/fx/qfxflickable.cpp @@ -148,6 +148,7 @@ QFxFlickablePrivate::QFxFlickablePrivate() , vWidth(-1), vHeight(-1), overShoot(true), flicked(false), moving(false), stealMouse(false) , pressed(false), atXEnd(false), atXBeginning(true), atYEnd(false), atYBeginning(true) , interactive(true), maxVelocity(-1), reportedVelocitySmoothing(100) + , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0) , horizontalVelocity(this), verticalVelocity(this), vTime(0), visibleArea(0) { fixupXEvent = QmlTimeLineEvent::timeLineEvent<QFxFlickablePrivate, &QFxFlickablePrivate::fixupX>(&_moveX, this); @@ -707,11 +708,57 @@ void QFxFlickable::mouseMoveEvent(QGraphicsSceneMouseEvent *event) void QFxFlickable::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { Q_D(QFxFlickable); + d->clearDelayedPress(); d->handleMouseReleaseEvent(event); event->accept(); ungrabMouse(); } +void QFxFlickablePrivate::captureDelayedPress(QGraphicsSceneMouseEvent *event) +{ + Q_Q(QFxFlickable); + if (!q->scene() || pressDelay <= 0) + return; + delayedPressTarget = q->scene()->mouseGrabberItem(); + delayedPressEvent = new QGraphicsSceneMouseEvent(event->type()); + delayedPressEvent->setAccepted(false); + for (int i = 0x1; i <= 0x10; i <<= 1) { + if (event->buttons() & i) { + Qt::MouseButton button = Qt::MouseButton(i); + delayedPressEvent->setButtonDownPos(button, event->buttonDownPos(button)); + } + } + delayedPressEvent->setScenePos(event->scenePos()); + delayedPressEvent->setLastScenePos(event->lastScenePos()); + delayedPressEvent->setPos(event->pos()); + delayedPressEvent->setLastPos(event->lastPos()); + delayedPressTimer.start(pressDelay, q); +} + +void QFxFlickablePrivate::clearDelayedPress() +{ + if (delayedPressEvent) { + delayedPressTimer.stop(); + delete delayedPressEvent; + delayedPressEvent = 0; + } +} + +void QFxFlickable::timerEvent(QTimerEvent *event) +{ + Q_D(QFxFlickable); + if (event->timerId() == d->delayedPressTimer.timerId()) { + d->delayedPressTimer.stop(); + if (d->delayedPressEvent) { + QFxItem *grabber = scene() ? qobject_cast<QFxItem*>(scene()->mouseGrabberItem()) : 0; + if (!grabber || grabber != this) + scene()->sendEvent(d->delayedPressTarget, d->delayedPressEvent); + delete d->delayedPressEvent; + d->delayedPressEvent = 0; + } + } +} + qreal QFxFlickable::minYExtent() const { return 0.0; @@ -996,22 +1043,34 @@ bool QFxFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event) d->handleMouseMoveEvent(&mouseEvent); break; case QEvent::GraphicsSceneMousePress: + if (d->delayedPressEvent) + return false; + d->handleMousePressEvent(&mouseEvent); + d->captureDelayedPress(event); break; case QEvent::GraphicsSceneMouseRelease: + if (d->delayedPressEvent) { + scene()->sendEvent(d->delayedPressTarget, d->delayedPressEvent); + d->clearDelayedPress(); + } d->handleMouseReleaseEvent(&mouseEvent); break; default: break; } grabber = qobject_cast<QFxItem*>(s->mouseGrabberItem()); - if (grabber && d->stealMouse && !grabber->keepMouseGrab() && grabber != this) + if (grabber && d->stealMouse && !grabber->keepMouseGrab() && grabber != this) { + d->clearDelayedPress(); grabMouse(); + } - return d->stealMouse; + return d->stealMouse || d->delayedPressEvent; } else if (!d->lastPosTime.isNull()) { d->lastPosTime = QTime(); } + if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) + d->clearDelayedPress(); return false; } @@ -1055,6 +1114,31 @@ bool QFxFlickable::isFlicking() const return d->flicked; } +/*! + \qmlproperty int Flickable::pressDelay + + This property holds the time to delay (ms) delivering a press to + children of the Flickable. This can be useful where reacting + to a press before a flicking action has undesireable effects. + + If the flickable is dragged/flicked before the delay times out + the press event will not be delivered. If the button is released + within the timeout, both the press and release will be delivered. +*/ +int QFxFlickable::pressDelay() const +{ + Q_D(const QFxFlickable); + return d->pressDelay; +} + +void QFxFlickable::setPressDelay(int delay) +{ + Q_D(QFxFlickable); + if (d->pressDelay == delay) + return; + d->pressDelay = delay; +} + qreal QFxFlickable::reportedVelocitySmoothing() const { Q_D(const QFxFlickable); diff --git a/src/declarative/fx/qfxflickable.h b/src/declarative/fx/qfxflickable.h index 4905101..b3339b0 100644 --- a/src/declarative/fx/qfxflickable.h +++ b/src/declarative/fx/qfxflickable.h @@ -71,6 +71,7 @@ class Q_DECLARATIVE_EXPORT QFxFlickable : public QFxItem Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged) Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive) + Q_PROPERTY(int pressDelay READ pressDelay WRITE setPressDelay) Q_PROPERTY(bool atXEnd READ isAtXEnd NOTIFY isAtBoundaryChanged) Q_PROPERTY(bool atYEnd READ isAtYEnd NOTIFY isAtBoundaryChanged) @@ -108,6 +109,9 @@ public: bool isMoving() const; bool isFlicking() const; + int pressDelay() const; + void setPressDelay(int delay); + qreal reportedVelocitySmoothing() const; void setReportedVelocitySmoothing(qreal); @@ -148,6 +152,7 @@ protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void timerEvent(QTimerEvent *event); qreal visibleX() const; qreal visibleY() const; diff --git a/src/declarative/fx/qfxflickable_p.h b/src/declarative/fx/qfxflickable_p.h index a506027..7224f21 100644 --- a/src/declarative/fx/qfxflickable_p.h +++ b/src/declarative/fx/qfxflickable_p.h @@ -76,6 +76,9 @@ public: virtual void fixupY(); void updateBeginningEnd(); + void captureDelayedPress(QGraphicsSceneMouseEvent *event); + void clearDelayedPress(); + public: QFxItem *viewport; QmlTimeLineValueProxy<QFxItem> _moveX; @@ -109,6 +112,10 @@ public: qreal reportedVelocitySmoothing; int flickTargetX; int flickTargetY; + QGraphicsSceneMouseEvent *delayedPressEvent; + QGraphicsItem *delayedPressTarget; + QBasicTimer delayedPressTimer; + int pressDelay; void updateVelocity(); struct Velocity : public QmlTimeLineValue diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index 88a0854..3429010 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -336,6 +336,7 @@ public: virtual void keyReleased(QKeyEvent *event); virtual void inputMethodEvent(QInputMethodEvent *event); virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const; + virtual void componentComplete(); private: QFxItemKeyFilter *m_next; @@ -377,6 +378,11 @@ QVariant QFxItemKeyFilter::inputMethodQuery(Qt::InputMethodQuery query) const return QVariant(); } +void QFxItemKeyFilter::componentComplete() +{ + if (m_next) m_next->componentComplete(); +} + class QFxKeyNavigationAttachedPrivate : public QObjectPrivate { public: @@ -912,11 +918,10 @@ public: QFxItem *item; }; -class QFxKeysAttached : public QObject, public QFxItemKeyFilter, public QmlParserStatus +class QFxKeysAttached : public QObject, public QFxItemKeyFilter { Q_OBJECT Q_DECLARE_PRIVATE(QFxKeysAttached) - Q_INTERFACES(QmlParserStatus) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(QList<QFxItem *> *forwardTo READ forwardTo) @@ -2496,6 +2501,8 @@ void QFxItem::componentComplete() d->_anchors->componentComplete(); d->_anchors->d_func()->updateOnComplete(); } + if (d->keyHandler) + d->keyHandler->componentComplete(); } QmlStateGroup *QFxItemPrivate::states() diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp index c24610f..6c0a83e 100644 --- a/src/declarative/fx/qfxlistview.cpp +++ b/src/declarative/fx/qfxlistview.cpp @@ -1507,7 +1507,8 @@ void QFxListView::itemsInserted(int modelIndex, int count) // Update the indexes of the following visible items. for (; index < d->visibleItems.count(); ++index) { FxListItem *listItem = d->visibleItems.at(index); - listItem->setPosition(listItem->position() + (pos - initialPos)); + if (listItem->item != d->currentItem->item) + listItem->setPosition(listItem->position() + (pos - initialPos)); if (listItem->index != -1) listItem->index += count; } diff --git a/src/declarative/fx/qfxloader.cpp b/src/declarative/fx/qfxloader.cpp index 95ddae3..869a5b0 100644 --- a/src/declarative/fx/qfxloader.cpp +++ b/src/declarative/fx/qfxloader.cpp @@ -111,9 +111,12 @@ void QFxLoader::setSource(const QUrl &url) d->source = url; d->item = 0; + emit itemChanged(); if (d->source.isEmpty()) { emit sourceChanged(); + emit statusChanged(); + emit progressChanged(); return; } @@ -122,14 +125,22 @@ void QFxLoader::setSource(const QUrl &url) (*iter)->setOpacity(1.); d->item = (*iter); emit sourceChanged(); + emit statusChanged(); + emit progressChanged(); + emit itemChanged(); } else { d->qmlcomp = new QmlComponent(qmlEngine(this), d->source, this); - if (!d->qmlcomp->isLoading()) + if (!d->qmlcomp->isLoading()) { d->_q_sourceLoaded(); - else + } else { connect(d->qmlcomp, SIGNAL(statusChanged(QmlComponent::Status)), this, SLOT(_q_sourceLoaded())); + connect(d->qmlcomp, SIGNAL(progressChanged(qreal)), + this, SIGNAL(progressChanged())); + emit statusChanged(); + emit progressChanged(); + } } } @@ -146,6 +157,8 @@ void QFxLoaderPrivate::_q_sourceLoaded() delete qmlcomp; qmlcomp = 0; emit q->sourceChanged(); + emit q->statusChanged(); + emit q->progressChanged(); return; } QObject *obj = qmlcomp->create(ctxt); @@ -163,10 +176,58 @@ void QFxLoaderPrivate::_q_sourceLoaded() delete qmlcomp; qmlcomp = 0; emit q->sourceChanged(); + emit q->statusChanged(); + emit q->progressChanged(); + emit q->itemChanged(); } } /*! + \qmlproperty enum Loader::status + + This property holds the status of QML loading. It can be one of: + \list + \o Null - no QML source has been set + \o Ready - the QML source has been loaded + \o Loading - the QML source is currently being loaded + \o Error - an error occurred while loading the QML source + \endlist + + \sa progress +*/ + +/*! + \qmlproperty real Loader::progress + + This property holds the progress of QML data loading, from 0.0 (nothing loaded) + to 1.0 (finished). + + \sa status +*/ +QFxLoader::Status QFxLoader::status() const +{ + Q_D(const QFxLoader); + + if (d->qmlcomp) + return static_cast<QFxLoader::Status>(d->qmlcomp->status()); + + if (d->item) + return Ready; + + return d->source.isEmpty() ? Null : Error; +} + +qreal QFxLoader::progress() const +{ + Q_D(const QFxLoader); + + if (d->qmlcomp) + return d->qmlcomp->progress(); + + return d->item ? 1.0 : 0.0; +} + +/*! \qmlproperty Item Loader::item This property holds the top-level item created from source. */ diff --git a/src/declarative/fx/qfxloader.h b/src/declarative/fx/qfxloader.h index 8c555c6..132c8f4 100644 --- a/src/declarative/fx/qfxloader.h +++ b/src/declarative/fx/qfxloader.h @@ -54,12 +54,14 @@ class QFxLoaderPrivate; class Q_DECLARATIVE_EXPORT QFxLoader : public QFxItem { Q_OBJECT + Q_ENUMS(Status) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(QFxItem *item READ item) //### NOTIFY itemChanged + Q_PROPERTY(QFxItem *item READ item NOTIFY itemChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) //### sourceItem //### sourceComponent - //### status, progress //### resizeMode { NoResize, SizeLoaderToItem (default), SizeItemToLoader } public: @@ -69,10 +71,17 @@ public: QUrl source() const; void setSource(const QUrl &); + enum Status { Null, Ready, Loading, Error }; + Status status() const; + qreal progress() const; + QFxItem *item() const; Q_SIGNALS: + void itemChanged(); void sourceChanged(); + void statusChanged(); + void progressChanged(); private: Q_DISABLE_COPY(QFxLoader) diff --git a/src/declarative/fx/qfxpathview.cpp b/src/declarative/fx/qfxpathview.cpp index 469e9f3..62f9db0 100644 --- a/src/declarative/fx/qfxpathview.cpp +++ b/src/declarative/fx/qfxpathview.cpp @@ -128,6 +128,9 @@ QFxPathView::QFxPathView(QFxPathViewPrivate &dd, QFxItem *parent) QFxPathView::~QFxPathView() { + Q_D(QFxPathView); + if (d->ownModel) + delete d->model; } /*! diff --git a/src/declarative/fx/qfxtextinput.cpp b/src/declarative/fx/qfxtextinput.cpp index 9718321..4dd29cd 100644 --- a/src/declarative/fx/qfxtextinput.cpp +++ b/src/declarative/fx/qfxtextinput.cpp @@ -555,33 +555,33 @@ void QFxTextInput::selectAll() void QFxTextInputPrivate::init() { - Q_Q(QFxTextInput); - control->setCursorWidth(1); - control->setPasswordCharacter(QLatin1Char('*')); - control->setLayoutDirection(Qt::LeftToRight); - q->setSmoothTransform(smooth); - q->setAcceptedMouseButtons(Qt::LeftButton); - q->setFlag(QGraphicsItem::ItemHasNoContents, false); - q->setFlag(QGraphicsItem::ItemAcceptsInputMethod); - q->connect(control, SIGNAL(cursorPositionChanged(int,int)), - q, SLOT(cursorPosChanged())); - q->connect(control, SIGNAL(selectionChanged()), - q, SLOT(selectionChanged())); - q->connect(control, SIGNAL(textChanged(const QString &)), - q, SLOT(q_textChanged())); - q->connect(control, SIGNAL(accepted()), - q, SIGNAL(accepted())); - q->connect(control, SIGNAL(updateNeeded(const QRect &)), - // q, SLOT(dirtyCache(const QRect &))); - q, SLOT(updateAll())); - q->connect(control, SIGNAL(cursorPositionChanged(int,int)), - q, SLOT(updateAll())); - q->connect(control, SIGNAL(selectionChanged()), - q, SLOT(updateAll())); - q->updateSize(); - oldValidity = control->hasAcceptableInput(); - lastSelectionStart = 0; - lastSelectionEnd = 0; + Q_Q(QFxTextInput); + control->setCursorWidth(1); + control->setPasswordCharacter(QLatin1Char('*')); + control->setLayoutDirection(Qt::LeftToRight); + q->setSmoothTransform(smooth); + q->setAcceptedMouseButtons(Qt::LeftButton); + q->setFlag(QGraphicsItem::ItemHasNoContents, false); + q->setFlag(QGraphicsItem::ItemAcceptsInputMethod); + q->connect(control, SIGNAL(cursorPositionChanged(int,int)), + q, SLOT(cursorPosChanged())); + q->connect(control, SIGNAL(selectionChanged()), + q, SLOT(selectionChanged())); + q->connect(control, SIGNAL(textChanged(const QString &)), + q, SLOT(q_textChanged())); + q->connect(control, SIGNAL(accepted()), + q, SIGNAL(accepted())); + q->connect(control, SIGNAL(updateNeeded(const QRect &)), + // q, SLOT(dirtyCache(const QRect &))); + q, SLOT(updateAll())); + q->connect(control, SIGNAL(cursorPositionChanged(int,int)), + q, SLOT(updateAll())); + q->connect(control, SIGNAL(selectionChanged()), + q, SLOT(updateAll())); + q->updateSize(); + oldValidity = control->hasAcceptableInput(); + lastSelectionStart = 0; + lastSelectionEnd = 0; } void QFxTextInput::cursorPosChanged() diff --git a/src/declarative/fx/qfxvisualitemmodel.cpp b/src/declarative/fx/qfxvisualitemmodel.cpp index 82bec09..cac8b8d 100644 --- a/src/declarative/fx/qfxvisualitemmodel.cpp +++ b/src/declarative/fx/qfxvisualitemmodel.cpp @@ -243,6 +243,16 @@ public: QmlContext *m_context; QList<int> m_roles; QHash<int,QString> m_roleNames; + void ensureRoles() { + if (m_roles.isEmpty()) { + if (m_listModelInterface) { + m_roles = m_listModelInterface->roles(); + for (int ii = 0; ii < m_roles.count(); ++ii) + m_roleNames.insert(m_roles.at(ii), + m_listModelInterface->toString(m_roles.at(ii))); + } + } + } struct ObjectRef { ObjectRef(QObject *object=0) : obj(object), ref(1) {} @@ -375,6 +385,7 @@ int QFxVisualDataModelDataMetaObject::createProperty(const char *name, const cha return QmlOpenMetaObject::createProperty(name, type); } else { const QLatin1String sname(name); + data->m_model->ensureRoles(); for (QHash<int, QString>::ConstIterator iter = data->m_model->m_roleNames.begin(); iter != data->m_model->m_roleNames.end(); ++iter) { @@ -397,6 +408,7 @@ QFxVisualDataModelDataMetaObject::propertyCreated(int, QMetaPropertyBuilder &pro && data->m_model->m_modelList) { return data->m_model->m_modelList->at(data->m_index); } else if (data->m_model->m_listModelInterface) { + data->m_model->ensureRoles(); for (QHash<int, QString>::ConstIterator iter = data->m_model->m_roleNames.begin(); iter != data->m_model->m_roleNames.end(); ++iter) { @@ -410,6 +422,7 @@ QFxVisualDataModelDataMetaObject::propertyCreated(int, QMetaPropertyBuilder &pro } } } else if (data->m_model->m_abstractItemModel) { + data->m_model->ensureRoles(); for (QHash<int, QString>::ConstIterator iter = data->m_model->m_roleNames.begin(); iter != data->m_model->m_roleNames.end(); ++iter) { @@ -560,12 +573,6 @@ void QFxVisualDataModel::setModel(const QVariant &model) if (object && (d->m_listModelInterface = qobject_cast<QListModelInterface *>(object))) { d->m_roles.clear(); d->m_roleNames.clear(); - if (d->m_listModelInterface) { - d->m_roles = d->m_listModelInterface->roles(); - for (int ii = 0; ii < d->m_roles.count(); ++ii) - d->m_roleNames.insert(d->m_roles.at(ii), - d->m_listModelInterface->toString(d->m_roles.at(ii))); - } QObject::connect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)), this, SLOT(_q_itemsChanged(int,int,QList<int>))); diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index e897cce..f291ac0 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -121,6 +121,14 @@ void QmlComponentPrivate::typeDataReady() emit q->statusChanged(q->status()); } +void QmlComponentPrivate::updateProgress(qreal p) +{ + Q_Q(QmlComponent); + + progress = p; + emit q->progressChanged(p); +} + void QmlComponentPrivate::fromTypeData(QmlCompositeTypeData *data) { url = data->imports.baseUrl(); @@ -238,6 +246,12 @@ bool QmlComponent::isLoading() const return status() == Loading; } +qreal QmlComponent::progress() const +{ + Q_D(const QmlComponent); + return d->progress; +} + /*! \fn void QmlComponent::statusChanged(QmlComponent::Status status) @@ -343,7 +357,9 @@ void QmlComponent::setData(const QByteArray &data, const QUrl &url) } + d->progress = 1.0; emit statusChanged(status()); + emit progressChanged(d->progress); } /*! @@ -364,17 +380,16 @@ void QmlComponent::loadUrl(const QUrl &url) QmlEnginePrivate::get(d->engine)->typeManager.get(d->url); if (data->status == QmlCompositeTypeData::Waiting) { - d->typeData = data; d->typeData->addWaiter(d); - + d->progress = data->progress; } else { - d->fromTypeData(data); - + d->progress = 1.0; } emit statusChanged(status()); + emit progressChanged(d->progress); } /*! diff --git a/src/declarative/qml/qmlcomponent.h b/src/declarative/qml/qmlcomponent.h index 60b7ccd..af250e5 100644 --- a/src/declarative/qml/qmlcomponent.h +++ b/src/declarative/qml/qmlcomponent.h @@ -84,6 +84,8 @@ public: QList<QmlError> errors() const; + qreal progress() const; + QUrl url() const; virtual QObject *create(QmlContext *context = 0); @@ -95,6 +97,7 @@ public: Q_SIGNALS: void statusChanged(QmlComponent::Status); + void progressChanged(qreal); protected: QmlComponent(QmlComponentPrivate &dd, QObject* parent); diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index 4b459c2..2b25b78 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -74,15 +74,17 @@ class QmlComponentPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QmlComponent) public: - QmlComponentPrivate() : typeData(0), start(-1), count(-1), cc(0), completePending(false), engine(0) {} + QmlComponentPrivate() : typeData(0), progress(0.), start(-1), count(-1), cc(0), completePending(false), engine(0) {} QmlCompositeTypeData *typeData; void typeDataReady(); + void updateProgress(qreal); void fromTypeData(QmlCompositeTypeData *data); QList<QmlError> errors; QUrl url; + qreal progress; int start; int count; diff --git a/src/declarative/qml/qmlcompositetypedata_p.h b/src/declarative/qml/qmlcompositetypedata_p.h index 54933c4..044b4ca 100644 --- a/src/declarative/qml/qmlcompositetypedata_p.h +++ b/src/declarative/qml/qmlcompositetypedata_p.h @@ -108,6 +108,8 @@ struct QmlCompositeTypeData : public QmlRefCount void addWaiter(QmlComponentPrivate *p); void remWaiter(QmlComponentPrivate *p); + qreal progress; + private: friend class QmlCompositeTypeManager; friend class QmlCompiler; diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp index f64547c..a99cff0 100644 --- a/src/declarative/qml/qmlcompositetypemanager.cpp +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -87,6 +87,7 @@ QmlComponent *QmlCompositeTypeData::toComponent(QmlEngine *engine) QmlCompiledData *cc = toCompiledComponent(engine); if (cc) { component = new QmlComponent(engine, cc, -1, -1, 0); + cc->release(); } else { component = new QmlComponent(engine, 0); component->d_func()->url = imports.baseUrl(); @@ -135,6 +136,14 @@ QmlCompositeTypeManager::QmlCompositeTypeManager(QmlEngine *e) { } +QmlCompositeTypeManager::~QmlCompositeTypeManager() +{ + for (Components::Iterator iter = components.begin(); iter != components.end();) { + (*iter)->release(); + iter = components.erase(iter); + } +} + QmlCompositeTypeData *QmlCompositeTypeManager::get(const QUrl &url) { QmlCompositeTypeData *unit = components.value(url.toString()); @@ -234,9 +243,26 @@ void QmlCompositeTypeManager::loadSource(QmlCompositeTypeData *unit) engine->networkAccessManager()->get(QNetworkRequest(url)); QObject::connect(reply, SIGNAL(finished()), this, SLOT(replyFinished())); + QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); } } +void QmlCompositeTypeManager::requestProgress(qint64 received, qint64 total) +{ + if (total <= 0) + return; + QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); + + QmlCompositeTypeData *unit = components.value(reply->url().toString()); + Q_ASSERT(unit); + + unit->progress = qreal(received)/total; + + foreach (QmlComponentPrivate *comp, unit->waiters) + comp->updateProgress(unit->progress); +} + void QmlCompositeTypeManager::setData(QmlCompositeTypeData *unit, const QByteArray &data, const QUrl &url) diff --git a/src/declarative/qml/qmlcompositetypemanager_p.h b/src/declarative/qml/qmlcompositetypemanager_p.h index cb0fc43..41cbe80 100644 --- a/src/declarative/qml/qmlcompositetypemanager_p.h +++ b/src/declarative/qml/qmlcompositetypemanager_p.h @@ -73,6 +73,7 @@ class QmlCompositeTypeManager : public QObject Q_OBJECT public: QmlCompositeTypeManager(QmlEngine *); + ~QmlCompositeTypeManager(); // Return a QmlCompositeTypeData for url. The QmlCompositeTypeData may be // cached. @@ -87,6 +88,7 @@ public: private Q_SLOTS: void replyFinished(); + void requestProgress(qint64 received, qint64 total); private: void loadSource(QmlCompositeTypeData *); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 6d3506c..e3d4840 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -1509,6 +1509,10 @@ public: if (s) { if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return)) return true; + if (s->urls.count() == 1 && !s->isBuiltin[0] && !s->isLibrary[0] && url_return) { + *url_return = QUrl(s->urls[0]+"/").resolved(QUrl(QLatin1String(unqualifiedtype + ".qml"))); + return true; + } } if (url_return) { *url_return = base.resolved(QUrl(QLatin1String(type + ".qml"))); diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index f9b222f..fdba79e 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -219,6 +219,7 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) if (enginePrivate && name.at(0).isUpper()) { // Attached property + //### needs to be done in a better way QmlCompositeTypeData *typeData = enginePrivate->typeManager.get(context->baseUrl()); @@ -230,6 +231,7 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) if (attachedFunc != -1) type = QmlMetaProperty::Property | QmlMetaProperty::Attached; } + typeData->release(); } return; diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp index c488c13..14d85ff 100644 --- a/src/declarative/qml/qmlmetatype.cpp +++ b/src/declarative/qml/qmlmetatype.cpp @@ -83,6 +83,7 @@ QT_BEGIN_NAMESPACE struct QmlMetaTypeData { + ~QmlMetaTypeData(); QList<QmlType *> types; typedef QHash<int, QmlType *> Ids; Ids idToType; @@ -101,6 +102,12 @@ struct QmlMetaTypeData Q_GLOBAL_STATIC(QmlMetaTypeData, metaTypeData) Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock) +QmlMetaTypeData::~QmlMetaTypeData() +{ + for (int i = 0; i < types.count(); ++i) + delete types.at(i); +} + class QmlTypePrivate { public: @@ -190,6 +197,7 @@ QmlType::QmlType(int type, int listType, int qmlListType, QmlType::~QmlType() { + delete d->m_customParser; delete d; } diff --git a/src/declarative/qml/qmlmetatype.h b/src/declarative/qml/qmlmetatype.h index 5ed9a5a..02c817d 100644 --- a/src/declarative/qml/qmlmetatype.h +++ b/src/declarative/qml/qmlmetatype.h @@ -151,6 +151,7 @@ public: private: friend class QmlMetaType; friend class QmlTypePrivate; + friend class QmlMetaTypeData; QmlType(int, int, int, QmlPrivate::Func, const char *, int); QmlType(int, int, int, QmlPrivate::Func, const char *, int, int, int, const QMetaObject *, QmlAttachedPropertiesFunc, const QMetaObject *, int, int, QmlPrivate::CreateFunc, const QMetaObject *, int, QmlCustomParser *); ~QmlType(); diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index 0f2a282..e102f05 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -80,6 +80,8 @@ QmlParser::Object::~Object() prop->release(); foreach(Property *prop, valueTypeProperties) prop->release(); + foreach(const DynamicProperty &prop, dynamicProperties) + if (prop.defaultValue) prop.defaultValue->release(); } const QMetaObject *Object::metaObject() const diff --git a/src/declarative/util/qfxview.cpp b/src/declarative/util/qfxview.cpp index 9291e1a..2a38cda 100644 --- a/src/declarative/util/qfxview.cpp +++ b/src/declarative/util/qfxview.cpp @@ -222,7 +222,7 @@ void QFxView::execute() if (d->qml.isEmpty()) { d->component = new QmlComponent(&d->engine, d->source, this); } else { - d->component = new QmlComponent(&d->engine, d->qml.toUtf8(), d->source); + d->component = new QmlComponent(&d->engine, d->qml.toUtf8(), d->source, this); } if (!d->component->isLoading()) { diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp index 0d9ea94..a5ae60f 100644 --- a/src/declarative/util/qmllistmodel.cpp +++ b/src/declarative/util/qmllistmodel.cpp @@ -72,7 +72,9 @@ struct ListModelData \qmlclass ListModel \brief The ListModel element defines a free-form list data source. - The ListModel is a simple hierarchy of elements containing data roles. + The ListModel is a simple hierarchy of elements containing data roles. The contents can + be defined dynamically, or explicitly in QML: + For example: \code @@ -166,6 +168,29 @@ struct ListModelData } \endcode + The content of a ListModel may be created and modified using the clear(), + append(), and set() methods. For example: + + \code + Component { + id: FruitDelegate + Item { + width: 200; height: 50 + Text { text: name } + Text { text: '$'+cost; anchors.right: parent.right } + + // Double the price when clicked. + MouseRegion { + anchors.fill: parent + onClicked: FruitModel.set(index, "cost", cost*2) + } + } + } + \endcode + + When creating content dynamically, note that the set of available properties cannot be changed + except by first clearing the model - whatever properties are first added are then the + only permitted properties in the model. */ class ModelObject : public QObject @@ -189,7 +214,6 @@ struct ModelNode { ModelNode(); ~ModelNode(); - QString className; QList<QVariant> values; QHash<QString, ModelNode *> properties; @@ -214,6 +238,19 @@ struct ModelNode return objectCache; } + void setProperty(const QString& prop, const QVariant& val) { + QHash<QString, ModelNode *>::const_iterator it = properties.find(prop); + if (it != properties.end()) { + (*it)->values[0] = val; + } else { + ModelNode *n = new ModelNode; + n->values << val; + properties.insert(prop,n); + } + if (objectCache) + objectCache->setValue(prop.toLatin1(), val); + } + QmlListModel *modelCache; ModelObject *objectCache; }; @@ -235,7 +272,7 @@ QmlListModel::~QmlListModel() void QmlListModel::checkRoles() const { - if (_rolesOk) + if (_rolesOk || !_root) return; for (int ii = 0; ii < _root->values.count(); ++ii) { @@ -341,6 +378,232 @@ int QmlListModel::count() const return _root->values.count(); } +/*! + \qmlmethod ListModel::clear() + + Deletes all content from the model. The properties are cleared such that + different properties may be set on subsequent additions. + + \sa append() remove() +*/ +void QmlListModel::clear() +{ + int cleared = count(); + _rolesOk = false; + delete _root; + _root = 0; + roleStrings.clear(); + emit itemsRemoved(0,cleared); +} + +/*! + \qmlmethod ListModel::remove(int index) + + Deletes the content at \a index from the model. + + \sa clear() +*/ +void QmlListModel::remove(int index) +{ + if (_root) { + ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index)); + _root->values.remove(index); + if (node) + delete node; + emit itemsRemoved(index,1); + } +} + +/*! + \qmlmethod ListModel::insert(index,dict) + + Adds a new item to the list model at position \a index, with the + values in \a dict. + + \code + FruitModel.insert(2, {"cost": 5.95, "name":"Pizza"}) + \endcode + + If \a index is not in the list, sufficient empty items are + added to the list. + + \sa set() append() +*/ +void QmlListModel::insert(int index, const QVariantMap& valuemap) +{ + if (!_root) + _root = new ModelNode; + if (index >= _root->values.count()) { + set(index,valuemap); + return; + } + ModelNode *mn = new ModelNode; + for (QVariantMap::const_iterator it=valuemap.begin(); it!=valuemap.end(); ++it) { + addRole(it.key()); + ModelNode *value = new ModelNode; + value->values << it.value(); + mn->properties.insert(it.key(),value); + } + _root->values.insert(index,qVariantFromValue(mn)); + emit itemsInserted(index,1); +} + +/*! + \qmlmethod ListModel::move(from,to,n) + + Moves \a n items \a from one position \a to another. + + The from and to ranges must exist; for example, to move the first 3 items + to the end of the list: + + \code + FruitModel.move(0,FruitModel.count-3,3) + \endcode + + \sa append() +*/ +void QmlListModel::move(int from, int to, int n) +{ + if (from+n > count() || to+n > count() || n==0 || from==to) + return; + if (from > to) { + // Only move forwards - flip if backwards moving + int tfrom = from; + int tto = to; + from = tto; + to = tto+n; + n = tfrom-tto; + } + if (n==1) { + _root->values.move(from,to); + } else { + QList<QVariant> replaced; + int i=0; + QVariantList::const_iterator it=_root->values.begin(); it += from+n; + for (; i<to-from; ++i,++it) + replaced.append(*it); + i=0; + it=_root->values.begin(); it += from; + for (; i<n; ++i,++it) + replaced.append(*it); + QVariantList::const_iterator f=replaced.begin(); + QVariantList::iterator t=_root->values.begin(); t += from; + for (; f != replaced.end(); ++f, ++t) + *t = *f; + } + emit itemsMoved(from,to,n); +} + +/*! + \qmlmethod ListModel::append(dict) + + Adds a new item to the end of the list model, with the + values in \a dict. + + \code + FruitModel.append({"cost": 5.95, "name":"Pizza"}) + \endcode + + \sa set() remove() +*/ +void QmlListModel::append(const QVariantMap& valuemap) +{ + if (!_root) + _root = new ModelNode; + ModelNode *mn = new ModelNode; + for (QVariantMap::const_iterator it=valuemap.begin(); it!=valuemap.end(); ++it) { + addRole(it.key()); + ModelNode *value = new ModelNode; + value->values << it.value(); + mn->properties.insert(it.key(),value); + } + _root->values << qVariantFromValue(mn); + emit itemsInserted(count()-1,1); +} + +/*! + \qmlmethod ListModel::set(index,dict) + + Changes the item at \a index in the list model to the + values in \a dict. + + \code + FruitModel.set(3, {"cost": 5.95, "name":"Pizza"}) + \endcode + + If \a index is not in the list, sufficient empty items are + added to the list. + + \sa append() +*/ +void QmlListModel::set(int index, const QVariantMap& valuemap) +{ + if (!_root) + _root = new ModelNode; + int initialcount = _root->values.count(); + while (index > _root->values.count()) + _root->values.append(qVariantFromValue(new ModelNode)); + if (index == _root->values.count()) + append(valuemap); + else { + ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index)); + QList<int> roles; + for (QVariantMap::const_iterator it=valuemap.begin(); it!=valuemap.end(); ++it) { + node->setProperty(it.key(),it.value()); + int r = roleStrings.indexOf(it.key()); + if (r<0) { + r = roleStrings.count(); + roleStrings << it.key(); + } + roles.append(r); + } + if (initialcount < index) { + emit itemsInserted(initialcount,index-initialcount+1); + } else { + emit itemsChanged(index,1,roles); + } + } +} + +/*! + \qmlmethod ListModel::set(index,property,value) + + Changes the \a property of the item at \a index in the list model to \a value. + + \code + FruitModel.set(3, "cost", 5.95) + \endcode + + If \a index is not in the list, sufficient empty items are + added to the list. + + \sa append() +*/ +void QmlListModel::set(int index, const QString& property, const QVariant& value) +{ + if (!_root) + _root = new ModelNode; + int initialcount = _root->values.count(); + while (index >= _root->values.count()) + _root->values.append(qVariantFromValue(new ModelNode)); + ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index)); + int r = roleStrings.indexOf(property); + if (r<0) { + r = roleStrings.count(); + roleStrings << property; + } + QList<int> roles; + roles.append(r); + + if (node) + node->setProperty(property,value); + if (initialcount < index) + emit itemsInserted(initialcount,index-initialcount+1); + else + emit itemsChanged(index,1,roles); +} + + class QmlListModelParser : public QmlCustomParser { public: @@ -518,7 +781,7 @@ static void dump(ModelNode *node, int ind) for (int ii = 0; ii < node->values.count(); ++ii) { ModelNode *subNode = qvariant_cast<ModelNode *>(node->values.at(ii)); if (subNode) { - qWarning().nospace() << indent << "Sub-node " << ii << ": class " << subNode->className; + qWarning().nospace() << indent << "Sub-node " << ii; dump(subNode, ind + 1); } else { qWarning().nospace() << indent << "Sub-node " << ii << ": " << node->values.at(ii).toString(); diff --git a/src/declarative/util/qmllistmodel.h b/src/declarative/util/qmllistmodel.h index 39edbe4..8bef347 100644 --- a/src/declarative/util/qmllistmodel.h +++ b/src/declarative/util/qmllistmodel.h @@ -72,6 +72,14 @@ public: virtual int count() const; virtual QHash<int,QVariant> data(int index, const QList<int> &roles = (QList<int>())) const; + Q_INVOKABLE void clear(); + Q_INVOKABLE void remove(int index); + Q_INVOKABLE void append(const QVariantMap& valuemap); + Q_INVOKABLE void insert(int index, const QVariantMap& valuemap); + Q_INVOKABLE void set(int index, const QVariantMap& valuemap); + Q_INVOKABLE void set(int index, const QString& property, const QVariant& value); + Q_INVOKABLE void move(int from, int to, int count); + private: QVariant valueForNode(ModelNode *) const; mutable QStringList roleStrings; |