src/declarative/graphicsitems/qdeclarativepathview.cpp
changeset 37 758a864f9613
parent 33 3e2da88830cd
equal deleted inserted replaced
36:ef0373b55136 37:758a864f9613
    65 }
    65 }
    66 
    66 
    67 static QDeclarativeOpenMetaObjectType *qPathViewAttachedType = 0;
    67 static QDeclarativeOpenMetaObjectType *qPathViewAttachedType = 0;
    68 
    68 
    69 QDeclarativePathViewAttached::QDeclarativePathViewAttached(QObject *parent)
    69 QDeclarativePathViewAttached::QDeclarativePathViewAttached(QObject *parent)
    70 : QObject(parent), m_view(0), m_onPath(false), m_isCurrent(false)
    70 : QObject(parent), m_percent(-1), m_view(0), m_onPath(false), m_isCurrent(false)
    71 {
    71 {
    72     if (qPathViewAttachedType) {
    72     if (qPathViewAttachedType) {
    73         m_metaobject = new QDeclarativeOpenMetaObject(this, qPathViewAttachedType);
    73         m_metaobject = new QDeclarativeOpenMetaObject(this, qPathViewAttachedType);
    74         m_metaobject->setCached(true);
    74         m_metaobject->setCached(true);
    75     } else {
    75     } else {
    86     return m_metaobject->value(name);
    86     return m_metaobject->value(name);
    87 }
    87 }
    88 void QDeclarativePathViewAttached::setValue(const QByteArray &name, const QVariant &val)
    88 void QDeclarativePathViewAttached::setValue(const QByteArray &name, const QVariant &val)
    89 {
    89 {
    90     m_metaobject->setValue(name, val);
    90     m_metaobject->setValue(name, val);
       
    91 }
       
    92 
       
    93 
       
    94 void QDeclarativePathViewPrivate::init()
       
    95 {
       
    96     Q_Q(QDeclarativePathView);
       
    97     offset = 0;
       
    98     q->setAcceptedMouseButtons(Qt::LeftButton);
       
    99     q->setFlag(QGraphicsItem::ItemIsFocusScope);
       
   100     q->setFiltersChildEvents(true);
       
   101     q->connect(&tl, SIGNAL(updated()), q, SLOT(ticked()));
       
   102     lastPosTime.invalidate();
       
   103     static int timelineCompletedIdx = -1;
       
   104     static int movementEndingIdx = -1;
       
   105     if (timelineCompletedIdx == -1) {
       
   106         timelineCompletedIdx = QDeclarativeTimeLine::staticMetaObject.indexOfSignal("completed()");
       
   107         movementEndingIdx = QDeclarativePathView::staticMetaObject.indexOfSlot("movementEnding()");
       
   108     }
       
   109     QMetaObject::connect(&tl, timelineCompletedIdx,
       
   110                          q, movementEndingIdx, Qt::DirectConnection);
    91 }
   111 }
    92 
   112 
    93 QDeclarativeItem *QDeclarativePathViewPrivate::getItem(int modelIndex)
   113 QDeclarativeItem *QDeclarativePathViewPrivate::getItem(int modelIndex)
    94 {
   114 {
    95     Q_Q(QDeclarativePathView);
   115     Q_Q(QDeclarativePathView);
   142     items.clear();
   162     items.clear();
   143 }
   163 }
   144 
   164 
   145 void QDeclarativePathViewPrivate::updateMappedRange()
   165 void QDeclarativePathViewPrivate::updateMappedRange()
   146 {
   166 {
   147     if (model && pathItems != -1 && pathItems < model->count())
   167     if (model && pathItems != -1 && pathItems < modelCount)
   148         mappedRange = qreal(pathItems)/model->count();
   168         mappedRange = qreal(pathItems)/modelCount;
   149     else
   169     else
   150         mappedRange = 1.0;
   170         mappedRange = 1.0;
   151 }
   171 }
   152 
   172 
   153 qreal QDeclarativePathViewPrivate::positionOfIndex(qreal index) const
   173 qreal QDeclarativePathViewPrivate::positionOfIndex(qreal index) const
   154 {
   174 {
   155     qreal pos = -1.0;
   175     qreal pos = -1.0;
   156 
   176 
   157     if (model && index >= 0 && index < model->count()) {
   177     if (model && index >= 0 && index < modelCount) {
   158         qreal start = 0.0;
   178         qreal start = 0.0;
   159         if (haveHighlightRange && highlightRangeMode != QDeclarativePathView::NoHighlightRange)
   179         if (haveHighlightRange && highlightRangeMode != QDeclarativePathView::NoHighlightRange)
   160             start = highlightRangeStart;
   180             start = highlightRangeStart;
   161         qreal globalPos = index + offset;
   181         qreal globalPos = index + offset;
   162         globalPos = qmlMod(globalPos, qreal(model->count())) / model->count();
   182         globalPos = qmlMod(globalPos, qreal(modelCount)) / modelCount;
   163         if (pathItems != -1 && pathItems < model->count()) {
   183         if (pathItems != -1 && pathItems < modelCount) {
   164             globalPos += start * mappedRange;
   184             globalPos += start * mappedRange;
   165             globalPos = qmlMod(globalPos, 1.0);
   185             globalPos = qmlMod(globalPos, 1.0);
   166             if (globalPos < mappedRange)
   186             if (globalPos < mappedRange)
   167                 pos = globalPos / mappedRange;
   187                 pos = globalPos / mappedRange;
   168         } else {
   188         } else {
   220         if (haveHighlightRange && highlightRangeMode == QDeclarativePathView::StrictlyEnforceRange) {
   240         if (haveHighlightRange && highlightRangeMode == QDeclarativePathView::StrictlyEnforceRange) {
   221             updateItem(highlightItem, highlightRangeStart);
   241             updateItem(highlightItem, highlightRangeStart);
   222         } else {
   242         } else {
   223             qreal target = currentIndex;
   243             qreal target = currentIndex;
   224 
   244 
       
   245             offsetAdj = 0.0;
   225             tl.reset(moveHighlight);
   246             tl.reset(moveHighlight);
   226             moveHighlight.setValue(highlightPosition);
   247             moveHighlight.setValue(highlightPosition);
   227 
   248 
   228             const int duration = highlightMoveDuration;
   249             const int duration = highlightMoveDuration;
   229 
   250 
   230             if (target - highlightPosition > model->count()/2) {
   251             if (target - highlightPosition > modelCount/2) {
   231                 highlightUp = false;
   252                 highlightUp = false;
   232                 qreal distance = model->count() - target + highlightPosition;
   253                 qreal distance = modelCount - target + highlightPosition;
   233                 tl.move(moveHighlight, 0.0, QEasingCurve(QEasingCurve::InQuad), int(duration * highlightPosition / distance));
   254                 tl.move(moveHighlight, 0.0, QEasingCurve(QEasingCurve::InQuad), int(duration * highlightPosition / distance));
   234                 tl.set(moveHighlight, model->count()-0.01);
   255                 tl.set(moveHighlight, modelCount-0.01);
   235                 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad), int(duration * (model->count()-target) / distance));
   256                 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad), int(duration * (modelCount-target) / distance));
   236             } else if (target - highlightPosition <= -model->count()/2) {
   257             } else if (target - highlightPosition <= -modelCount/2) {
   237                 highlightUp = true;
   258                 highlightUp = true;
   238                 qreal distance = model->count() - highlightPosition + target;
   259                 qreal distance = modelCount - highlightPosition + target;
   239                 tl.move(moveHighlight, model->count()-0.01, QEasingCurve(QEasingCurve::InQuad), int(duration * (model->count()-highlightPosition) / distance));
   260                 tl.move(moveHighlight, modelCount-0.01, QEasingCurve(QEasingCurve::InQuad), int(duration * (modelCount-highlightPosition) / distance));
   240                 tl.set(moveHighlight, 0.0);
   261                 tl.set(moveHighlight, 0.0);
   241                 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad), int(duration * target / distance));
   262                 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::OutQuad), int(duration * target / distance));
   242             } else {
   263             } else {
   243                 highlightUp = highlightPosition - target < 0;
   264                 highlightUp = highlightPosition - target < 0;
   244                 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::InOutQuad), duration);
   265                 tl.move(moveHighlight, target, QEasingCurve(QEasingCurve::InOutQuad), duration);
   255         if (haveHighlightRange && highlightRangeMode != QDeclarativePathView::NoHighlightRange) {
   276         if (haveHighlightRange && highlightRangeMode != QDeclarativePathView::NoHighlightRange) {
   256             start = highlightRangeStart;
   277             start = highlightRangeStart;
   257             end = highlightRangeEnd;
   278             end = highlightRangeEnd;
   258         }
   279         }
   259 
   280 
   260         qreal range = qreal(model->count());
   281         qreal range = qreal(modelCount);
   261         // calc normalized position of highlight relative to offset
   282         // calc normalized position of highlight relative to offset
   262         qreal relativeHighlight = qmlMod(pos + offset, range) / range;
   283         qreal relativeHighlight = qmlMod(pos + offset, range) / range;
   263 
   284 
   264         if (!highlightUp && relativeHighlight > end * mappedRange) {
   285         if (!highlightUp && relativeHighlight > end * mappedRange) {
   265             qreal diff = 1.0 - relativeHighlight;
   286             qreal diff = 1.0 - relativeHighlight;
   278 }
   299 }
   279 
   300 
   280 void QDeclarativePathViewPrivate::updateItem(QDeclarativeItem *item, qreal percent)
   301 void QDeclarativePathViewPrivate::updateItem(QDeclarativeItem *item, qreal percent)
   281 {
   302 {
   282     if (QDeclarativePathViewAttached *att = attached(item)) {
   303     if (QDeclarativePathViewAttached *att = attached(item)) {
       
   304         if (qFuzzyCompare(att->m_percent, percent))
       
   305             return;
       
   306         att->m_percent = percent;
   283         foreach(const QString &attr, path->attributes())
   307         foreach(const QString &attr, path->attributes())
   284             att->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
   308             att->setValue(attr.toUtf8(), path->attributeAt(attr, percent));
   285     }
   309     }
   286     QPointF pf = path->pointAt(percent);
   310     QPointF pf = path->pointAt(percent);
   287     item->setX(qRound(pf.x() - item->width()/2));
   311     item->setX(qRound(pf.x() - item->width()/2));
   304     q->refill();
   328     q->refill();
   305 }
   329 }
   306 
   330 
   307 /*!
   331 /*!
   308     \qmlclass PathView QDeclarativePathView
   332     \qmlclass PathView QDeclarativePathView
       
   333     \ingroup qml-view-elements
   309     \since 4.7
   334     \since 4.7
   310     \brief The PathView element lays out model-provided items on a path.
   335     \brief The PathView element lays out model-provided items on a path.
   311     \inherits Item
   336     \inherits Item
   312 
   337 
   313     A PathView displays data from models created from built-in QML elements like ListModel
   338     A PathView displays data from models created from built-in QML elements like ListModel
   314     and XmlListModel, or custom model classes defined in C++ that inherit from
   339     and XmlListModel, or custom model classes defined in C++ that inherit from
   315     QAbstractListModel.
   340     QAbstractListModel.
   316 
   341 
   317     A ListView has a \l model, which defines the data to be displayed, and
   342     The view has a \l model, which defines the data to be displayed, and
   318     a \l delegate, which defines how the data should be displayed.  
   343     a \l delegate, which defines how the data should be displayed.  
   319     The \l delegate is instantiated for each item on the \l path.
   344     The \l delegate is instantiated for each item on the \l path.
   320     The items may be flicked to move them along the path.
   345     The items may be flicked to move them along the path.
   321 
   346 
   322     For example, if there is a simple list model defined in a file \c ContactModel.qml like this:
   347     For example, if there is a simple list model defined in a file \c ContactModel.qml like this:
   330     \image pathview.gif
   355     \image pathview.gif
   331 
   356 
   332     (Note the above example uses PathAttribute to scale and modify the
   357     (Note the above example uses PathAttribute to scale and modify the
   333     opacity of the items as they rotate. This additional code can be seen in the
   358     opacity of the items as they rotate. This additional code can be seen in the
   334     PathAttribute documentation.)
   359     PathAttribute documentation.)
       
   360 
       
   361     The \c focus can be set to \c true to enable keyboard navigation.
       
   362     The path view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
   335 
   363 
   336     Delegates are instantiated as needed and may be destroyed at any time.
   364     Delegates are instantiated as needed and may be destroyed at any time.
   337     State should \e never be stored in a delegate.
   365     State should \e never be stored in a delegate.
   338 
   366 
   339     \bold Note that views do not enable \e clip automatically.  If the view
   367     \bold Note that views do not enable \e clip automatically.  If the view
   340     is not clipped by another item or the screen, it will be necessary
   368     is not clipped by another item or the screen, it will be necessary
   341     to set \e {clip: true} in order to have the out of view items clipped
   369     to set \e {clip: true} in order to have the out of view items clipped
   342     nicely.
   370     nicely.
   343 
   371 
   344     \sa Path
   372     \sa Path, {declarative/modelviews/pathview}{PathView example}
   345 */
   373 */
   346 
   374 
   347 QDeclarativePathView::QDeclarativePathView(QDeclarativeItem *parent)
   375 QDeclarativePathView::QDeclarativePathView(QDeclarativeItem *parent)
   348   : QDeclarativeItem(*(new QDeclarativePathViewPrivate), parent)
   376   : QDeclarativeItem(*(new QDeclarativePathViewPrivate), parent)
   349 {
   377 {
   401     \qmlproperty model PathView::model
   429     \qmlproperty model PathView::model
   402     This property holds the model providing data for the view.
   430     This property holds the model providing data for the view.
   403 
   431 
   404     The model provides a set of data that is used to create the items for the view.
   432     The model provides a set of data that is used to create the items for the view.
   405     For large or dynamic datasets the model is usually provided by a C++ model object.
   433     For large or dynamic datasets the model is usually provided by a C++ model object.
   406     Models can also be created directly in XML, using the ListModel element.
   434     Models can also be created directly in QML, using the ListModel element.
   407 
   435 
   408     \sa {qmlmodels}{Data Models}
   436     \sa {qmlmodels}{Data Models}
   409 */
   437 */
   410 QVariant QDeclarativePathView::model() const
   438 QVariant QDeclarativePathView::model() const
   411 {
   439 {
   447             d->ownModel = true;
   475             d->ownModel = true;
   448         }
   476         }
   449         if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
   477         if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
   450             dataModel->setModel(model);
   478             dataModel->setModel(model);
   451     }
   479     }
       
   480     d->modelCount = 0;
   452     if (d->model) {
   481     if (d->model) {
   453         connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
   482         connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
   454         connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
   483         connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
   455         connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
   484         connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
   456         connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
   485         connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
   457         connect(d->model, SIGNAL(createdItem(int, QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
   486         connect(d->model, SIGNAL(createdItem(int, QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
   458     }
   487         d->modelCount = d->model->count();
   459     d->offset = qmlMod(d->offset, qreal(d->model->count()));
   488         if (d->model->count())
   460     if (d->offset < 0)
   489             d->offset = qmlMod(d->offset, qreal(d->model->count()));
   461         d->offset = d->model->count() + d->offset;
   490         if (d->offset < 0)
       
   491             d->offset = d->model->count() + d->offset;
       
   492 }
   462     d->regenerate();
   493     d->regenerate();
   463     d->fixOffset();
   494     d->fixOffset();
   464     emit countChanged();
   495     emit countChanged();
   465     emit modelChanged();
   496     emit modelChanged();
   466 }
   497 }
   470     This property holds the number of items in the model.
   501     This property holds the number of items in the model.
   471 */
   502 */
   472 int QDeclarativePathView::count() const
   503 int QDeclarativePathView::count() const
   473 {
   504 {
   474     Q_D(const QDeclarativePathView);
   505     Q_D(const QDeclarativePathView);
   475     return d->model ? d->model->count() : 0;
   506     return d->model ? d->modelCount : 0;
   476 }
   507 }
   477 
   508 
   478 /*!
   509 /*!
   479     \qmlproperty Path PathView::path
   510     \qmlproperty Path PathView::path
   480     \default
   511     \default
   518 }
   549 }
   519 
   550 
   520 void QDeclarativePathView::setCurrentIndex(int idx)
   551 void QDeclarativePathView::setCurrentIndex(int idx)
   521 {
   552 {
   522     Q_D(QDeclarativePathView);
   553     Q_D(QDeclarativePathView);
   523     if (d->model && d->model->count())
   554     if (d->model && d->modelCount)
   524         idx = qAbs(idx % d->model->count());
   555         idx = qAbs(idx % d->modelCount);
   525     if (d->model && idx != d->currentIndex) {
   556     if (d->model && idx != d->currentIndex) {
   526         if (d->model->count()) {
   557         if (d->modelCount) {
   527             int itemIndex = (d->currentIndex - d->firstIndex + d->model->count()) % d->model->count();
   558             int itemIndex = (d->currentIndex - d->firstIndex + d->modelCount) % d->modelCount;
   528             if (itemIndex < d->items.count()) {
   559             if (itemIndex < d->items.count()) {
   529                 if (QDeclarativeItem *item = d->items.at(itemIndex)) {
   560                 if (QDeclarativeItem *item = d->items.at(itemIndex)) {
   530                     if (QDeclarativePathViewAttached *att = d->attached(item))
   561                     if (QDeclarativePathViewAttached *att = d->attached(item))
   531                         att->setIsCurrentItem(false);
   562                         att->setIsCurrentItem(false);
   532                 }
   563                 }
   533             }
   564             }
   534         }
   565         }
   535         d->currentItem = 0;
   566         d->currentItem = 0;
   536         d->moveReason = QDeclarativePathViewPrivate::SetIndex;
   567         d->moveReason = QDeclarativePathViewPrivate::SetIndex;
   537         d->currentIndex = idx;
   568         d->currentIndex = idx;
   538         if (d->model->count()) {
   569         if (d->modelCount) {
   539             if (d->haveHighlightRange && d->highlightRangeMode == QDeclarativePathView::StrictlyEnforceRange)
   570             if (d->haveHighlightRange && d->highlightRangeMode == QDeclarativePathView::StrictlyEnforceRange)
   540                 d->snapToCurrent();
   571                 d->snapToCurrent();
   541             int itemIndex = (idx - d->firstIndex + d->model->count()) % d->model->count();
   572             int itemIndex = (idx - d->firstIndex + d->modelCount) % d->modelCount;
   542             if (itemIndex < d->items.count()) {
   573             if (itemIndex < d->items.count()) {
   543                 d->currentItem = d->items.at(itemIndex);
   574                 d->currentItem = d->items.at(itemIndex);
   544                 d->currentItem->setFocus(true);
   575                 d->currentItem->setFocus(true);
   545                 if (QDeclarativePathViewAttached *att = d->attached(d->currentItem))
   576                 if (QDeclarativePathViewAttached *att = d->attached(d->currentItem))
   546                     att->setIsCurrentItem(true);
   577                     att->setIsCurrentItem(true);
   573     \bold Note: methods should only be called after the Component has completed.
   604     \bold Note: methods should only be called after the Component has completed.
   574 */
   605 */
   575 void QDeclarativePathView::decrementCurrentIndex()
   606 void QDeclarativePathView::decrementCurrentIndex()
   576 {
   607 {
   577     Q_D(QDeclarativePathView);
   608     Q_D(QDeclarativePathView);
   578     if (d->model && d->model->count()) {
   609     if (d->model && d->modelCount) {
   579         int idx = currentIndex()-1;
   610         int idx = currentIndex()-1;
   580         if (idx < 0)
   611         if (idx < 0)
   581             idx = d->model->count() - 1;
   612             idx = d->modelCount - 1;
   582         setCurrentIndex(idx);
   613         setCurrentIndex(idx);
   583     }
   614     }
   584 }
   615 }
   585 
   616 
   586 /*!
   617 /*!
   605 void QDeclarativePathViewPrivate::setOffset(qreal o)
   636 void QDeclarativePathViewPrivate::setOffset(qreal o)
   606 {
   637 {
   607     Q_Q(QDeclarativePathView);
   638     Q_Q(QDeclarativePathView);
   608     if (offset != o) {
   639     if (offset != o) {
   609         if (isValid() && q->isComponentComplete()) {
   640         if (isValid() && q->isComponentComplete()) {
   610             offset = qmlMod(o, qreal(model->count()));
   641             offset = qmlMod(o, qreal(modelCount));
   611             if (offset < 0)
   642             if (offset < 0)
   612                 offset += qreal(model->count());
   643                 offset += qreal(modelCount);
   613             q->refill();
   644             q->refill();
   614         } else {
   645         } else {
   615             offset = o;
   646             offset = o;
   616         }
   647         }
   617         emit q->offsetChanged();
   648         emit q->offsetChanged();
   618     }
   649     }
   619 }
   650 }
   620 
   651 
       
   652 void QDeclarativePathViewPrivate::setAdjustedOffset(qreal o)
       
   653 {
       
   654     setOffset(o+offsetAdj);
       
   655 }
       
   656 
   621 /*!
   657 /*!
   622     \qmlproperty Component PathView::highlight
   658     \qmlproperty Component PathView::highlight
   623     This property holds the component to use as the highlight.
   659     This property holds the component to use as the highlight.
   624 
   660 
   625     An instance of the highlight component will be created for each view.
   661     An instance of the highlight component will be created for each view.
   626     The geometry of the resultant component instance will be managed by the view
   662     The geometry of the resultant component instance will be managed by the view
   627     so as to stay with the current item.
   663     so as to stay with the current item.
   628 
   664 
   629     The below example demonstrates how to make a simple highlight.  Note the use
   665     The below example demonstrates how to make a simple highlight.  Note the use
   630     of the PathView.onPath property to ensure that the highlight is hidden
   666     of the \l{PathView::onPath}{PathView.onPath} attached property to ensure that
   631     when flicked off of the path.
   667     the highlight is hidden when flicked away from the path.
   632 
   668 
   633     \code
   669     \code
   634     Component {
   670     Component {
   635         Rectangle {
   671         Rectangle {
   636             visible: PathView.onPath
   672             visible: PathView.onPath
   677     \qmlproperty real PathView::preferredHighlightEnd
   713     \qmlproperty real PathView::preferredHighlightEnd
   678     \qmlproperty enumeration PathView::highlightRangeMode
   714     \qmlproperty enumeration PathView::highlightRangeMode
   679 
   715 
   680     These properties set the preferred range of the highlight (current item)
   716     These properties set the preferred range of the highlight (current item)
   681     within the view.  The preferred values must be in the range 0.0-1.0.
   717     within the view.  The preferred values must be in the range 0.0-1.0.
       
   718 
       
   719     If highlightRangeMode is set to \e PathView.NoHighlightRange
   682 
   720 
   683     If highlightRangeMode is set to \e PathView.ApplyRange the view will
   721     If highlightRangeMode is set to \e PathView.ApplyRange the view will
   684     attempt to maintain the highlight within the range, however
   722     attempt to maintain the highlight within the range, however
   685     the highlight can move outside of the range at the ends of the path
   723     the highlight can move outside of the range at the ends of the path
   686     or due to a mouse interaction.
   724     or due to a mouse interaction.
   844         if (!interactive)
   882         if (!interactive)
   845             d->tl.clear();
   883             d->tl.clear();
   846         emit interactiveChanged();
   884         emit interactiveChanged();
   847     }
   885     }
   848 }
   886 }
       
   887 
       
   888 /*!
       
   889     \qmlproperty bool PathView::moving
       
   890 
       
   891     This property holds whether the view is currently moving
       
   892     due to the user either dragging or flicking the view.
       
   893 */
       
   894 bool QDeclarativePathView::isMoving() const
       
   895 {
       
   896     Q_D(const QDeclarativePathView);
       
   897     return d->moving;
       
   898 }
       
   899 
       
   900 /*!
       
   901     \qmlproperty bool PathView::flicking
       
   902 
       
   903     This property holds whether the view is currently moving
       
   904     due to the user flicking the view.
       
   905 */
       
   906 bool QDeclarativePathView::isFlicking() const
       
   907 {
       
   908     Q_D(const QDeclarativePathView);
       
   909     return d->flicking;
       
   910 }
       
   911 
       
   912 /*!
       
   913     \qmlsignal PathView::onMovementStarted()
       
   914 
       
   915     This handler is called when the view begins moving due to user
       
   916     interaction.
       
   917 */
       
   918 
       
   919 /*!
       
   920     \qmlsignal PathView::onMovementEnded()
       
   921 
       
   922     This handler is called when the view stops moving due to user
       
   923     interaction.  If a flick was generated, this handler will
       
   924     be triggered once the flick stops.  If a flick was not
       
   925     generated, the handler will be triggered when the
       
   926     user stops dragging - i.e. a mouse or touch release.
       
   927 */
       
   928 
       
   929 /*!
       
   930     \qmlsignal PathView::onFlickStarted()
       
   931 
       
   932     This handler is called when the view is flicked.  A flick
       
   933     starts from the point that the mouse or touch is released,
       
   934     while still in motion.
       
   935 */
       
   936 
       
   937 /*!
       
   938     \qmlsignal PathView::onFlickEnded()
       
   939 
       
   940     This handler is called when the view stops moving due to a flick.
       
   941 */
   849 
   942 
   850 /*!
   943 /*!
   851     \qmlproperty Component PathView::delegate
   944     \qmlproperty Component PathView::delegate
   852 
   945 
   853     The delegate provides a template defining each item instantiated by the view.
   946     The delegate provides a template defining each item instantiated by the view.
   962         qreal distance = qAbs(event->pos().x() - d->startPoint.x()) + qAbs(event->pos().y() - d->startPoint.y());
  1055         qreal distance = qAbs(event->pos().x() - d->startPoint.x()) + qAbs(event->pos().y() - d->startPoint.y());
   963         if (distance > d->dragMargin)
  1056         if (distance > d->dragMargin)
   964             return;
  1057             return;
   965     }
  1058     }
   966 
  1059 
   967     d->stealMouse = false;
  1060     if (d->tl.isActive() && d->flicking)
       
  1061         d->stealMouse = true; // If we've been flicked then steal the click.
       
  1062     else
       
  1063         d->stealMouse = false;
       
  1064 
   968     d->lastElapsed = 0;
  1065     d->lastElapsed = 0;
   969     d->lastDist = 0;
  1066     d->lastDist = 0;
   970     QDeclarativeItemPrivate::start(d->lastPosTime);
  1067     QDeclarativeItemPrivate::start(d->lastPosTime);
   971     d->tl.clear();
  1068     d->tl.clear();
   972 }
  1069 }
   977     if (!d->interactive || !d->lastPosTime.isValid())
  1074     if (!d->interactive || !d->lastPosTime.isValid())
   978         return;
  1075         return;
   979 
  1076 
   980     if (!d->stealMouse) {
  1077     if (!d->stealMouse) {
   981         QPointF delta = event->pos() - d->startPoint;
  1078         QPointF delta = event->pos() - d->startPoint;
   982         if (qAbs(delta.x()) > QApplication::startDragDistance() && qAbs(delta.y()) > QApplication::startDragDistance())
  1079         if (qAbs(delta.x()) > QApplication::startDragDistance() || qAbs(delta.y()) > QApplication::startDragDistance())
   983             d->stealMouse = true;
  1080             d->stealMouse = true;
   984     }
  1081     }
   985 
  1082 
   986     if (d->stealMouse) {
  1083     if (d->stealMouse) {
   987         d->moveReason = QDeclarativePathViewPrivate::Mouse;
  1084         d->moveReason = QDeclarativePathViewPrivate::Mouse;
   988         qreal newPc;
  1085         qreal newPc;
   989         d->pointNear(event->pos(), &newPc);
  1086         d->pointNear(event->pos(), &newPc);
   990         qreal diff = (newPc - d->startPc)*d->model->count()*d->mappedRange;
  1087         qreal diff = (newPc - d->startPc)*d->modelCount*d->mappedRange;
   991         if (diff) {
  1088         if (diff) {
   992             setOffset(d->offset + diff);
  1089             setOffset(d->offset + diff);
   993 
  1090 
   994             if (diff > d->model->count()/2)
  1091             if (diff > d->modelCount/2)
   995                 diff -= d->model->count();
  1092                 diff -= d->modelCount;
   996             else if (diff < -d->model->count()/2)
  1093             else if (diff < -d->modelCount/2)
   997                 diff += d->model->count();
  1094                 diff += d->modelCount;
   998 
  1095 
   999             d->lastElapsed = QDeclarativeItemPrivate::restart(d->lastPosTime);
  1096             d->lastElapsed = QDeclarativeItemPrivate::restart(d->lastPosTime);
  1000             d->lastDist = diff;
  1097             d->lastDist = diff;
  1001             d->startPc = newPc;
  1098             d->startPc = newPc;
  1002         }
  1099         }
       
  1100         if (!d->moving) {
       
  1101             d->moving = true;
       
  1102             emit movingChanged();
       
  1103             emit movementStarted();
       
  1104         }
  1003     }
  1105     }
  1004 }
  1106 }
  1005 
  1107 
  1006 void QDeclarativePathView::mouseReleaseEvent(QGraphicsSceneMouseEvent *)
  1108 void QDeclarativePathView::mouseReleaseEvent(QGraphicsSceneMouseEvent *)
  1007 {
  1109 {
  1011     if (!d->interactive || !d->lastPosTime.isValid())
  1113     if (!d->interactive || !d->lastPosTime.isValid())
  1012         return;
  1114         return;
  1013 
  1115 
  1014     qreal elapsed = qreal(d->lastElapsed + QDeclarativeItemPrivate::elapsed(d->lastPosTime)) / 1000.;
  1116     qreal elapsed = qreal(d->lastElapsed + QDeclarativeItemPrivate::elapsed(d->lastPosTime)) / 1000.;
  1015     qreal velocity = elapsed > 0. ? d->lastDist / elapsed : 0;
  1117     qreal velocity = elapsed > 0. ? d->lastDist / elapsed : 0;
  1016     if (d->model && d->model->count() && qAbs(velocity) > 1.) {
  1118     if (d->model && d->modelCount && qAbs(velocity) > 1.) {
  1017         qreal count = d->pathItems == -1 ? d->model->count() : d->pathItems;
  1119         qreal count = d->pathItems == -1 ? d->modelCount : d->pathItems;
  1018         if (qAbs(velocity) > count * 2) // limit velocity
  1120         if (qAbs(velocity) > count * 2) // limit velocity
  1019             velocity = (velocity > 0 ? count : -count) * 2;
  1121             velocity = (velocity > 0 ? count : -count) * 2;
  1020         // Calculate the distance to be travelled
  1122         // Calculate the distance to be travelled
  1021         qreal v2 = velocity*velocity;
  1123         qreal v2 = velocity*velocity;
  1022         qreal accel = d->deceleration/10;
  1124         qreal accel = d->deceleration/10;
  1023         // + 0.25 to encourage moving at least one item in the flick direction
  1125         // + 0.25 to encourage moving at least one item in the flick direction
  1024         qreal dist = qMin(qreal(d->model->count()-1), qreal(v2 / (accel * 2.0) + 0.25));
  1126         qreal dist = qMin(qreal(d->modelCount-1), qreal(v2 / (accel * 2.0) + 0.25));
  1025         if (d->haveHighlightRange && d->highlightRangeMode == QDeclarativePathView::StrictlyEnforceRange) {
  1127         if (d->haveHighlightRange && d->highlightRangeMode == QDeclarativePathView::StrictlyEnforceRange) {
  1026             // round to nearest item.
  1128             // round to nearest item.
  1027             if (velocity > 0.)
  1129             if (velocity > 0.)
  1028                 dist = qRound(dist + d->offset) - d->offset;
  1130                 dist = qRound(dist + d->offset) - d->offset;
  1029             else
  1131             else
  1034                 accel = 0.;
  1136                 accel = 0.;
  1035             } else {
  1137             } else {
  1036                 accel = v2 / (2.0f * qAbs(dist));
  1138                 accel = v2 / (2.0f * qAbs(dist));
  1037             }
  1139             }
  1038         }
  1140         }
       
  1141         d->offsetAdj = 0.0;
  1039         d->moveOffset.setValue(d->offset);
  1142         d->moveOffset.setValue(d->offset);
  1040         d->tl.accel(d->moveOffset, velocity, accel, dist);
  1143         d->tl.accel(d->moveOffset, velocity, accel, dist);
  1041         d->tl.callback(QDeclarativeTimeLineCallback(&d->moveOffset, d->fixOffsetCallback, d));
  1144         d->tl.callback(QDeclarativeTimeLineCallback(&d->moveOffset, d->fixOffsetCallback, d));
       
  1145         if (!d->flicking) {
       
  1146             d->flicking = true;
       
  1147             emit flickingChanged();
       
  1148             emit flickStarted();
       
  1149         }
  1042     } else {
  1150     } else {
  1043         d->fixOffset();
  1151         d->fixOffset();
  1044     }
  1152     }
  1045 
  1153 
  1046     d->lastPosTime.invalidate();
  1154     d->lastPosTime.invalidate();
  1047     ungrabMouse();
  1155     ungrabMouse();
       
  1156     if (!d->tl.isActive())
       
  1157         movementEnding();
  1048 }
  1158 }
  1049 
  1159 
  1050 bool QDeclarativePathView::sendMouseEvent(QGraphicsSceneMouseEvent *event)
  1160 bool QDeclarativePathView::sendMouseEvent(QGraphicsSceneMouseEvent *event)
  1051 {
  1161 {
  1052     Q_D(QDeclarativePathView);
  1162     Q_D(QDeclarativePathView);
  1162         } else {
  1272         } else {
  1163 //            qDebug() << "release";
  1273 //            qDebug() << "release";
  1164             d->updateItem(item, 1.0);
  1274             d->updateItem(item, 1.0);
  1165             d->releaseItem(item);
  1275             d->releaseItem(item);
  1166             if (it == d->items.begin()) {
  1276             if (it == d->items.begin()) {
  1167                 if (++d->firstIndex >= d->model->count())
  1277                 if (++d->firstIndex >= d->modelCount)
  1168                     d->firstIndex = 0;
  1278                     d->firstIndex = 0;
  1169             }
  1279             }
  1170             it = d->items.erase(it);
  1280             it = d->items.erase(it);
  1171         }
  1281         }
  1172         ++idx;
  1282         ++idx;
  1173         if (idx >= d->model->count())
  1283         if (idx >= d->modelCount)
  1174             idx = 0;
  1284             idx = 0;
  1175     }
  1285     }
  1176 
  1286 
  1177     // add items to beginning and end
  1287     if (d->modelCount) {
  1178     int count = d->pathItems == -1 ? d->model->count() : qMin(d->pathItems, d->model->count());
  1288         // add items to beginning and end
  1179     if (d->items.count() < count) {
  1289         int count = d->pathItems == -1 ? d->modelCount : qMin(d->pathItems, d->modelCount);
  1180         int idx = qRound(d->model->count() - d->offset) % d->model->count();
  1290         if (d->items.count() < count) {
  1181         qreal startPos = 0.0;
  1291             int idx = qRound(d->modelCount - d->offset) % d->modelCount;
  1182         if (d->haveHighlightRange && d->highlightRangeMode != QDeclarativePathView::NoHighlightRange)
  1292             qreal startPos = 0.0;
  1183             startPos = d->highlightRangeStart;
  1293             if (d->haveHighlightRange && d->highlightRangeMode != QDeclarativePathView::NoHighlightRange)
  1184         if (d->firstIndex >= 0) {
  1294                 startPos = d->highlightRangeStart;
  1185             startPos = d->positionOfIndex(d->firstIndex);
  1295             if (d->firstIndex >= 0) {
  1186             idx = (d->firstIndex + d->items.count()) % d->model->count();
  1296                 startPos = d->positionOfIndex(d->firstIndex);
  1187         }
  1297                 idx = (d->firstIndex + d->items.count()) % d->modelCount;
  1188         qreal pos = d->positionOfIndex(idx);
       
  1189         while ((pos > startPos || !d->items.count()) && d->items.count() < count) {
       
  1190 //            qDebug() << "append" << idx;
       
  1191             QDeclarativeItem *item = d->getItem(idx);
       
  1192             if (d->model->completePending())
       
  1193                 item->setZValue(idx+1);
       
  1194             if (d->currentIndex == idx) {
       
  1195                 item->setFocus(true);
       
  1196                 if (QDeclarativePathViewAttached *att = d->attached(item))
       
  1197                     att->setIsCurrentItem(true);
       
  1198                 currentVisible = true;
       
  1199                 d->currentItemOffset = pos;
       
  1200                 d->currentItem = item;
       
  1201             }
  1298             }
  1202             if (d->items.count() == 0)
  1299             qreal pos = d->positionOfIndex(idx);
  1203                 d->firstIndex = idx;
  1300             while ((pos > startPos || !d->items.count()) && d->items.count() < count) {
  1204             d->items.append(item);
  1301     //            qDebug() << "append" << idx;
  1205             d->updateItem(item, pos);
  1302                 QDeclarativeItem *item = d->getItem(idx);
  1206             if (d->model->completePending())
  1303                 if (d->model->completePending())
  1207                 d->model->completeItem();
  1304                     item->setZValue(idx+1);
  1208             ++idx;
  1305                 if (d->currentIndex == idx) {
  1209             if (idx >= d->model->count())
  1306                     item->setFocus(true);
  1210                 idx = 0;
  1307                     if (QDeclarativePathViewAttached *att = d->attached(item))
  1211             pos = d->positionOfIndex(idx);
  1308                         att->setIsCurrentItem(true);
  1212         }
  1309                     currentVisible = true;
  1213 
  1310                     d->currentItemOffset = pos;
  1214         idx = d->firstIndex - 1;
  1311                     d->currentItem = item;
  1215         if (idx < 0)
  1312                 }
  1216             idx = d->model->count() - 1;
  1313                 if (d->items.count() == 0)
  1217         pos = d->positionOfIndex(idx);
  1314                     d->firstIndex = idx;
  1218         while (pos >= 0.0 && pos < startPos) {
  1315                 d->items.append(item);
  1219 //            qDebug() << "prepend" << idx;
  1316                 d->updateItem(item, pos);
  1220             QDeclarativeItem *item = d->getItem(idx);
  1317                 if (d->model->completePending())
  1221             if (d->model->completePending())
  1318                     d->model->completeItem();
  1222                 item->setZValue(idx+1);
  1319                 ++idx;
  1223             if (d->currentIndex == idx) {
  1320                 if (idx >= d->modelCount)
  1224                 item->setFocus(true);
  1321                     idx = 0;
  1225                 if (QDeclarativePathViewAttached *att = d->attached(item))
  1322                 pos = d->positionOfIndex(idx);
  1226                     att->setIsCurrentItem(true);
       
  1227                 currentVisible = true;
       
  1228                 d->currentItemOffset = pos;
       
  1229                 d->currentItem = item;
       
  1230             }
  1323             }
  1231             d->items.prepend(item);
  1324 
  1232             d->updateItem(item, pos);
       
  1233             if (d->model->completePending())
       
  1234                 d->model->completeItem();
       
  1235             d->firstIndex = idx;
       
  1236             idx = d->firstIndex - 1;
  1325             idx = d->firstIndex - 1;
  1237             if (idx < 0)
  1326             if (idx < 0)
  1238                 idx = d->model->count() - 1;
  1327                 idx = d->modelCount - 1;
  1239             pos = d->positionOfIndex(idx);
  1328             pos = d->positionOfIndex(idx);
       
  1329             while (pos >= 0.0 && pos < startPos) {
       
  1330     //            qDebug() << "prepend" << idx;
       
  1331                 QDeclarativeItem *item = d->getItem(idx);
       
  1332                 if (d->model->completePending())
       
  1333                     item->setZValue(idx+1);
       
  1334                 if (d->currentIndex == idx) {
       
  1335                     item->setFocus(true);
       
  1336                     if (QDeclarativePathViewAttached *att = d->attached(item))
       
  1337                         att->setIsCurrentItem(true);
       
  1338                     currentVisible = true;
       
  1339                     d->currentItemOffset = pos;
       
  1340                     d->currentItem = item;
       
  1341                 }
       
  1342                 d->items.prepend(item);
       
  1343                 d->updateItem(item, pos);
       
  1344                 if (d->model->completePending())
       
  1345                     d->model->completeItem();
       
  1346                 d->firstIndex = idx;
       
  1347                 idx = d->firstIndex - 1;
       
  1348                 if (idx < 0)
       
  1349                     idx = d->modelCount - 1;
       
  1350                 pos = d->positionOfIndex(idx);
       
  1351             }
  1240         }
  1352         }
  1241     }
  1353     }
  1242 
  1354 
  1243     if (!currentVisible)
  1355     if (!currentVisible)
  1244         d->currentItemOffset = 1.0;
  1356         d->currentItemOffset = 1.0;
  1250     } else if (d->highlightItem && d->moveReason != QDeclarativePathViewPrivate::SetIndex) {
  1362     } else if (d->highlightItem && d->moveReason != QDeclarativePathViewPrivate::SetIndex) {
  1251         d->updateItem(d->highlightItem, d->currentItemOffset);
  1363         d->updateItem(d->highlightItem, d->currentItemOffset);
  1252         if (QDeclarativePathViewAttached *att = d->attached(d->highlightItem))
  1364         if (QDeclarativePathViewAttached *att = d->attached(d->highlightItem))
  1253             att->setOnPath(currentVisible);
  1365             att->setOnPath(currentVisible);
  1254     }
  1366     }
       
  1367     while (d->itemCache.count())
       
  1368         d->releaseItem(d->itemCache.takeLast());
  1255 }
  1369 }
  1256 
  1370 
  1257 void QDeclarativePathView::itemsInserted(int modelIndex, int count)
  1371 void QDeclarativePathView::itemsInserted(int modelIndex, int count)
  1258 {
  1372 {
  1259     //XXX support animated insertion
  1373     //XXX support animated insertion
  1260     Q_D(QDeclarativePathView);
  1374     Q_D(QDeclarativePathView);
  1261     if (!d->isValid() || !isComponentComplete())
  1375     if (!d->isValid() || !isComponentComplete())
  1262         return;
  1376         return;
  1263 
  1377 
  1264     QList<QDeclarativeItem *> removedItems = d->items;
  1378     d->itemCache += d->items;
  1265     d->items.clear();
  1379     d->items.clear();
  1266     if (modelIndex <= d->currentIndex) {
  1380     if (modelIndex <= d->currentIndex) {
  1267         d->currentIndex += count;
  1381         d->currentIndex += count;
  1268         emit currentIndexChanged();
  1382         emit currentIndexChanged();
  1269     }
  1383     } else if (d->offset != 0) {
  1270     d->regenerate();
  1384         d->offset += count;
  1271     while (removedItems.count())
  1385         d->offsetAdj += count;
  1272         d->releaseItem(removedItems.takeLast());
  1386     }
  1273     d->updateCurrent();
  1387 
       
  1388     d->modelCount = d->model->count();
       
  1389     if (d->flicking || d->moving) {
       
  1390         d->regenerate();
       
  1391         d->updateCurrent();
       
  1392     } else {
       
  1393         d->firstIndex = -1;
       
  1394         d->updateMappedRange();
       
  1395         d->scheduleLayout();
       
  1396     }
  1274     emit countChanged();
  1397     emit countChanged();
  1275 }
  1398 }
  1276 
  1399 
  1277 void QDeclarativePathView::itemsRemoved(int modelIndex, int count)
  1400 void QDeclarativePathView::itemsRemoved(int modelIndex, int count)
  1278 {
  1401 {
  1279     //XXX support animated removal
  1402     //XXX support animated removal
  1280     Q_D(QDeclarativePathView);
  1403     Q_D(QDeclarativePathView);
  1281     if (!d->isValid() || !isComponentComplete())
  1404     if (!d->model || !d->modelCount || !d->model->isValid() || !d->path || !isComponentComplete())
  1282         return;
  1405         return;
  1283 
  1406 
  1284     // fix current
  1407     // fix current
  1285     bool currentChanged = false;
  1408     bool currentChanged = false;
  1286     if (d->currentIndex >= modelIndex + count) {
  1409     if (d->currentIndex >= modelIndex + count) {
  1287         d->currentIndex -= count;
  1410         d->currentIndex -= count;
  1288         currentChanged = true;
  1411         currentChanged = true;
  1289     } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
  1412     } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
  1290         // current item has been removed.
  1413         // current item has been removed.
  1291         d->currentIndex = qMin(modelIndex, d->model->count()-1);
  1414         d->currentIndex = qMin(modelIndex, d->modelCount-1);
  1292         if (d->currentItem) {
  1415         if (d->currentItem) {
  1293             if (QDeclarativePathViewAttached *att = d->attached(d->currentItem))
  1416             if (QDeclarativePathViewAttached *att = d->attached(d->currentItem))
  1294                 att->setIsCurrentItem(true);
  1417                 att->setIsCurrentItem(true);
  1295         }
  1418         }
  1296         currentChanged = true;
  1419         currentChanged = true;
  1297     }
  1420     }
  1298 
  1421 
  1299     QList<QDeclarativeItem *> removedItems = d->items;
  1422     d->itemCache += d->items;
  1300     d->items.clear();
  1423     d->items.clear();
  1301     if (d->offset >= d->model->count())
  1424 
  1302         d->offset = d->model->count() - 1;
  1425     if (modelIndex > d->currentIndex) {
  1303 
  1426         if (d->offset >= count) {
       
  1427             d->offset -= count;
       
  1428             d->offsetAdj -= count;
       
  1429         }
       
  1430     }
       
  1431 
       
  1432     d->modelCount = d->model->count();
  1304     d->regenerate();
  1433     d->regenerate();
  1305     while (removedItems.count())
       
  1306         d->releaseItem(removedItems.takeLast());
       
  1307     d->updateCurrent();
  1434     d->updateCurrent();
       
  1435     if (!d->modelCount)
       
  1436         update();
  1308     if (currentChanged)
  1437     if (currentChanged)
  1309         emit currentIndexChanged();
  1438         emit currentIndexChanged();
  1310     emit countChanged();
  1439     emit countChanged();
  1311 }
  1440 }
  1312 
  1441 
  1333 }
  1462 }
  1334 
  1463 
  1335 void QDeclarativePathView::modelReset()
  1464 void QDeclarativePathView::modelReset()
  1336 {
  1465 {
  1337     Q_D(QDeclarativePathView);
  1466     Q_D(QDeclarativePathView);
       
  1467     d->modelCount = d->model->count();
  1338     d->regenerate();
  1468     d->regenerate();
  1339     emit countChanged();
  1469     emit countChanged();
  1340 }
  1470 }
  1341 
  1471 
  1342 void QDeclarativePathView::createdItem(int index, QDeclarativeItem *item)
  1472 void QDeclarativePathView::createdItem(int index, QDeclarativeItem *item)
  1370 {
  1500 {
  1371     Q_D(QDeclarativePathView);
  1501     Q_D(QDeclarativePathView);
  1372     d->updateCurrent();
  1502     d->updateCurrent();
  1373 }
  1503 }
  1374 
  1504 
       
  1505 void QDeclarativePathView::movementEnding()
       
  1506 {
       
  1507     Q_D(QDeclarativePathView);
       
  1508     if (d->flicking) {
       
  1509         d->flicking = false;
       
  1510         emit flickingChanged();
       
  1511         emit flickEnded();
       
  1512     }
       
  1513     if (d->moving && !d->stealMouse) {
       
  1514         d->moving = false;
       
  1515         emit movingChanged();
       
  1516         emit movementEnded();
       
  1517     }
       
  1518 }
       
  1519 
  1375 // find the item closest to the snap position
  1520 // find the item closest to the snap position
  1376 int QDeclarativePathViewPrivate::calcCurrentIndex()
  1521 int QDeclarativePathViewPrivate::calcCurrentIndex()
  1377 {
  1522 {
  1378     int current = -1;
  1523     int current = -1;
  1379     if (model && items.count()) {
  1524     if (model && items.count()) {
  1380         offset = qmlMod(offset, model->count());
  1525         offset = qmlMod(offset, modelCount);
  1381         if (offset < 0)
  1526         if (offset < 0)
  1382             offset += model->count();
  1527             offset += modelCount;
  1383         current = qRound(qAbs(qmlMod(model->count() - offset, model->count())));
  1528         current = qRound(qAbs(qmlMod(modelCount - offset, modelCount)));
  1384         current = current % model->count();
  1529         current = current % modelCount;
  1385     }
  1530     }
  1386 
  1531 
  1387     return current;
  1532     return current;
  1388 }
  1533 }
  1389 
  1534 
  1395     if (!haveHighlightRange || highlightRangeMode != QDeclarativePathView::StrictlyEnforceRange)
  1540     if (!haveHighlightRange || highlightRangeMode != QDeclarativePathView::StrictlyEnforceRange)
  1396         return;
  1541         return;
  1397 
  1542 
  1398     int idx = calcCurrentIndex();
  1543     int idx = calcCurrentIndex();
  1399     if (model && idx != currentIndex) {
  1544     if (model && idx != currentIndex) {
  1400         int itemIndex = (currentIndex - firstIndex + model->count()) % model->count();
  1545         int itemIndex = (currentIndex - firstIndex + modelCount) % modelCount;
  1401         if (itemIndex < items.count()) {
  1546         if (itemIndex < items.count()) {
  1402             if (QDeclarativeItem *item = items.at(itemIndex)) {
  1547             if (QDeclarativeItem *item = items.at(itemIndex)) {
  1403                 if (QDeclarativePathViewAttached *att = attached(item))
  1548                 if (QDeclarativePathViewAttached *att = attached(item))
  1404                     att->setIsCurrentItem(false);
  1549                     att->setIsCurrentItem(false);
  1405             }
  1550             }
  1406         }
  1551         }
  1407         currentIndex = idx;
  1552         currentIndex = idx;
  1408         currentItem = 0;
  1553         currentItem = 0;
  1409         itemIndex = (idx - firstIndex + model->count()) % model->count();
  1554         itemIndex = (idx - firstIndex + modelCount) % modelCount;
  1410         if (itemIndex < items.count()) {
  1555         if (itemIndex < items.count()) {
  1411             currentItem = items.at(itemIndex);
  1556             currentItem = items.at(itemIndex);
  1412             currentItem->setFocus(true);
  1557             currentItem->setFocus(true);
  1413             if (QDeclarativePathViewAttached *att = attached(currentItem))
  1558             if (QDeclarativePathViewAttached *att = attached(currentItem))
  1414                 att->setIsCurrentItem(true);
  1559                 att->setIsCurrentItem(true);
  1436     }
  1581     }
  1437 }
  1582 }
  1438 
  1583 
  1439 void QDeclarativePathViewPrivate::snapToCurrent()
  1584 void QDeclarativePathViewPrivate::snapToCurrent()
  1440 {
  1585 {
  1441     if (!model || model->count() <= 0)
  1586     if (!model || modelCount <= 0)
  1442         return;
  1587         return;
  1443 
  1588 
  1444     qreal targetOffset = model->count() - currentIndex;
  1589     qreal targetOffset = modelCount - currentIndex;
  1445 
  1590 
  1446     moveReason = Other;
  1591     moveReason = Other;
       
  1592     offsetAdj = 0.0;
  1447     tl.reset(moveOffset);
  1593     tl.reset(moveOffset);
  1448     moveOffset.setValue(offset);
  1594     moveOffset.setValue(offset);
  1449 
  1595 
  1450     const int duration = highlightMoveDuration;
  1596     const int duration = highlightMoveDuration;
  1451 
  1597 
  1452     if (targetOffset - offset > model->count()/2) {
  1598     if (targetOffset - offset > modelCount/2) {
  1453         qreal distance = model->count() - targetOffset + offset;
  1599         qreal distance = modelCount - targetOffset + offset;
  1454         tl.move(moveOffset, 0.0, QEasingCurve(QEasingCurve::InQuad), int(duration * offset / distance));
  1600         tl.move(moveOffset, 0.0, QEasingCurve(QEasingCurve::InQuad), int(duration * offset / distance));
  1455         tl.set(moveOffset, model->count());
  1601         tl.set(moveOffset, modelCount);
  1456         tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::OutQuad), int(duration * (model->count()-targetOffset) / distance));
  1602         tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::OutQuad), int(duration * (modelCount-targetOffset) / distance));
  1457     } else if (targetOffset - offset <= -model->count()/2) {
  1603     } else if (targetOffset - offset <= -modelCount/2) {
  1458         qreal distance = model->count() - offset + targetOffset;
  1604         qreal distance = modelCount - offset + targetOffset;
  1459         tl.move(moveOffset, model->count(), QEasingCurve(QEasingCurve::InQuad), int(duration * (model->count()-offset) / distance));
  1605         tl.move(moveOffset, modelCount, QEasingCurve(QEasingCurve::InQuad), int(duration * (modelCount-offset) / distance));
  1460         tl.set(moveOffset, 0.0);
  1606         tl.set(moveOffset, 0.0);
  1461         tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::OutQuad), int(duration * targetOffset / distance));
  1607         tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::OutQuad), int(duration * targetOffset / distance));
  1462     } else {
  1608     } else {
  1463         tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
  1609         tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), duration);
  1464     }
  1610     }