summaryrefslogtreecommitdiffstats
path: root/src/declarative/graphicsitems/qdeclarativepathview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/graphicsitems/qdeclarativepathview.cpp')
-rw-r--r--src/declarative/graphicsitems/qdeclarativepathview.cpp222
1 files changed, 148 insertions, 74 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp
index f1b0213..cc17157 100644
--- a/src/declarative/graphicsitems/qdeclarativepathview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp
@@ -44,7 +44,6 @@
#include <qdeclarativestate_p.h>
#include <qdeclarativeopenmetaobject_p.h>
-
#include <QDebug>
#include <QEvent>
#include <qlistmodelinterface_p.h>
@@ -64,48 +63,31 @@ inline qreal qmlMod(qreal x, qreal y)
return fmod(x, y);
}
+static QDeclarativeOpenMetaObjectType *qPathViewAttachedType = 0;
-class QDeclarativePathViewAttached : public QObject
+QDeclarativePathViewAttached::QDeclarativePathViewAttached(QObject *parent)
+: QObject(parent), m_view(0), m_onPath(false), m_isCurrent(false)
{
- Q_OBJECT
-
- Q_PROPERTY(bool onPath READ isOnPath NOTIFY onPathChanged)
-public:
- QDeclarativePathViewAttached(QObject *parent)
- : QObject(parent), mo(new QDeclarativeOpenMetaObject(this)), onPath(false)
- {
- }
-
- ~QDeclarativePathViewAttached()
- {
- QDeclarativePathView::attachedProperties.remove(parent());
- }
-
- QVariant value(const QByteArray &name) const
- {
- return mo->value(name);
- }
- void setValue(const QByteArray &name, const QVariant &val)
- {
- mo->setValue(name, val);
- }
-
- bool isOnPath() const { return onPath; }
- void setOnPath(bool on) {
- if (on != onPath) {
- onPath = on;
- emit onPathChanged();
- }
+ if (qPathViewAttachedType) {
+ m_metaobject = new QDeclarativeOpenMetaObject(this, qPathViewAttachedType);
+ m_metaobject->setCached(true);
+ } else {
+ m_metaobject = new QDeclarativeOpenMetaObject(this);
}
+}
-Q_SIGNALS:
- void onPathChanged();
-
-private:
- QDeclarativeOpenMetaObject *mo;
- bool onPath;
-};
+QDeclarativePathViewAttached::~QDeclarativePathViewAttached()
+{
+}
+QVariant QDeclarativePathViewAttached::value(const QByteArray &name) const
+{
+ return m_metaobject->value(name);
+}
+void QDeclarativePathViewAttached::setValue(const QByteArray &name, const QVariant &val)
+{
+ m_metaobject->setValue(name, val);
+}
QDeclarativeItem *QDeclarativePathViewPrivate::getItem(int modelIndex)
{
@@ -113,8 +95,20 @@ QDeclarativeItem *QDeclarativePathViewPrivate::getItem(int modelIndex)
requestedIndex = modelIndex;
QDeclarativeItem *item = model->item(modelIndex, false);
if (item) {
- if (QObject *obj = QDeclarativePathView::qmlAttachedProperties(item))
- static_cast<QDeclarativePathViewAttached *>(obj)->setOnPath(true);
+ if (!attType) {
+ // pre-create one metatype to share with all attached objects
+ attType = new QDeclarativeOpenMetaObjectType(&QDeclarativePathViewAttached::staticMetaObject, qmlEngine(q));
+ foreach(const QString &attr, path->attributes()) {
+ attType->createProperty(attr.toUtf8());
+ }
+ }
+ qPathViewAttachedType = attType;
+ QDeclarativePathViewAttached *att = static_cast<QDeclarativePathViewAttached *>(qmlAttachedPropertiesObject<QDeclarativePathView>(item));
+ qPathViewAttachedType = 0;
+ if (att) {
+ att->m_view = q;
+ att->setOnPath(true);
+ }
item->setParentItem(q);
}
requestedIndex = -1;
@@ -125,14 +119,26 @@ void QDeclarativePathViewPrivate::releaseItem(QDeclarativeItem *item)
{
if (!item || !model)
return;
- if (QObject *obj = QDeclarativePathView::qmlAttachedProperties(item))
- static_cast<QDeclarativePathViewAttached *>(obj)->setOnPath(false);
- if (model->release(item) == 0) {
- if (QObject *obj = QDeclarativePathView::qmlAttachedProperties(item))
- static_cast<QDeclarativePathViewAttached *>(obj)->setOnPath(false);
+ if (QDeclarativePathViewAttached *att = attached(item))
+ att->setOnPath(false);
+ model->release(item);
+}
+
+QDeclarativePathViewAttached *QDeclarativePathViewPrivate::attached(QDeclarativeItem *item)
+{
+ return static_cast<QDeclarativePathViewAttached *>(qmlAttachedPropertiesObject<QDeclarativePathView>(item, false));
+}
+
+void QDeclarativePathViewPrivate::clear()
+{
+ for (int i=0; i<items.count(); i++){
+ QDeclarativeItem *p = items[i];
+ releaseItem(p);
}
+ items.clear();
}
+
/*!
\qmlclass PathView QDeclarativePathView
\since 4.7
@@ -147,6 +153,11 @@ void QDeclarativePathViewPrivate::releaseItem(QDeclarativeItem *item)
\image pathview.gif
+ Note that views do not enable \e clip automatically. If the view
+ is not clipped by another item or the screen, it will be necessary
+ to set \e {clip: true} in order to have the out of view items clipped
+ nicely.
+
\sa Path
*/
@@ -160,6 +171,9 @@ QDeclarativePathView::QDeclarativePathView(QDeclarativeItem *parent)
QDeclarativePathView::~QDeclarativePathView()
{
Q_D(QDeclarativePathView);
+ d->clear();
+ if (d->attType)
+ d->attType->release();
if (d->ownModel)
delete d->model;
}
@@ -185,6 +199,15 @@ QDeclarativePathView::~QDeclarativePathView()
*/
/*!
+ \qmlattachedproperty bool PathView::isCurrentItem
+ This attached property is true if this delegate is the current item; otherwise false.
+
+ It is attached to each instance of the delegate.
+
+ This property may be used to adjust the appearance of the current item.
+*/
+
+/*!
\qmlproperty model PathView::model
This property holds the model providing data for the view.
@@ -203,6 +226,9 @@ QVariant QDeclarativePathView::model() const
void QDeclarativePathView::setModel(const QVariant &model)
{
Q_D(QDeclarativePathView);
+ if (d->modelVariant == model)
+ return;
+
if (d->model) {
disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
@@ -242,6 +268,7 @@ void QDeclarativePathView::setModel(const QVariant &model)
d->pathOffset = 0;
d->regenerate();
d->fixOffset();
+ emit modelChanged();
}
/*!
@@ -269,9 +296,19 @@ QDeclarativePath *QDeclarativePathView::path() const
void QDeclarativePathView::setPath(QDeclarativePath *path)
{
Q_D(QDeclarativePathView);
+ if (d->path == path)
+ return;
+ if (d->path)
+ disconnect(d->path, SIGNAL(changed()), this, SLOT(refill()));
d->path = path;
connect(d->path, SIGNAL(changed()), this, SLOT(refill()));
+ d->clear();
+ if (d->attType) {
+ d->attType->release();
+ d->attType = 0;
+ }
d->regenerate();
+ emit pathChanged();
}
/*!
@@ -290,12 +327,25 @@ void QDeclarativePathView::setCurrentIndex(int idx)
if (d->model && d->model->count())
idx = qAbs(idx % d->model->count());
if (d->model && idx != d->currentIndex) {
+ if (d->model->count()) {
+ int itemIndex = (d->currentIndex - d->firstIndex + d->model->count()) % d->model->count();
+ if (itemIndex < d->items.count()) {
+ if (QDeclarativeItem *item = d->items.at(d->currentIndex)) {
+ if (QDeclarativePathViewAttached *att = d->attached(item))
+ att->setIsCurrentItem(false);
+ }
+ }
+ }
d->currentIndex = idx;
if (d->model->count()) {
d->snapToCurrent();
int itemIndex = (idx - d->firstIndex + d->model->count()) % d->model->count();
- if (itemIndex < d->items.count())
- d->items.at(itemIndex)->setFocus(true);
+ if (itemIndex < d->items.count()) {
+ QDeclarativeItem *item = d->items.at(itemIndex);
+ item->setFocus(true);
+ if (QDeclarativePathViewAttached *att = d->attached(item))
+ att->setIsCurrentItem(true);
+ }
}
emit currentIndexChanged();
}
@@ -333,7 +383,7 @@ void QDeclarativePathViewPrivate::setOffset(qreal o)
/*!
\qmlproperty real PathView::snapPosition
- This property determines the position (0-100) the nearest item will snap to.
+ This property determines the position (0.0-1.0) the nearest item will snap to.
*/
qreal QDeclarativePathView::snapPosition() const
{
@@ -344,8 +394,12 @@ qreal QDeclarativePathView::snapPosition() const
void QDeclarativePathView::setSnapPosition(qreal pos)
{
Q_D(QDeclarativePathView);
- d->snapPos = pos/100;
+ qreal normalizedPos = pos - int(pos);
+ if (qFuzzyCompare(normalizedPos, d->snapPos))
+ return;
+ d->snapPos = normalizedPos;
d->fixOffset();
+ emit snapPositionChanged();
}
/*!
@@ -365,7 +419,10 @@ qreal QDeclarativePathView::dragMargin() const
void QDeclarativePathView::setDragMargin(qreal dragMargin)
{
Q_D(QDeclarativePathView);
+ if (d->dragMargin == dragMargin)
+ return;
d->dragMargin = dragMargin;
+ emit dragMarginChanged();
}
/*!
@@ -392,16 +449,19 @@ QDeclarativeComponent *QDeclarativePathView::delegate() const
return 0;
}
-void QDeclarativePathView::setDelegate(QDeclarativeComponent *c)
+void QDeclarativePathView::setDelegate(QDeclarativeComponent *delegate)
{
Q_D(QDeclarativePathView);
+ if (delegate == this->delegate())
+ return;
if (!d->ownModel) {
d->model = new QDeclarativeVisualDataModel(qmlContext(this));
d->ownModel = true;
}
if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model)) {
- dataModel->setDelegate(c);
+ dataModel->setDelegate(delegate);
d->regenerate();
+ emit delegateChanged();
}
}
@@ -422,6 +482,7 @@ void QDeclarativePathView::setPathItemCount(int i)
return;
d->pathItems = i;
d->regenerate();
+ pathItemCountChanged();
}
QPointF QDeclarativePathViewPrivate::pointNear(const QPointF &point, qreal *nearPercent) const
@@ -631,11 +692,7 @@ void QDeclarativePathViewPrivate::regenerate()
if (!q->isComponentComplete())
return;
- for (int i=0; i<items.count(); i++){
- QDeclarativeItem *p = items[i];
- releaseItem(p);
- }
- items.clear();
+ clear();
if (!isValid())
return;
@@ -655,18 +712,25 @@ void QDeclarativePathViewPrivate::regenerate()
}
items.append(item);
item->setZValue(i);
+ qreal percent = i * (100. / numItems) + _offset;
+ percent = qAbs(qmlMod(percent, qreal(100.0))/100.0);
+ updateItem(item, percent);
model->completeItem();
- if (currentIndex == index)
+ if (currentIndex == index) {
item->setFocus(true);
+ if (QDeclarativePathViewAttached *att = attached(item))
+ att->setIsCurrentItem(true);
+ }
}
- q->refill();
+ if (pathItems != -1)
+ q->refill();
}
void QDeclarativePathViewPrivate::updateItem(QDeclarativeItem *item, qreal percent)
{
- if (QObject *obj = QDeclarativePathView::qmlAttachedProperties(item)) {
+ if (QDeclarativePathViewAttached *att = attached(item)) {
foreach(const QString &attr, path->attributes())
- static_cast<QDeclarativePathViewAttached *>(obj)->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
+ att->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
}
QPointF pf = path->pointAt(percent);
item->setX(pf.x() - item->width()*item->scale()/2);
@@ -717,8 +781,11 @@ void QDeclarativePathView::refill()
QDeclarativeItem *item = d->getItem(index);
item->setZValue(wrapIndex);
d->model->completeItem();
- if (d->currentIndex == index)
+ if (d->currentIndex == index) {
item->setFocus(true);
+ if (QDeclarativePathViewAttached *att = d->attached(item))
+ att->setIsCurrentItem(true);
+ }
d->items << item;
d->pathOffset++;
d->pathOffset=d->pathOffset % d->items.count();
@@ -734,8 +801,11 @@ void QDeclarativePathView::refill()
QDeclarativeItem *item = d->getItem(d->firstIndex);
item->setZValue(d->firstIndex);
d->model->completeItem();
- if (d->currentIndex == d->firstIndex)
+ if (d->currentIndex == d->firstIndex) {
item->setFocus(true);
+ if (QDeclarativePathViewAttached *att = d->attached(item))
+ att->setIsCurrentItem(true);
+ }
d->items.prepend(item);
d->pathOffset--;
if (d->pathOffset < 0)
@@ -891,10 +961,21 @@ void QDeclarativePathViewPrivate::updateCurrent()
return;
int idx = calcCurrentIndex();
if (model && idx != currentIndex) {
+ int itemIndex = (currentIndex - firstIndex + model->count()) % model->count();
+ if (itemIndex < items.count()) {
+ if (QDeclarativeItem *item = items.at(itemIndex)) {
+ if (QDeclarativePathViewAttached *att = attached(item))
+ att->setIsCurrentItem(false);
+ }
+ }
currentIndex = idx;
- int itemIndex = (idx - firstIndex + model->count()) % model->count();
- if (itemIndex < items.count())
- items.at(itemIndex)->setFocus(true);
+ itemIndex = (idx - firstIndex + model->count()) % model->count();
+ if (itemIndex < items.count()) {
+ QDeclarativeItem *item = items.at(itemIndex);
+ item->setFocus(true);
+ if (QDeclarativePathViewAttached *att = attached(item))
+ att->setIsCurrentItem(true);
+ }
emit q->currentIndexChanged();
}
}
@@ -975,17 +1056,10 @@ void QDeclarativePathViewPrivate::snapToCurrent()
}
}
-QHash<QObject*, QObject*> QDeclarativePathView::attachedProperties;
-QObject *QDeclarativePathView::qmlAttachedProperties(QObject *obj)
+QDeclarativePathViewAttached *QDeclarativePathView::qmlAttachedProperties(QObject *obj)
{
- QObject *rv = attachedProperties.value(obj);
- if (!rv) {
- rv = new QDeclarativePathViewAttached(obj);
- attachedProperties.insert(obj, rv);
- }
- return rv;
+ return new QDeclarativePathViewAttached(obj);
}
QT_END_NAMESPACE
-#include <qdeclarativepathview.moc>