Qt 4.8
qdeclarativelistview.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "private/qdeclarativelistview_p.h"
43 
44 #include "private/qdeclarativeflickable_p_p.h"
45 #include "private/qdeclarativevisualitemmodel_p.h"
46 
47 #include "private/qdeclarativesmoothedanimation_p_p.h"
48 #include <qdeclarativeexpression.h>
49 #include <qdeclarativeengine.h>
50 #include <qdeclarativeguard_p.h>
51 #include <qdeclarativeinfo.h>
52 
53 #include <qlistmodelinterface_p.h>
54 #include <qmath.h>
55 #include <QKeyEvent>
56 #include "qplatformdefs.h"
57 
59 
60 #ifndef QML_FLICK_SNAPONETHRESHOLD
61 #define QML_FLICK_SNAPONETHRESHOLD 30
62 #endif
63 
65 {
66  if (property != m_property) {
69  }
70 }
71 
73 {
74  if (criteria != m_criteria) {
77  }
78 }
79 
81 {
82  if (delegate != m_delegate) {
85  }
86 }
87 
89 {
91  return value.isEmpty() ? QString() : value.at(0);
92  else
93  return value;
94 }
95 
96 //----------------------------------------------------------------------------
97 
99 {
100 public:
101  FxListItem(QDeclarativeItem *i, QDeclarativeListView *v) : item(i), section(0), view(v) {
102  attached = static_cast<QDeclarativeListViewAttached*>(qmlAttachedPropertiesObject<QDeclarativeListView>(item));
103  if (attached)
104  attached->setView(view);
105  }
107  qreal position() const {
108  if (section) {
109  if (view->orientation() == QDeclarativeListView::Vertical)
110  return section->y();
111  else
112  return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section->width()-section->x() : section->x());
113  } else {
114  return itemPosition();
115  }
116  }
117 
118  qreal itemPosition() const {
119  if (view->orientation() == QDeclarativeListView::Vertical)
120  return item->y();
121  else
122  return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-item->x() : item->x());
123  }
124  qreal size() const {
125  if (section)
126  return (view->orientation() == QDeclarativeListView::Vertical ? item->height()+section->height() : item->width()+section->width());
127  else
128  return (view->orientation() == QDeclarativeListView::Vertical ? item->height() : item->width());
129  }
130  qreal itemSize() const {
131  return (view->orientation() == QDeclarativeListView::Vertical ? item->height() : item->width());
132  }
133  qreal sectionSize() const {
134  if (section)
135  return (view->orientation() == QDeclarativeListView::Vertical ? section->height() : section->width());
136  return 0.0;
137  }
138  qreal endPosition() const {
139  if (view->orientation() == QDeclarativeListView::Vertical) {
140  return item->y() + (item->height() >= 1.0 ? item->height() : 1) - 1;
141  } else {
142  return (view->effectiveLayoutDirection() == Qt::RightToLeft
143  ? -item->width()-item->x() + (item->width() >= 1.0 ? item->width() : 1)
144  : item->x() + (item->width() >= 1.0 ? item->width() : 1)) - 1;
145  }
146  }
147  void setPosition(qreal pos) {
148  if (view->orientation() == QDeclarativeListView::Vertical) {
149  if (section) {
150  section->setY(pos);
151  pos += section->height();
152  }
153  item->setY(pos);
154  } else {
155  if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
156  if (section) {
157  section->setX(-section->width()-pos);
158  pos += section->width();
159  }
160  item->setX(-item->width()-pos);
161  } else {
162  if (section) {
163  section->setX(pos);
164  pos += section->width();
165  }
166  item->setX(pos);
167  }
168  }
169  }
170  void setSize(qreal size) {
171  if (view->orientation() == QDeclarativeListView::Vertical)
172  item->setHeight(size);
173  else
174  item->setWidth(size);
175  }
176  bool contains(qreal x, qreal y) const {
177  return (x >= item->x() && x < item->x() + item->width() &&
178  y >= item->y() && y < item->y() + item->height());
179  }
180 
185  int index;
186 };
187 
188 //----------------------------------------------------------------------------
189 
191 {
193 
194 public:
196  : currentItem(0), orient(QDeclarativeListView::Vertical), layoutDirection(Qt::LeftToRight)
197  , visiblePos(0), visibleIndex(0)
198  , averageSize(100.0), currentIndex(-1), requestedIndex(-1)
199  , itemCount(0), highlightRangeStart(0), highlightRangeEnd(0)
200  , highlightRangeStartValid(false), highlightRangeEndValid(false)
201  , highlightComponent(0), highlight(0), trackedItem(0)
202  , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0)
203  , sectionCriteria(0), spacing(0.0)
204  , highlightMoveSpeed(400), highlightMoveDuration(-1)
205  , highlightResizeSpeed(400), highlightResizeDuration(-1), highlightRange(QDeclarativeListView::NoHighlightRange)
206  , snapMode(QDeclarativeListView::NoSnap), overshootDist(0.0)
207  , footerComponent(0), footer(0), headerComponent(0), header(0)
208  , bufferMode(BufferBefore | BufferAfter)
209  , ownModel(false), wrap(false), autoHighlight(true), haveHighlightRange(false)
210  , correctFlick(false), inFlickCorrection(false), lazyRelease(false)
211  , deferredRelease(false), layoutScheduled(false), currentIndexCleared(false)
212  , inViewportMoved(false)
213  , minExtentDirty(true), maxExtentDirty(true)
214  {}
215 
216  void init();
217  void clear();
218  FxListItem *createItem(int modelIndex);
219  void releaseItem(FxListItem *item);
220  QDeclarativeItem *createComponentItem(QDeclarativeComponent *component);
221 
222  FxListItem *visibleItem(int modelIndex) const {
223  if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
224  for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
225  FxListItem *item = visibleItems.at(i);
226  if (item->index == modelIndex)
227  return item;
228  }
229  }
230  return 0;
231  }
232 
234  const qreal pos = isRightToLeft() ? -position()-size() : position();
235  for (int i = 0; i < visibleItems.count(); ++i) {
236  FxListItem *item = visibleItems.at(i);
237  if (item->index != -1 && item->endPosition() > pos)
238  return item;
239  }
240  return visibleItems.count() ? visibleItems.first() : 0;
241  }
242 
243  // Returns the item before modelIndex, if created.
244  // May return an item marked for removal.
245  FxListItem *itemBefore(int modelIndex) const {
246  if (modelIndex < visibleIndex)
247  return 0;
248  int idx = 1;
249  int lastIndex = -1;
250  while (idx < visibleItems.count()) {
251  FxListItem *item = visibleItems.at(idx);
252  if (item->index != -1)
253  lastIndex = item->index;
254  if (item->index == modelIndex)
255  return visibleItems.at(idx-1);
256  ++idx;
257  }
258  if (lastIndex == modelIndex-1)
259  return visibleItems.last();
260  return 0;
261  }
262 
263  void regenerate() {
265  if (q->isComponentComplete()) {
266  if (header) {
267  if (q->scene())
268  q->scene()->removeItem(header->item);
269  header->item->deleteLater();
270  delete header;
271  header = 0;
272  }
273  if (footer) {
274  if (q->scene())
275  q->scene()->removeItem(footer->item);
276  footer->item->deleteLater();
277  delete footer;
278  footer = 0;
279  }
280  updateHeader();
281  updateFooter();
282  clear();
283  setPosition(0);
284  q->refill();
285  updateCurrent(currentIndex);
286  }
287  }
288 
289  void mirrorChange() {
290  regenerate();
291  }
292 
293  bool isRightToLeft() const {
294  Q_Q(const QDeclarativeListView);
295  return orient == QDeclarativeListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
296  }
297 
298  qreal position() const {
299  Q_Q(const QDeclarativeListView);
300  return orient == QDeclarativeListView::Vertical ? q->contentY() : q->contentX();
301  }
302 
303  void setPosition(qreal pos) {
305  if (orient == QDeclarativeListView::Vertical) {
306  q->QDeclarativeFlickable::setContentY(pos);
307  } else {
308  if (isRightToLeft())
309  q->QDeclarativeFlickable::setContentX(-pos-size());
310  else
311  q->QDeclarativeFlickable::setContentX(pos);
312  }
313  }
314  qreal size() const {
315  Q_Q(const QDeclarativeListView);
316  return orient == QDeclarativeListView::Vertical ? q->height() : q->width();
317  }
318 
320  qreal pos = 0;
321  if (!visibleItems.isEmpty()) {
322  pos = (*visibleItems.constBegin())->position();
323  if (visibleIndex > 0)
324  pos -= visibleIndex * (averageSize + spacing);
325  }
326  return pos;
327  }
328 
329  qreal lastPosition() const {
330  qreal pos = 0;
331  if (!visibleItems.isEmpty()) {
332  int invisibleCount = visibleItems.count() - visibleIndex;
333  for (int i = visibleItems.count()-1; i >= 0; --i) {
334  if (visibleItems.at(i)->index != -1) {
335  invisibleCount = model->count() - visibleItems.at(i)->index - 1;
336  break;
337  }
338  }
339  pos = (*(--visibleItems.constEnd()))->endPosition() + invisibleCount * (averageSize + spacing);
340  } else if (model && model->count()) {
341  pos = model->count() * averageSize + (model->count()-1) * spacing;
342  }
343  return pos;
344  }
345 
347  return isRightToLeft() ? -lastPosition()-1 : originPosition();
348  }
349 
350  qreal endPosition() const {
351  return isRightToLeft() ? -originPosition()-1 : lastPosition();
352  }
353 
354  qreal positionAt(int modelIndex) const {
355  if (FxListItem *item = visibleItem(modelIndex))
356  return item->position();
357  if (!visibleItems.isEmpty()) {
358  if (modelIndex < visibleIndex) {
359  int count = visibleIndex - modelIndex;
360  qreal cs = 0;
361  if (modelIndex == currentIndex && currentItem) {
362  cs = currentItem->size() + spacing;
363  --count;
364  }
365  return (*visibleItems.constBegin())->position() - count * (averageSize + spacing) - cs;
366  } else {
367  int idx = visibleItems.count() - 1;
368  while (idx >= 0 && visibleItems.at(idx)->index == -1)
369  --idx;
370  if (idx < 0)
371  idx = visibleIndex;
372  else
373  idx = visibleItems.at(idx)->index;
374  int count = modelIndex - idx - 1;
375 
376  return (*(--visibleItems.constEnd()))->endPosition() + spacing + count * (averageSize + spacing) + 1;
377  }
378  }
379  return 0;
380  }
381 
382  qreal endPositionAt(int modelIndex) const {
383  if (FxListItem *item = visibleItem(modelIndex))
384  return item->endPosition();
385  if (!visibleItems.isEmpty()) {
386  if (modelIndex < visibleIndex) {
387  int count = visibleIndex - modelIndex;
388  return (*visibleItems.constBegin())->position() - (count - 1) * (averageSize + spacing) - spacing - 1;
389  } else {
390  int idx = visibleItems.count() - 1;
391  while (idx >= 0 && visibleItems.at(idx)->index == -1)
392  --idx;
393  if (idx < 0)
394  idx = visibleIndex;
395  else
396  idx = visibleItems.at(idx)->index;
397  int count = modelIndex - idx - 1;
398  return (*(--visibleItems.constEnd()))->endPosition() + count * (averageSize + spacing);
399  }
400  }
401  return 0;
402  }
403 
404  QString sectionAt(int modelIndex) {
405  if (FxListItem *item = visibleItem(modelIndex))
406  return item->attached->section();
407 
408  QString section;
409  if (sectionCriteria) {
410  QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
411  section = sectionCriteria->sectionString(propValue);
412  }
413 
414  return section;
415  }
416 
417  bool isValid() const {
418  return model && model->count() && model->isValid();
419  }
420 
422  if (FxListItem *snapItem = snapItemAt(pos))
423  return snapItem->position();
424  if (visibleItems.count()) {
425  qreal firstPos = visibleItems.first()->position();
426  qreal endPos = visibleItems.last()->position();
427  if (pos < firstPos) {
428  return firstPos - qRound((firstPos - pos) / averageSize) * averageSize;
429  } else if (pos > endPos)
430  return endPos + qRound((pos - endPos) / averageSize) * averageSize;
431  }
432  return qRound((pos - originPosition()) / averageSize) * averageSize + originPosition();
433  }
434 
436  FxListItem *snapItem = 0;
437  for (int i = 0; i < visibleItems.count(); ++i) {
438  FxListItem *item = visibleItems[i];
439  if (item->index == -1)
440  continue;
441  qreal itemTop = item->position();
442  if (highlight && itemTop >= pos && item->endPosition() <= pos + highlight->size() - 1)
443  return item;
444  if (itemTop+item->size()/2 >= pos && itemTop-item->size()/2 < pos)
445  snapItem = item;
446  }
447  return snapItem;
448  }
449 
450  int lastVisibleIndex() const {
451  int lastIndex = -1;
452  for (int i = visibleItems.count()-1; i >= 0; --i) {
453  FxListItem *listItem = visibleItems.at(i);
454  if (listItem->index != -1) {
455  lastIndex = listItem->index;
456  break;
457  }
458  }
459  return lastIndex;
460  }
461 
462  // map a model index to visibleItems index.
463  int mapFromModel(int modelIndex) const {
464  if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
465  return -1;
466  for (int i = 0; i < visibleItems.count(); ++i) {
467  FxListItem *listItem = visibleItems.at(i);
468  if (listItem->index == modelIndex)
469  return i;
470  if (listItem->index > modelIndex)
471  return -1;
472  }
473  return -1; // Not in visibleList
474  }
475 
476  void updateViewport() {
478  if (orient == QDeclarativeListView::Vertical) {
479  q->setContentHeight(endPosition() - startPosition() + 1);
480  } else {
481  q->setContentWidth(endPosition() - startPosition() + 1);
482  }
483  }
484 
485  void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
487  QDeclarativeFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
488  if (!q->isComponentComplete())
489  return;
490  if (item != contentItem && (!highlight || item != highlight->item)) {
491  if ((orient == QDeclarativeListView::Vertical && newGeometry.height() != oldGeometry.height())
492  || (orient == QDeclarativeListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
493  scheduleLayout();
494  }
495  }
496  if ((header && header->item == item) || (footer && footer->item == item)) {
497  if (header)
498  updateHeader();
499  if (footer)
500  updateFooter();
501  }
502  if (currentItem && currentItem->item == item)
503  updateHighlight();
504  if (trackedItem && trackedItem->item == item)
505  q->trackedPositionChanged();
506  }
507 
508  // for debugging only
509  void checkVisible() const {
510  int skip = 0;
511  for (int i = 0; i < visibleItems.count(); ++i) {
512  FxListItem *listItem = visibleItems.at(i);
513  if (listItem->index == -1) {
514  ++skip;
515  } else if (listItem->index != visibleIndex + i - skip) {
516  qFatal("index %d %d %d", visibleIndex, i, listItem->index);
517  }
518  }
519  }
520 
521  void refill(qreal from, qreal to, bool doBuffer = false);
522  void scheduleLayout();
523  void layout();
524  void updateUnrequestedIndexes();
525  void updateUnrequestedPositions();
526  void updateTrackedItem();
527  void createHighlight();
528  void updateHighlight();
529  void createSection(FxListItem *);
530  void updateSections();
531  void updateCurrentSection();
532  void updateCurrent(int);
533  void updateAverage();
534  void updateHeader();
535  void updateFooter();
536  void fixupPosition();
537  void positionViewAtIndex(int index, int mode);
538  virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
539  virtual void flick(QDeclarativeFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
540  QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
541 
562  enum MovementReason { Other, SetIndex, Mouse };
564  int buffer;
569  static const int sectionCacheSize = 4;
570  QDeclarativeItem *sectionCache[sectionCacheSize];
583  enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
585  mutable qreal minExtent;
586  mutable qreal maxExtent;
587 
588  bool ownModel : 1;
589  bool wrap : 1;
590  bool autoHighlight : 1;
592  bool correctFlick : 1;
594  bool lazyRelease : 1;
595  bool deferredRelease : 1;
596  bool layoutScheduled : 1;
598  bool inViewportMoved : 1;
599  mutable bool minExtentDirty : 1;
600  mutable bool maxExtentDirty : 1;
601 };
602 
604 {
607  addItemChangeListener(this, Geometry);
608  QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
609  q->setFlickableDirection(QDeclarativeFlickable::VerticalFlick);
610  ::memset(sectionCache, 0, sizeof(QDeclarativeItem*) * sectionCacheSize);
611 }
612 
614 {
615  timeline.clear();
616  for (int i = 0; i < visibleItems.count(); ++i)
617  releaseItem(visibleItems.at(i));
618  visibleItems.clear();
619  for (int i = 0; i < sectionCacheSize; ++i) {
620  delete sectionCache[i];
621  sectionCache[i] = 0;
622  }
623  visiblePos = header ? header->size() : 0;
624  visibleIndex = 0;
625  releaseItem(currentItem);
626  currentItem = 0;
627  createHighlight();
628  trackedItem = 0;
629  minExtentDirty = true;
630  maxExtentDirty = true;
631  itemCount = 0;
632 }
633 
635 {
637  // create object
638  requestedIndex = modelIndex;
639  FxListItem *listItem = 0;
640  if (QDeclarativeItem *item = model->item(modelIndex, false)) {
641  listItem = new FxListItem(item, q);
642  listItem->index = modelIndex;
643  // initialise attached properties
644  if (sectionCriteria) {
645  QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
646  listItem->attached->m_section = sectionCriteria->sectionString(propValue);
647  if (modelIndex > 0) {
648  if (FxListItem *item = itemBefore(modelIndex))
649  listItem->attached->m_prevSection = item->attached->section();
650  else
651  listItem->attached->m_prevSection = sectionAt(modelIndex-1);
652  }
653  if (modelIndex < model->count()-1) {
654  if (FxListItem *item = visibleItem(modelIndex+1))
655  listItem->attached->m_nextSection = item->attached->section();
656  else
657  listItem->attached->m_nextSection = sectionAt(modelIndex+1);
658  }
659  }
660  if (model->completePending()) {
661  // complete
662  listItem->item->setZValue(1);
663  listItem->item->setParentItem(q->contentItem());
664  model->completeItem();
665  } else {
666  listItem->item->setParentItem(q->contentItem());
667  }
670  if (sectionCriteria && sectionCriteria->delegate()) {
671  if (listItem->attached->m_prevSection != listItem->attached->m_section)
672  createSection(listItem);
673  }
674  unrequestedItems.remove(listItem->item);
675  }
676  requestedIndex = -1;
677 
678  return listItem;
679 }
680 
682 {
684  QDeclarativeItem *item = 0;
685  QDeclarativeContext *creationContext = component->creationContext();
687  creationContext ? creationContext : qmlContext(q));
688  QObject *nobj = component->create(context);
689  if (nobj) {
690  QDeclarative_setParent_noEvent(context, nobj);
691  item = qobject_cast<QDeclarativeItem *>(nobj);
692  if (!item)
693  delete nobj;
694  } else {
695  delete context;
696  }
697 
698  return item;
699 }
700 
702 {
704  if (!item || !model)
705  return;
706  if (trackedItem == item)
707  trackedItem = 0;
710  if (model->release(item->item) == 0) {
711  // item was not destroyed, and we no longer reference it.
712  unrequestedItems.insert(item->item, model->indexOf(item->item, q));
713  }
714  if (item->section) {
715  int i = 0;
716  do {
717  if (!sectionCache[i]) {
718  sectionCache[i] = item->section;
719  sectionCache[i]->setVisible(false);
720  item->section = 0;
721  break;
722  }
723  ++i;
724  } while (i < sectionCacheSize);
725  delete item->section;
726  }
727  delete item;
728 }
729 
730 void QDeclarativeListViewPrivate::refill(qreal from, qreal to, bool doBuffer)
731 {
733  if (!isValid() || !q->isComponentComplete())
734  return;
735  itemCount = model->count();
736  qreal bufferFrom = from - buffer;
737  qreal bufferTo = to + buffer;
738  qreal fillFrom = from;
739  qreal fillTo = to;
740  if (doBuffer && (bufferMode & BufferAfter))
741  fillTo = bufferTo;
742  if (doBuffer && (bufferMode & BufferBefore))
743  fillFrom = bufferFrom;
744 
745  bool haveValidItems = false;
746  int modelIndex = visibleIndex;
747  qreal itemEnd = visiblePos-1;
748  if (!visibleItems.isEmpty()) {
749  visiblePos = (*visibleItems.constBegin())->position();
750  itemEnd = (*(--visibleItems.constEnd()))->endPosition() + spacing;
751  int i = visibleItems.count() - 1;
752  while (i > 0 && visibleItems.at(i)->index == -1)
753  --i;
754  if (visibleItems.at(i)->index != -1) {
755  haveValidItems = true;
756  modelIndex = visibleItems.at(i)->index + 1;
757  }
758  }
759 
760  if (haveValidItems && (fillFrom > itemEnd+averageSize+spacing
761  || fillTo < visiblePos - averageSize - spacing)) {
762  // We've jumped more than a page. Estimate which items are now
763  // visible and fill from there.
764  int count = (fillFrom - itemEnd) / (averageSize + spacing);
765  for (int i = 0; i < visibleItems.count(); ++i)
766  releaseItem(visibleItems.at(i));
767  visibleItems.clear();
768  modelIndex += count;
769  if (modelIndex >= model->count()) {
770  count -= modelIndex - model->count() + 1;
771  modelIndex = model->count() - 1;
772  } else if (modelIndex < 0) {
773  count -= modelIndex;
774  modelIndex = 0;
775  }
776  visibleIndex = modelIndex;
777  visiblePos = itemEnd + count * (averageSize + spacing) + 1;
778  itemEnd = visiblePos-1;
779  }
780 
781  bool changed = false;
782  FxListItem *item = 0;
783  qreal pos = itemEnd + 1;
784  while (modelIndex < model->count() && pos <= fillTo) {
785 // qDebug() << "refill: append item" << modelIndex << "pos" << pos;
786  if (!(item = createItem(modelIndex)))
787  break;
788  item->setPosition(pos);
789  pos += item->size() + spacing;
790  visibleItems.append(item);
791  ++modelIndex;
792  changed = true;
793  if (doBuffer) // never buffer more than one item per frame
794  break;
795  }
796  while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos-1 >= fillFrom) {
797 // qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
798  if (!(item = createItem(visibleIndex-1)))
799  break;
800  --visibleIndex;
801  visiblePos -= item->size() + spacing;
802  item->setPosition(visiblePos);
803  visibleItems.prepend(item);
804  changed = true;
805  if (doBuffer) // never buffer more than one item per frame
806  break;
807  }
808 
809  if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
810  while (visibleItems.count() > 1 && (item = visibleItems.first()) && item->endPosition() < bufferFrom) {
811  if (item->attached->delayRemove())
812  break;
813 // qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
814  if (item->index != -1)
815  visibleIndex++;
816  visibleItems.removeFirst();
817  releaseItem(item);
818  changed = true;
819  }
820  while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
821  if (item->attached->delayRemove())
822  break;
823 // qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
824  visibleItems.removeLast();
825  releaseItem(item);
826  changed = true;
827  }
828  deferredRelease = false;
829  } else {
830  deferredRelease = true;
831  }
832  if (changed) {
833  minExtentDirty = true;
834  maxExtentDirty = true;
835  if (visibleItems.count())
836  visiblePos = (*visibleItems.constBegin())->position();
837  updateAverage();
838  if (currentIndex >= 0 && currentItem && !visibleItem(currentIndex)) {
839  currentItem->setPosition(positionAt(currentIndex));
840  updateHighlight();
841  }
842 
843  if (sectionCriteria)
844  updateCurrentSection();
845  if (header)
846  updateHeader();
847  if (footer)
848  updateFooter();
849  updateViewport();
850  updateUnrequestedPositions();
851  } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
852  refill(from, to, true);
853  }
854  lazyRelease = false;
855 }
856 
858 {
860  if (!layoutScheduled) {
861  layoutScheduled = true;
863  }
864 }
865 
867 {
869  layoutScheduled = false;
870  if (!isValid() && !visibleItems.count()) {
871  clear();
872  setPosition(0);
873  return;
874  }
875  if (!visibleItems.isEmpty()) {
876  bool fixedCurrent = currentItem && visibleItems.first()->item == currentItem->item;
877  qreal sum = visibleItems.first()->size();
878  qreal pos = visibleItems.first()->position() + visibleItems.first()->size() + spacing;
879  for (int i=1; i < visibleItems.count(); ++i) {
880  FxListItem *item = visibleItems.at(i);
881  item->setPosition(pos);
882  pos += item->size() + spacing;
883  sum += item->size();
884  fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
885  }
886  averageSize = qRound(sum / visibleItems.count());
887  // move current item if it is not a visible item.
888  if (currentIndex >= 0 && currentItem && !fixedCurrent)
889  currentItem->setPosition(positionAt(currentIndex));
890  }
891  q->refill();
892  minExtentDirty = true;
893  maxExtentDirty = true;
894  updateHighlight();
895  if (!q->isMoving() && !q->isFlicking()) {
896  fixupPosition();
897  q->refill();
898  }
899  if (sectionCriteria)
900  updateCurrentSection();
901  if (header)
902  updateHeader();
903  if (footer)
904  updateFooter();
905  updateViewport();
906 }
907 
909 {
912  for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
913  *it = model->indexOf(it.key(), q);
914 }
915 
917 {
919  if (unrequestedItems.count()) {
920  qreal pos = position();
922  for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
923  QDeclarativeItem *item = it.key();
924  if (orient == QDeclarativeListView::Vertical) {
925  if (item->y() + item->height() > pos && item->y() < pos + q->height())
926  item->setY(positionAt(*it));
927  } else {
928  if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
929  if (isRightToLeft())
930  item->setX(-positionAt(*it)-item->width());
931  else
932  item->setX(positionAt(*it));
933  }
934  }
935  }
936  }
937 }
938 
940 {
942  FxListItem *item = currentItem;
943  if (highlight)
944  item = highlight;
945  trackedItem = item;
946  if (trackedItem)
947  q->trackedPositionChanged();
948 }
949 
951 {
953  bool changed = false;
954  if (highlight) {
955  if (trackedItem == highlight)
956  trackedItem = 0;
957  if (highlight->item->scene())
958  highlight->item->scene()->removeItem(highlight->item);
959  highlight->item->deleteLater();
960  delete highlight;
961  highlight = 0;
962  delete highlightPosAnimator;
963  delete highlightSizeAnimator;
964  highlightPosAnimator = 0;
965  highlightSizeAnimator = 0;
966  changed = true;
967  }
968 
969  if (currentItem) {
970  QDeclarativeItem *item = 0;
971  if (highlightComponent) {
972  item = createComponentItem(highlightComponent);
973  } else {
974  item = new QDeclarativeItem;
975  }
976  if (item) {
977  QDeclarative_setParent_noEvent(item, q->contentItem());
978  item->setParentItem(q->contentItem());
979  highlight = new FxListItem(item, q);
980  if (currentItem && autoHighlight) {
981  if (orient == QDeclarativeListView::Vertical) {
982  highlight->item->setHeight(currentItem->item->height());
983  } else {
984  highlight->item->setWidth(currentItem->item->width());
985  }
986  highlight->setPosition(currentItem->itemPosition());
987  }
990  const QLatin1String posProp(orient == QDeclarativeListView::Vertical ? "y" : "x");
991  highlightPosAnimator = new QSmoothedAnimation(q);
992  highlightPosAnimator->target = QDeclarativeProperty(highlight->item, posProp);
993  highlightPosAnimator->velocity = highlightMoveSpeed;
994  highlightPosAnimator->userDuration = highlightMoveDuration;
995  const QLatin1String sizeProp(orient == QDeclarativeListView::Vertical ? "height" : "width");
996  highlightSizeAnimator = new QSmoothedAnimation(q);
997  highlightSizeAnimator->velocity = highlightResizeSpeed;
998  highlightSizeAnimator->userDuration = highlightResizeDuration;
999  highlightSizeAnimator->target = QDeclarativeProperty(highlight->item, sizeProp);
1000  if (autoHighlight) {
1001  highlightPosAnimator->restart();
1002  highlightSizeAnimator->restart();
1003  }
1004  changed = true;
1005  }
1006  }
1007  if (changed)
1008  emit q->highlightItemChanged();
1009 }
1010 
1012 {
1013  if ((!currentItem && highlight) || (currentItem && !highlight))
1014  createHighlight();
1015  if (currentItem && autoHighlight && highlight && !hData.moving && !vData.moving) {
1016  // auto-update highlight
1017  highlightPosAnimator->to = isRightToLeft()
1018  ? -currentItem->itemPosition()-currentItem->itemSize()
1019  : currentItem->itemPosition();
1020  highlightSizeAnimator->to = currentItem->itemSize();
1021  if (orient == QDeclarativeListView::Vertical) {
1022  if (highlight->item->width() == 0)
1023  highlight->item->setWidth(currentItem->item->width());
1024  } else {
1025  if (highlight->item->height() == 0)
1026  highlight->item->setHeight(currentItem->item->height());
1027  }
1028  highlightPosAnimator->restart();
1029  highlightSizeAnimator->restart();
1030  }
1031  updateTrackedItem();
1032 }
1033 
1035 {
1037  if (!sectionCriteria || !sectionCriteria->delegate())
1038  return;
1039  if (listItem->attached->m_prevSection != listItem->attached->m_section) {
1040  if (!listItem->section) {
1041  qreal pos = listItem->position();
1042  int i = sectionCacheSize-1;
1043  while (i >= 0 && !sectionCache[i])
1044  --i;
1045  if (i >= 0) {
1046  listItem->section = sectionCache[i];
1047  sectionCache[i] = 0;
1048  listItem->section->setVisible(true);
1050  context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
1051  } else {
1053  context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
1054  QObject *nobj = sectionCriteria->delegate()->beginCreate(context);
1055  if (nobj) {
1056  QDeclarative_setParent_noEvent(context, nobj);
1057  listItem->section = qobject_cast<QDeclarativeItem *>(nobj);
1058  if (!listItem->section) {
1059  delete nobj;
1060  } else {
1061  listItem->section->setZValue(1);
1062  QDeclarative_setParent_noEvent(listItem->section, q->contentItem());
1063  listItem->section->setParentItem(q->contentItem());
1064  }
1065  } else {
1066  delete context;
1067  }
1068  sectionCriteria->delegate()->completeCreate();
1069  }
1070  listItem->setPosition(pos);
1071  } else {
1073  context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
1074  }
1075  } else if (listItem->section) {
1076  qreal pos = listItem->position();
1077  int i = 0;
1078  do {
1079  if (!sectionCache[i]) {
1080  sectionCache[i] = listItem->section;
1081  sectionCache[i]->setVisible(false);
1082  listItem->section = 0;
1083  return;
1084  }
1085  ++i;
1086  } while (i < sectionCacheSize);
1087  delete listItem->section;
1088  listItem->section = 0;
1089  listItem->setPosition(pos);
1090  }
1091 }
1092 
1094 {
1095  if (sectionCriteria && !visibleItems.isEmpty()) {
1096  QString prevSection;
1097  if (visibleIndex > 0)
1098  prevSection = sectionAt(visibleIndex-1);
1099  QDeclarativeListViewAttached *prevAtt = 0;
1100  int idx = -1;
1101  for (int i = 0; i < visibleItems.count(); ++i) {
1102  QDeclarativeListViewAttached *attached = visibleItems.at(i)->attached;
1103  attached->setPrevSection(prevSection);
1104  if (visibleItems.at(i)->index != -1) {
1105  QString propValue = model->stringValue(visibleItems.at(i)->index, sectionCriteria->property());
1106  attached->setSection(sectionCriteria->sectionString(propValue));
1107  idx = visibleItems.at(i)->index;
1108  }
1109  createSection(visibleItems.at(i));
1110  if (prevAtt)
1111  prevAtt->setNextSection(attached->section());
1112  prevSection = attached->section();
1113  prevAtt = attached;
1114  }
1115  if (prevAtt) {
1116  if (idx > 0 && idx < model->count()-1)
1117  prevAtt->setNextSection(sectionAt(idx+1));
1118  else
1119  prevAtt->setNextSection(QString());
1120  }
1121  }
1122 }
1123 
1125 {
1127  if (!sectionCriteria || visibleItems.isEmpty()) {
1128  if (!currentSection.isEmpty()) {
1129  currentSection.clear();
1130  emit q->currentSectionChanged();
1131  }
1132  return;
1133  }
1134  int index = 0;
1135  while (index < visibleItems.count() && visibleItems.at(index)->endPosition() < position())
1136  ++index;
1137 
1138  QString newSection = currentSection;
1139  if (index < visibleItems.count())
1140  newSection = visibleItems.at(index)->attached->section();
1141  else
1142  newSection = visibleItems.first()->attached->section();
1143  if (newSection != currentSection) {
1144  currentSection = newSection;
1145  emit q->currentSectionChanged();
1146  }
1147 }
1148 
1150 {
1152  if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
1153  if (currentItem) {
1154  currentItem->attached->setIsCurrentItem(false);
1155  releaseItem(currentItem);
1156  currentItem = 0;
1157  currentIndex = modelIndex;
1158  emit q->currentIndexChanged();
1159  updateHighlight();
1160  } else if (currentIndex != modelIndex) {
1161  currentIndex = modelIndex;
1162  emit q->currentIndexChanged();
1163  }
1164  return;
1165  }
1166 
1167  if (currentItem && currentIndex == modelIndex) {
1168  updateHighlight();
1169  return;
1170  }
1171  FxListItem *oldCurrentItem = currentItem;
1172  currentIndex = modelIndex;
1173  currentItem = createItem(modelIndex);
1174  if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
1175  oldCurrentItem->attached->setIsCurrentItem(false);
1176  if (currentItem) {
1177  if (modelIndex == visibleIndex - 1 && visibleItems.count()) {
1178  // We can calculate exact postion in this case
1179  currentItem->setPosition(visibleItems.first()->position() - currentItem->size() - spacing);
1180  } else {
1181  // Create current item now and position as best we can.
1182  // Its position will be corrected when it becomes visible.
1183  currentItem->setPosition(positionAt(modelIndex));
1184  }
1185  currentItem->item->setFocus(true);
1186  currentItem->attached->setIsCurrentItem(true);
1187  // Avoid showing section delegate twice. We still need the section heading so that
1188  // currentItem positioning works correctly.
1189  // This is slightly sub-optimal, but section heading caching minimizes the impact.
1190  if (currentItem->section)
1191  currentItem->section->setVisible(false);
1192  if (visibleItems.isEmpty())
1193  averageSize = currentItem->size();
1194  }
1195  updateHighlight();
1196  emit q->currentIndexChanged();
1197  // Release the old current item
1198  releaseItem(oldCurrentItem);
1199 }
1200 
1202 {
1203  if (!visibleItems.count())
1204  return;
1205  qreal sum = 0.0;
1206  for (int i = 0; i < visibleItems.count(); ++i)
1207  sum += visibleItems.at(i)->size();
1208  averageSize = qRound(sum / visibleItems.count());
1209 }
1210 
1212 {
1214  if (!footer && footerComponent) {
1215  QDeclarativeItem *item = createComponentItem(footerComponent);
1216  if (item) {
1217  QDeclarative_setParent_noEvent(item, q->contentItem());
1218  item->setParentItem(q->contentItem());
1219  item->setZValue(1);
1222  footer = new FxListItem(item, q);
1223  }
1224  }
1225  if (footer) {
1226  if (visibleItems.count()) {
1227  qreal endPos = lastPosition() + 1;
1228  if (lastVisibleIndex() == model->count()-1) {
1229  footer->setPosition(endPos);
1230  } else {
1231  qreal visiblePos = position() + q->height();
1232  if (endPos <= visiblePos || footer->position() < endPos)
1233  footer->setPosition(endPos);
1234  }
1235  } else {
1236  footer->setPosition(visiblePos);
1237  }
1238  }
1239 }
1240 
1242 {
1244  if (!header && headerComponent) {
1245  QDeclarativeItem *item = createComponentItem(headerComponent);
1246  if (item) {
1247  QDeclarative_setParent_noEvent(item, q->contentItem());
1248  item->setParentItem(q->contentItem());
1249  item->setZValue(1);
1252  header = new FxListItem(item, q);
1253  }
1254  }
1255  if (header) {
1256  if (visibleItems.count()) {
1257  qreal startPos = originPosition();
1258  if (visibleIndex == 0) {
1259  header->setPosition(startPos - header->size());
1260  } else {
1261  if (position() <= startPos || header->position() > startPos - header->size())
1262  header->setPosition(startPos - header->size());
1263  }
1264  } else {
1265  if (itemCount == 0)
1266  visiblePos = header->size();
1267  header->setPosition(0);
1268  }
1269  }
1270 }
1271 
1273 {
1274  if ((haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange)
1275  || snapMode != QDeclarativeListView::NoSnap)
1276  moveReason = Other;
1277  if (orient == QDeclarativeListView::Vertical)
1278  fixupY();
1279  else
1280  fixupX();
1281 }
1282 
1284 {
1285  if ((orient == QDeclarativeListView::Horizontal && &data == &vData)
1286  || (orient == QDeclarativeListView::Vertical && &data == &hData))
1287  return;
1288 
1289  correctFlick = false;
1290  fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1291  bool strictHighlightRange = haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange;
1292 
1293  qreal highlightStart;
1294  qreal highlightEnd;
1295  qreal viewPos;
1296  if (isRightToLeft()) {
1297  // Handle Right-To-Left exceptions
1298  viewPos = -position()-size();
1299  highlightStart = highlightRangeStartValid ? size() - highlightRangeEnd : highlightRangeStart;
1300  highlightEnd = highlightRangeEndValid ? size() - highlightRangeStart : highlightRangeEnd;
1301  } else {
1302  viewPos = position();
1303  highlightStart = highlightRangeStart;
1304  highlightEnd = highlightRangeEnd;
1305  }
1306 
1307  if (snapMode != QDeclarativeListView::NoSnap && moveReason != QDeclarativeListViewPrivate::SetIndex) {
1308  qreal tempPosition = isRightToLeft() ? -position()-size() : position();
1309  if (snapMode == QDeclarativeListView::SnapOneItem && moveReason == Mouse) {
1310  // if we've been dragged < averageSize/2 then bias towards the next item
1311  qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1312  qreal bias = 0;
1313  if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < averageSize/2)
1314  bias = averageSize/2;
1315  else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -averageSize/2)
1316  bias = -averageSize/2;
1317  if (isRightToLeft())
1318  bias = -bias;
1319  tempPosition -= bias;
1320  }
1321  FxListItem *topItem = snapItemAt(tempPosition+highlightStart);
1322  if (!topItem && strictHighlightRange && currentItem) {
1323  // StrictlyEnforceRange always keeps an item in range
1324  updateHighlight();
1325  topItem = currentItem;
1326  }
1327  FxListItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
1328  if (!bottomItem && strictHighlightRange && currentItem) {
1329  // StrictlyEnforceRange always keeps an item in range
1330  updateHighlight();
1331  bottomItem = currentItem;
1332  }
1333  qreal pos;
1334  bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1335  if (topItem && (isInBounds || strictHighlightRange)) {
1336  if (topItem->index == 0 && header && tempPosition+highlightStart < header->position()+header->size()/2 && !strictHighlightRange) {
1337  pos = isRightToLeft() ? - header->position() + highlightStart - size() : header->position() - highlightStart;
1338  } else {
1339  if (isRightToLeft())
1340  pos = qMax(qMin(-topItem->position() + highlightStart - size(), -maxExtent), -minExtent);
1341  else
1342  pos = qMax(qMin(topItem->position() - highlightStart, -maxExtent), -minExtent);
1343  }
1344  } else if (bottomItem && isInBounds) {
1345  if (isRightToLeft())
1346  pos = qMax(qMin(-bottomItem->position() + highlightEnd - size(), -maxExtent), -minExtent);
1347  else
1348  pos = qMax(qMin(bottomItem->position() - highlightEnd, -maxExtent), -minExtent);
1349  } else {
1350  QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
1351  return;
1352  }
1353 
1354  qreal dist = qAbs(data.move + pos);
1355  if (dist > 0) {
1356  timeline.reset(data.move);
1357  if (fixupMode != Immediate) {
1358  timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1359  data.fixingUp = true;
1360  } else {
1361  timeline.set(data.move, -pos);
1362  }
1363  vTime = timeline.time();
1364  }
1365  } else if (currentItem && strictHighlightRange
1366  && moveReason != QDeclarativeListViewPrivate::SetIndex) {
1367  updateHighlight();
1368  qreal pos = currentItem->itemPosition();
1369  if (viewPos < pos + currentItem->itemSize() - highlightEnd)
1370  viewPos = pos + currentItem->itemSize() - highlightEnd;
1371  if (viewPos > pos - highlightStart)
1372  viewPos = pos - highlightStart;
1373  if (isRightToLeft())
1374  viewPos = -viewPos-size();
1375 
1376  timeline.reset(data.move);
1377  if (viewPos != position()) {
1378  if (fixupMode != Immediate) {
1379  timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1380  data.fixingUp = true;
1381  } else {
1382  timeline.set(data.move, -viewPos);
1383  }
1384  }
1385  vTime = timeline.time();
1386  } else {
1387  QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
1388  }
1389  data.inOvershoot = false;
1390  fixupMode = Normal;
1391 }
1392 
1394  QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
1395 {
1397 
1398  data.fixingUp = false;
1399  moveReason = Mouse;
1400  if ((!haveHighlightRange || highlightRange != QDeclarativeListView::StrictlyEnforceRange) && snapMode == QDeclarativeListView::NoSnap) {
1401  correctFlick = true;
1402  QDeclarativeFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1403  return;
1404  }
1405  qreal maxDistance = 0;
1406  qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value();
1407  qreal highlightStart = isRightToLeft() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
1408  // -ve velocity means list is moving up/left
1409  if (velocity > 0) {
1410  if (data.move.value() < minExtent) {
1411  if (snapMode == QDeclarativeListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1412  // if we've been dragged < averageSize/2 then bias towards the next item
1413  qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1414  qreal bias = dist < averageSize/2 ? averageSize/2 : 0;
1415  if (isRightToLeft())
1416  bias = -bias;
1417  data.flickTarget = -snapPosAt(-(dataValue - highlightStart) - bias) + highlightStart;
1418  maxDistance = qAbs(data.flickTarget - data.move.value());
1419  velocity = maxVelocity;
1420  } else {
1421  maxDistance = qAbs(minExtent - data.move.value());
1422  }
1423  }
1424  if (snapMode == QDeclarativeListView::NoSnap && highlightRange != QDeclarativeListView::StrictlyEnforceRange)
1425  data.flickTarget = minExtent;
1426  } else {
1427  if (data.move.value() > maxExtent) {
1428  if (snapMode == QDeclarativeListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1429  // if we've been dragged < averageSize/2 then bias towards the next item
1430  qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1431  qreal bias = -dist < averageSize/2 ? averageSize/2 : 0;
1432  if (isRightToLeft())
1433  bias = -bias;
1434  data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + bias) + highlightStart;
1435  maxDistance = qAbs(data.flickTarget - data.move.value());
1436  velocity = -maxVelocity;
1437  } else {
1438  maxDistance = qAbs(maxExtent - data.move.value());
1439  }
1440  }
1441  if (snapMode == QDeclarativeListView::NoSnap && highlightRange != QDeclarativeListView::StrictlyEnforceRange)
1442  data.flickTarget = maxExtent;
1443  }
1444 
1445  bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds;
1446 
1447  if (maxDistance > 0 || overShoot) {
1448  // These modes require the list to stop exactly on an item boundary.
1449  // The initial flick will estimate the boundary to stop on.
1450  // Since list items can have variable sizes, the boundary will be
1451  // reevaluated and adjusted as we approach the boundary.
1452  qreal v = velocity;
1453  if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1454  if (v < 0)
1455  v = -maxVelocity;
1456  else
1457  v = maxVelocity;
1458  }
1459  if (!hData.flicking && !vData.flicking) {
1460  // the initial flick - estimate boundary
1461  qreal accel = deceleration;
1462  qreal v2 = v * v;
1463  overshootDist = qreal(0.0);
1464  // + averageSize/4 to encourage moving at least one item in the flick direction
1465  qreal dist = v2 / (accel * qreal(2.0)) + averageSize/4;
1466  if (maxDistance > 0)
1467  dist = qMin(dist, maxDistance);
1468  if (v > 0)
1469  dist = -dist;
1470  if ((maxDistance > qreal(0.0) && v2 / (2.0f * maxDistance) < accel) || snapMode == QDeclarativeListView::SnapOneItem) {
1471  if (snapMode != QDeclarativeListView::SnapOneItem) {
1472  qreal distTemp = isRightToLeft() ? -dist : dist;
1473  data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
1474  }
1475  data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
1476  if (overShoot) {
1477  if (data.flickTarget >= minExtent) {
1478  overshootDist = overShootDistance(vSize);
1479  data.flickTarget += overshootDist;
1480  } else if (data.flickTarget <= maxExtent) {
1481  overshootDist = overShootDistance(vSize);
1482  data.flickTarget -= overshootDist;
1483  }
1484  }
1485  qreal adjDist = -data.flickTarget + data.move.value();
1486  if (qAbs(adjDist) > qAbs(dist)) {
1487  // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1488  qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1489  if (adjv2 > v2) {
1490  v2 = adjv2;
1491  v = qSqrt(v2);
1492  if (dist > 0)
1493  v = -v;
1494  }
1495  }
1496  dist = adjDist;
1497  accel = v2 / (2.0f * qAbs(dist));
1498  } else if (overShoot) {
1499  data.flickTarget = data.move.value() - dist;
1500  if (data.flickTarget >= minExtent) {
1501  overshootDist = overShootDistance(vSize);
1502  data.flickTarget += overshootDist;
1503  } else if (data.flickTarget <= maxExtent) {
1504  overshootDist = overShootDistance(vSize);
1505  data.flickTarget -= overshootDist;
1506  }
1507  }
1508 
1509  timeline.reset(data.move);
1510  timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1511  timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1512  if (!hData.flicking && q->xflick()) {
1513  hData.flicking = true;
1514  emit q->flickingChanged();
1515  emit q->flickingHorizontallyChanged();
1516  emit q->flickStarted();
1517  }
1518  if (!vData.flicking && q->yflick()) {
1519  vData.flicking = true;
1520  emit q->flickingChanged();
1521  emit q->flickingVerticallyChanged();
1522  emit q->flickStarted();
1523  }
1524  correctFlick = true;
1525  } else {
1526  // reevaluate the target boundary.
1527  qreal newtarget = data.flickTarget;
1528  if (snapMode != QDeclarativeListView::NoSnap || highlightRange == QDeclarativeListView::StrictlyEnforceRange) {
1529  qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
1530  newtarget = -snapPosAt(-(tempFlickTarget - highlightStart)) + highlightStart;
1531  newtarget = isRightToLeft() ? -newtarget+size() : newtarget;
1532  }
1533  if (velocity < 0 && newtarget <= maxExtent)
1534  newtarget = maxExtent - overshootDist;
1535  else if (velocity > 0 && newtarget >= minExtent)
1536  newtarget = minExtent + overshootDist;
1537  if (newtarget == data.flickTarget) { // boundary unchanged - nothing to do
1538  if (qAbs(velocity) < MinimumFlickVelocity)
1539  correctFlick = false;
1540  return;
1541  }
1542  data.flickTarget = newtarget;
1543  qreal dist = -newtarget + data.move.value();
1544  if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
1545  correctFlick = false;
1546  timeline.reset(data.move);
1547  fixup(data, minExtent, maxExtent);
1548  return;
1549  }
1550 
1551  timeline.reset(data.move);
1552  timeline.accelDistance(data.move, v, -dist);
1553  timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1554  }
1555  } else {
1556  correctFlick = false;
1557  timeline.reset(data.move);
1558  fixup(data, minExtent, maxExtent);
1559  }
1560 }
1561 
1562 //----------------------------------------------------------------------------
1563 
1632 {
1634  d->init();
1635 }
1636 
1638 {
1640  d->clear();
1641  if (d->ownModel)
1642  delete d->model;
1643  delete d->header;
1644  delete d->footer;
1645 }
1646 
1756 {
1757  Q_D(const QDeclarativeListView);
1758  return d->modelVariant;
1759 }
1760 
1762 {
1764  if (d->modelVariant == model)
1765  return;
1766  if (d->model) {
1767  disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1768  disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1769  disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1770  disconnect(d->model, SIGNAL(itemsChanged(int,int)), this, SLOT(itemsChanged(int,int)));
1771  disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1774  }
1775  d->clear();
1776  QDeclarativeVisualModel *oldModel = d->model;
1777  d->model = 0;
1778  d->setPosition(0);
1779  d->modelVariant = model;
1780  QObject *object = qvariant_cast<QObject*>(model);
1781  QDeclarativeVisualModel *vim = 0;
1782  if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
1783  if (d->ownModel) {
1784  delete oldModel;
1785  d->ownModel = false;
1786  }
1787  d->model = vim;
1788  } else {
1789  if (!d->ownModel) {
1790  d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
1791  d->ownModel = true;
1792  } else {
1793  d->model = oldModel;
1794  }
1795  if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
1796  dataModel->setModel(model);
1797  }
1798  if (d->model) {
1800  if (isComponentComplete()) {
1801  updateSections();
1802  refill();
1803  if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
1804  setCurrentIndex(0);
1805  } else {
1807  d->updateCurrent(d->currentIndex);
1808  if (d->highlight && d->currentItem) {
1809  if (d->autoHighlight)
1810  d->highlight->setPosition(d->currentItem->position());
1811  d->updateTrackedItem();
1812  }
1813  }
1814  d->updateViewport();
1815  }
1816  connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1817  connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1818  connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1819  connect(d->model, SIGNAL(itemsChanged(int,int)), this, SLOT(itemsChanged(int,int)));
1820  connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1823  emit countChanged();
1824  }
1825  emit modelChanged();
1826 }
1827 
1853 {
1854  Q_D(const QDeclarativeListView);
1855  if (d->model) {
1856  if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
1857  return dataModel->delegate();
1858  }
1859 
1860  return 0;
1861 }
1862 
1864 {
1866  if (delegate == this->delegate())
1867  return;
1868  if (!d->ownModel) {
1869  d->model = new QDeclarativeVisualDataModel(qmlContext(this));
1870  d->ownModel = true;
1871  }
1872  if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model)) {
1873  int oldCount = dataModel->count();
1874  dataModel->setDelegate(delegate);
1875  if (isComponentComplete()) {
1876  for (int i = 0; i < d->visibleItems.count(); ++i)
1877  d->releaseItem(d->visibleItems.at(i));
1878  d->visibleItems.clear();
1879  d->releaseItem(d->currentItem);
1880  d->currentItem = 0;
1881  updateSections();
1882  refill();
1884  d->updateCurrent(d->currentIndex);
1885  if (d->highlight && d->currentItem) {
1886  if (d->autoHighlight)
1887  d->highlight->setPosition(d->currentItem->position());
1888  d->updateTrackedItem();
1889  }
1890  d->updateViewport();
1891  }
1892  if (oldCount != dataModel->count())
1893  emit countChanged();
1894  }
1896 }
1897 
1917 {
1918  Q_D(const QDeclarativeListView);
1919  return d->currentIndex;
1920 }
1921 
1923 {
1925  if (d->requestedIndex >= 0) // currently creating item
1926  return;
1927  d->currentIndexCleared = (index == -1);
1928  if (index == d->currentIndex)
1929  return;
1930  if (isComponentComplete() && d->isValid()) {
1931  if (d->layoutScheduled)
1932  d->layout();
1934  d->updateCurrent(index);
1935  } else if (d->currentIndex != index) {
1936  d->currentIndex = index;
1938  }
1939 }
1940 
1942 {
1944  if (!d->currentItem)
1945  return 0;
1946  return d->currentItem->item;
1947 }
1948 
1963 {
1965  if (!d->highlight)
1966  return 0;
1967  return d->highlight->item;
1968 }
1969 
1977 int QDeclarativeListView::count() const
1978 {
1979  Q_D(const QDeclarativeListView);
1980  if (d->model)
1981  return d->model->count();
1982  return 0;
1983 }
1984 
2000 {
2001  Q_D(const QDeclarativeListView);
2002  return d->highlightComponent;
2003 }
2004 
2006 {
2008  if (highlight != d->highlightComponent) {
2009  d->highlightComponent = highlight;
2010  d->createHighlight();
2011  if (d->currentItem)
2012  d->updateHighlight();
2014  }
2015 }
2016 
2040 {
2041  Q_D(const QDeclarativeListView);
2042  return d->autoHighlight;
2043 }
2044 
2046 {
2048  if (d->autoHighlight != autoHighlight) {
2049  d->autoHighlight = autoHighlight;
2050  if (autoHighlight) {
2051  d->updateHighlight();
2052  } else {
2053  if (d->highlightPosAnimator)
2054  d->highlightPosAnimator->stop();
2055  if (d->highlightSizeAnimator)
2056  d->highlightSizeAnimator->stop();
2057  }
2059  }
2060 }
2061 
2062 //###Possibly rename these properties, since they are very useful even without a highlight?
2097 {
2098  Q_D(const QDeclarativeListView);
2099  return d->highlightRangeStart;
2100 }
2101 
2103 {
2105  d->highlightRangeStartValid = true;
2106  if (d->highlightRangeStart == start)
2107  return;
2108  d->highlightRangeStart = start;
2109  d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
2111 }
2112 
2114 {
2116  d->highlightRangeStartValid = false;
2117  if (d->highlightRangeStart == 0)
2118  return;
2119  d->highlightRangeStart = 0;
2121 }
2122 
2124 {
2125  Q_D(const QDeclarativeListView);
2126  return d->highlightRangeEnd;
2127 }
2128 
2130 {
2132  d->highlightRangeEndValid = true;
2133  if (d->highlightRangeEnd == end)
2134  return;
2135  d->highlightRangeEnd = end;
2136  d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
2138 }
2139 
2141 {
2143  d->highlightRangeEndValid = false;
2144  if (d->highlightRangeEnd == 0)
2145  return;
2146  d->highlightRangeEnd = 0;
2148 }
2149 
2151 {
2152  Q_D(const QDeclarativeListView);
2153  return d->highlightRange;
2154 }
2155 
2157 {
2159  if (d->highlightRange == mode)
2160  return;
2161  d->highlightRange = mode;
2162  d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
2164 }
2165 
2177 {
2178  Q_D(const QDeclarativeListView);
2179  return d->spacing;
2180 }
2181 
2183 {
2185  if (spacing != d->spacing) {
2186  d->spacing = spacing;
2187  d->layout();
2188  emit spacingChanged();
2189  }
2190 }
2191 
2217 {
2218  Q_D(const QDeclarativeListView);
2219  return d->orient;
2220 }
2221 
2223 {
2225  if (d->orient != orientation) {
2226  d->orient = orientation;
2227  if (d->orient == QDeclarativeListView::Vertical) {
2228  setContentWidth(-1);
2230  setContentX(0);
2231  } else {
2232  setContentHeight(-1);
2234  setContentY(0);
2235  }
2236  d->regenerate();
2238  }
2239 }
2240 
2264 {
2265  Q_D(const QDeclarativeListView);
2266  return d->layoutDirection;
2267 }
2268 
2270 {
2272  if (d->layoutDirection != layoutDirection) {
2273  d->layoutDirection = layoutDirection;
2274  d->regenerate();
2276  }
2277 }
2278 
2280 {
2281  Q_D(const QDeclarativeListView);
2282  if (d->effectiveLayoutMirror)
2283  return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
2284  else
2285  return d->layoutDirection;
2286 }
2287 
2302 {
2303  Q_D(const QDeclarativeListView);
2304  return d->wrap;
2305 }
2306 
2308 {
2310  if (d->wrap == wrap)
2311  return;
2312  d->wrap = wrap;
2314 }
2315 
2339 {
2340  Q_D(const QDeclarativeListView);
2341  return d->buffer;
2342 }
2343 
2345 {
2347  if (d->buffer != b) {
2348  d->buffer = b;
2349  if (isComponentComplete()) {
2351  refill();
2352  }
2354  }
2355 }
2356 
2412 {
2414  if (!d->sectionCriteria) {
2415  d->sectionCriteria = new QDeclarativeViewSection(this);
2416  connect(d->sectionCriteria, SIGNAL(propertyChanged()), this, SLOT(updateSections()));
2417  }
2418  return d->sectionCriteria;
2419 }
2420 
2429 {
2430  Q_D(const QDeclarativeListView);
2431  return d->currentSection;
2432 }
2433 
2457 {
2458  Q_D(const QDeclarativeListView);\
2459  return d->highlightMoveSpeed;
2460 }
2461 
2463 {
2465  if (d->highlightMoveSpeed != speed) {
2466  d->highlightMoveSpeed = speed;
2467  if (d->highlightPosAnimator)
2468  d->highlightPosAnimator->velocity = d->highlightMoveSpeed;
2470  }
2471 }
2472 
2474 {
2475  Q_D(const QDeclarativeListView);
2476  return d->highlightMoveDuration;
2477 }
2478 
2480 {
2482  if (d->highlightMoveDuration != duration) {
2483  d->highlightMoveDuration = duration;
2484  if (d->highlightPosAnimator)
2485  d->highlightPosAnimator->userDuration = d->highlightMoveDuration;
2487  }
2488 }
2489 
2491 {
2492  Q_D(const QDeclarativeListView);\
2493  return d->highlightResizeSpeed;
2494 }
2495 
2497 {
2499  if (d->highlightResizeSpeed != speed) {
2500  d->highlightResizeSpeed = speed;
2501  if (d->highlightSizeAnimator)
2502  d->highlightSizeAnimator->velocity = d->highlightResizeSpeed;
2504  }
2505 }
2506 
2508 {
2509  Q_D(const QDeclarativeListView);
2510  return d->highlightResizeDuration;
2511 }
2512 
2514 {
2516  if (d->highlightResizeDuration != duration) {
2517  d->highlightResizeDuration = duration;
2518  if (d->highlightSizeAnimator)
2519  d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
2521  }
2522 }
2523 
2549 {
2550  Q_D(const QDeclarativeListView);
2551  return d->snapMode;
2552 }
2553 
2555 {
2557  if (d->snapMode != mode) {
2558  d->snapMode = mode;
2560  }
2561 }
2562 
2576 {
2577  Q_D(const QDeclarativeListView);
2578  return d->footerComponent;
2579 }
2580 
2582 {
2584  if (d->footerComponent != footer) {
2585  if (d->footer) {
2586  if (scene())
2587  scene()->removeItem(d->footer->item);
2588  d->footer->item->deleteLater();
2589  delete d->footer;
2590  d->footer = 0;
2591  }
2592  d->footerComponent = footer;
2593  d->minExtentDirty = true;
2594  d->maxExtentDirty = true;
2595  if (isComponentComplete()) {
2596  d->updateFooter();
2597  d->updateViewport();
2598  d->fixupPosition();
2599  }
2600  emit footerChanged();
2601  }
2602 }
2603 
2617 {
2618  Q_D(const QDeclarativeListView);
2619  return d->headerComponent;
2620 }
2621 
2623 {
2625  if (d->headerComponent != header) {
2626  if (d->header) {
2627  if (scene())
2628  scene()->removeItem(d->header->item);
2629  d->header->item->deleteLater();
2630  delete d->header;
2631  d->header = 0;
2632  }
2633  d->headerComponent = header;
2634  d->minExtentDirty = true;
2635  d->maxExtentDirty = true;
2636  if (isComponentComplete()) {
2637  d->updateHeader();
2638  d->updateFooter();
2639  d->updateViewport();
2640  d->fixupPosition();
2641  }
2642  emit headerChanged();
2643  }
2644 }
2645 
2647 {
2649  // Positioning the view manually should override any current movement state
2650  d->moveReason = QDeclarativeListViewPrivate::Other;
2652 }
2653 
2655 {
2657  // Positioning the view manually should override any current movement state
2658  d->moveReason = QDeclarativeListViewPrivate::Other;
2660 }
2661 
2663 {
2665  if (event->type() == QEvent::User) {
2666  if (d->layoutScheduled)
2667  d->layout();
2668  return true;
2669  }
2670 
2671  return QDeclarativeFlickable::event(event);
2672 }
2673 
2675 {
2678  if (!d->itemCount)
2679  return;
2680  // Recursion can occur due to refill changing the content size.
2681  if (d->inViewportMoved)
2682  return;
2683  d->inViewportMoved = true;
2684  d->lazyRelease = true;
2685  refill();
2686  if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2687  d->moveReason = QDeclarativeListViewPrivate::Mouse;
2688  if (d->moveReason != QDeclarativeListViewPrivate::SetIndex) {
2689  if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2690  // reposition highlight
2691  qreal pos = d->highlight->position();
2692  qreal viewPos;
2693  qreal highlightStart;
2694  qreal highlightEnd;
2695  if (d->isRightToLeft()) {
2696  // Handle Right-To-Left exceptions
2697  viewPos = -d->position()-d->size();
2698  highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
2699  highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
2700  } else {
2701  viewPos = d->position();
2702  highlightStart = d->highlightRangeStart;
2703  highlightEnd = d->highlightRangeEnd;
2704  }
2705  if (pos > viewPos + highlightEnd - d->highlight->size())
2706  pos = viewPos + highlightEnd - d->highlight->size();
2707  if (pos < viewPos + highlightStart)
2708  pos = viewPos + highlightStart;
2709  d->highlightPosAnimator->stop();
2710  d->highlight->setPosition(qRound(pos));
2711 
2712  // update current index
2713  if (FxListItem *snapItem = d->snapItemAt(d->highlight->position())) {
2714  if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
2715  d->updateCurrent(snapItem->index);
2716  }
2717  }
2718  }
2719 
2720  if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
2721  d->inFlickCorrection = true;
2722  // Near an end and it seems that the extent has changed?
2723  // Recalculate the flick so that we don't end up in an odd position.
2724  if (yflick() && !d->vData.inOvershoot) {
2725  if (d->vData.velocity > 0) {
2726  const qreal minY = minYExtent();
2727  if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
2728  && minY != d->vData.flickTarget)
2729  d->flickY(-d->vData.smoothVelocity.value());
2731  } else if (d->vData.velocity < 0) {
2732  const qreal maxY = maxYExtent();
2733  if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
2734  && maxY != d->vData.flickTarget)
2735  d->flickY(-d->vData.smoothVelocity.value());
2737  }
2738  }
2739 
2740  if (xflick() && !d->hData.inOvershoot) {
2741  if (d->hData.velocity > 0) {
2742  const qreal minX = minXExtent();
2743  if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
2744  && minX != d->hData.flickTarget)
2745  d->flickX(-d->hData.smoothVelocity.value());
2746  d->bufferMode = d->isRightToLeft()
2748  } else if (d->hData.velocity < 0) {
2749  const qreal maxX = maxXExtent();
2750  if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
2751  && maxX != d->hData.flickTarget)
2752  d->flickX(-d->hData.smoothVelocity.value());
2753  d->bufferMode = d->isRightToLeft()
2755  }
2756  }
2757  d->inFlickCorrection = false;
2758  }
2759  d->inViewportMoved = false;
2760 }
2761 
2763 {
2764  Q_D(const QDeclarativeListView);
2765  if (d->orient == QDeclarativeListView::Horizontal)
2767  if (d->minExtentDirty) {
2768  d->minExtent = -d->startPosition();
2769  if (d->header && d->visibleItems.count())
2770  d->minExtent += d->header->size();
2771  if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2772  d->minExtent += d->highlightRangeStart;
2773  if (d->sectionCriteria) {
2774  if (d->visibleItem(0))
2775  d->minExtent -= d->visibleItem(0)->sectionSize();
2776  }
2777  d->minExtent = qMax(d->minExtent, -(d->endPositionAt(0) - d->highlightRangeEnd + 1));
2778  }
2779  d->minExtentDirty = false;
2780  }
2781 
2782  return d->minExtent;
2783 }
2784 
2786 {
2787  Q_D(const QDeclarativeListView);
2788  if (d->orient == QDeclarativeListView::Horizontal)
2789  return height();
2790  if (d->maxExtentDirty) {
2791  if (!d->model || !d->model->count()) {
2792  d->maxExtent = d->header ? -d->header->size() : 0;
2793  d->maxExtent += height();
2794  } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2795  d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart);
2796  if (d->highlightRangeEnd != d->highlightRangeStart)
2797  d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd + 1));
2798  } else {
2799  d->maxExtent = -(d->endPosition() - height() + 1);
2800  }
2801  if (d->footer)
2802  d->maxExtent -= d->footer->size();
2803  qreal minY = minYExtent();
2804  if (d->maxExtent > minY)
2805  d->maxExtent = minY;
2806  d->maxExtentDirty = false;
2807  }
2808  return d->maxExtent;
2809 }
2810 
2812 {
2813  Q_D(const QDeclarativeListView);
2814  if (d->orient == QDeclarativeListView::Vertical)
2816  if (d->minExtentDirty) {
2817  d->minExtent = -d->startPosition();
2818 
2819  qreal highlightStart;
2820  qreal highlightEnd;
2821  qreal endPositionFirstItem = 0;
2822  if (d->isRightToLeft()) {
2823  if (d->model && d->model->count())
2824  endPositionFirstItem = d->positionAt(d->model->count()-1);
2825  else if (d->header)
2826  d->minExtent += d->header->size();
2827  highlightStart = d->highlightRangeStartValid
2828  ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
2829  : d->size() - (d->lastPosition()-endPositionFirstItem);
2830  highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
2831  if (d->footer)
2832  d->minExtent += d->footer->size();
2833  qreal maxX = maxXExtent();
2834  if (d->minExtent < maxX)
2835  d->minExtent = maxX;
2836  } else {
2837  endPositionFirstItem = d->endPositionAt(0);
2838  highlightStart = d->highlightRangeStart;
2839  highlightEnd = d->highlightRangeEnd;
2840  if (d->header && d->visibleItems.count())
2841  d->minExtent += d->header->size();
2842  }
2843  if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2844  d->minExtent += d->isRightToLeft() ? -highlightStart : highlightStart;
2845  d->minExtent = qMax(d->minExtent, -(endPositionFirstItem - highlightEnd + 1));
2846  }
2847  d->minExtentDirty = false;
2848  }
2849 
2850  return d->minExtent;
2851 }
2852 
2854 {
2855  Q_D(const QDeclarativeListView);
2856  if (d->orient == QDeclarativeListView::Vertical)
2857  return width();
2858  if (d->maxExtentDirty) {
2859  qreal highlightStart;
2860  qreal highlightEnd;
2861  qreal lastItemPosition = 0;
2862  d->maxExtent = 0;
2863  if (d->isRightToLeft()) {
2864  highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
2865  highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
2866  lastItemPosition = d->endPosition();
2867  } else {
2868  highlightStart = d->highlightRangeStart;
2869  highlightEnd = d->highlightRangeEnd;
2870  if (d->model && d->model->count())
2871  lastItemPosition = d->positionAt(d->model->count()-1);
2872  }
2873  if (!d->model || !d->model->count()) {
2874  if (!d->isRightToLeft())
2875  d->maxExtent = d->header ? -d->header->size() : 0;
2876  d->maxExtent += width();
2877  } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2878  d->maxExtent = -(lastItemPosition - highlightStart);
2879  if (highlightEnd != highlightStart) {
2880  d->maxExtent = d->isRightToLeft()
2881  ? qMax(d->maxExtent, -(d->endPosition() - highlightEnd + 1))
2882  : qMin(d->maxExtent, -(d->endPosition() - highlightEnd + 1));
2883  }
2884  } else {
2885  d->maxExtent = -(d->endPosition() - width() + 1);
2886  }
2887  if (d->isRightToLeft()) {
2888  if (d->header && d->visibleItems.count())
2889  d->maxExtent -= d->header->size();
2890  } else {
2891  if (d->footer)
2892  d->maxExtent -= d->footer->size();
2893  qreal minX = minXExtent();
2894  if (d->maxExtent > minX)
2895  d->maxExtent = minX;
2896  }
2897  d->maxExtentDirty = false;
2898  }
2899  return d->maxExtent;
2900 }
2901 
2903 {
2905  keyPressPreHandler(event);
2906  if (event->isAccepted())
2907  return;
2908 
2909  if (d->model && d->model->count() && d->interactive) {
2910  if ((d->orient == QDeclarativeListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left)
2911  || (d->orient == QDeclarativeListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right)
2912  || (d->orient == QDeclarativeListView::Vertical && event->key() == Qt::Key_Up)) {
2913  if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) {
2915  event->accept();
2916  return;
2917  } else if (d->wrap) {
2918  event->accept();
2919  return;
2920  }
2921  } else if ((d->orient == QDeclarativeListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right)
2922  || (d->orient == QDeclarativeListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left)
2923  || (d->orient == QDeclarativeListView::Vertical && event->key() == Qt::Key_Down)) {
2924  if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) {
2926  event->accept();
2927  return;
2928  } else if (d->wrap) {
2929  event->accept();
2930  return;
2931  }
2932  }
2933  }
2934  event->ignore();
2936 }
2937 
2939  const QRectF &oldGeometry)
2940 {
2942  d->maxExtentDirty = true;
2943  d->minExtentDirty = true;
2944  if (d->isRightToLeft() && d->orient == QDeclarativeListView::Horizontal) {
2945  // maintain position relative to the right edge
2946  int dx = newGeometry.width() - oldGeometry.width();
2947  setContentX(contentX() - dx);
2948  }
2949  QDeclarativeFlickable::geometryChanged(newGeometry, oldGeometry);
2950 }
2951 
2952 
2966 {
2968  int count = d->model ? d->model->count() : 0;
2969  if (count && (currentIndex() < count - 1 || d->wrap)) {
2971  int index = currentIndex()+1;
2972  setCurrentIndex((index >= 0 && index < count) ? index : 0);
2973  }
2974 }
2975 
2989 {
2991  int count = d->model ? d->model->count() : 0;
2992  if (count && (currentIndex() > 0 || d->wrap)) {
2994  int index = currentIndex()-1;
2995  setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2996  }
2997 }
2998 
3000 {
3002  if (!isValid())
3003  return;
3004  if (mode < QDeclarativeListView::Beginning || mode > QDeclarativeListView::Contain)
3005  return;
3006  int idx = qMax(qMin(index, model->count()-1), 0);
3007 
3008  if (layoutScheduled)
3009  layout();
3010  qreal pos = isRightToLeft() ? -position() - size() : position();
3011  FxListItem *item = visibleItem(idx);
3012  qreal maxExtent;
3013  if (orient == QDeclarativeListView::Vertical)
3014  maxExtent = -q->maxYExtent();
3015  else
3016  maxExtent = isRightToLeft() ? q->minXExtent()-size(): -q->maxXExtent();
3017 
3018  if (!item) {
3019  int itemPos = positionAt(idx);
3020  // save the currently visible items in case any of them end up visible again
3021  QList<FxListItem*> oldVisible = visibleItems;
3022  visibleItems.clear();
3023  visiblePos = itemPos;
3024  visibleIndex = idx;
3025  setPosition(qMin(qreal(itemPos), maxExtent));
3026  // now release the reference to all the old visible items.
3027  for (int i = 0; i < oldVisible.count(); ++i)
3028  releaseItem(oldVisible.at(i));
3029  item = visibleItem(idx);
3030  }
3031  if (item) {
3032  const qreal itemPos = item->position();
3033  switch (mode) {
3035  pos = itemPos;
3036  if (index < 0 && header)
3037  pos -= header->size();
3038  break;
3040  pos = itemPos - (size() - item->size())/2;
3041  break;
3043  pos = itemPos - size() + item->size();
3044  if (index >= model->count() && footer)
3045  pos += footer->size();
3046  break;
3048  if (itemPos > pos + size())
3049  pos = itemPos - size() + item->size();
3050  else if (item->endPosition() < pos)
3051  pos = itemPos;
3052  break;
3054  if (item->endPosition() > pos + size())
3055  pos = itemPos - size() + item->size();
3056  if (itemPos < pos)
3057  pos = itemPos;
3058  }
3059  pos = qMin(pos, maxExtent);
3060  qreal minExtent;
3061  if (orient == QDeclarativeListView::Vertical) {
3062  minExtent = -q->minYExtent();
3063  } else {
3064  minExtent = isRightToLeft() ? q->maxXExtent()-size(): -q->minXExtent();
3065  }
3066  pos = qMax(pos, minExtent);
3068  q->cancelFlick();
3069  setPosition(pos);
3070  if (highlight) {
3071  if (autoHighlight) {
3072  highlight->setPosition(currentItem->itemPosition());
3073  highlight->setSize(currentItem->itemSize());
3074  }
3075  updateHighlight();
3076  }
3077  }
3078  fixupPosition();
3079 }
3080 
3118 {
3120  if (!d->isValid() || index < 0 || index >= d->model->count())
3121  return;
3122  d->positionViewAtIndex(index, mode);
3123 }
3124 
3149 {
3151  if (!d->isValid())
3152  return;
3153  d->positionViewAtIndex(-1, Beginning);
3154 }
3155 
3157 {
3159  if (!d->isValid())
3160  return;
3161  d->positionViewAtIndex(d->model->count(), End);
3162 }
3163 
3180 {
3181  Q_D(const QDeclarativeListView);
3182  for (int i = 0; i < d->visibleItems.count(); ++i) {
3183  const FxListItem *listItem = d->visibleItems.at(i);
3184  if(listItem->contains(x, y))
3185  return listItem->index;
3186  }
3187 
3188  return -1;
3189 }
3190 
3192 {
3195  updateSections();
3196  d->updateHeader();
3197  d->updateFooter();
3198  if (d->isValid()) {
3199  refill();
3201  if (d->currentIndex < 0 && !d->currentIndexCleared)
3202  d->updateCurrent(0);
3203  else
3204  d->updateCurrent(d->currentIndex);
3205  if (d->highlight && d->currentItem) {
3206  if (d->autoHighlight)
3207  d->highlight->setPosition(d->currentItem->position());
3208  d->updateTrackedItem();
3209  }
3210  d->moveReason = QDeclarativeListViewPrivate::Other;
3211  d->fixupPosition();
3212  }
3213 }
3214 
3216 {
3218  if (isComponentComplete() && d->model) {
3219  QList<QByteArray> roles;
3220  if (d->sectionCriteria && !d->sectionCriteria->property().isEmpty())
3221  roles << d->sectionCriteria->property().toUtf8();
3222  d->model->setWatchedRoles(roles);
3223  d->updateSections();
3224  if (d->itemCount)
3225  d->layout();
3226  }
3227 }
3228 
3230 {
3232  if (d->isRightToLeft())
3233  d->refill(-d->position()-d->size()+1, -d->position());
3234  else
3235  d->refill(d->position(), d->position()+d->size()-1);
3236 }
3237 
3239 {
3241  if (!d->trackedItem || !d->currentItem)
3242  return;
3243  if (d->moveReason == QDeclarativeListViewPrivate::SetIndex) {
3244  qreal trackedPos = qCeil(d->trackedItem->position());
3245  qreal trackedSize = d->trackedItem->size();
3246  if (d->trackedItem != d->currentItem) {
3247  trackedPos -= d->currentItem->sectionSize();
3248  trackedSize += d->currentItem->sectionSize();
3249  }
3250  qreal viewPos;
3251  qreal highlightStart;
3252  qreal highlightEnd;
3253  if (d->isRightToLeft()) {
3254  viewPos = -d->position()-d->size();
3255  highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
3256  highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
3257  } else {
3258  viewPos = d->position();
3259  highlightStart = d->highlightRangeStart;
3260  highlightEnd = d->highlightRangeEnd;
3261  }
3262  qreal pos = viewPos;
3263  if (d->haveHighlightRange) {
3264  if (d->highlightRange == StrictlyEnforceRange) {
3265  if (trackedPos > pos + highlightEnd - d->trackedItem->size())
3266  pos = trackedPos - highlightEnd + d->trackedItem->size();
3267  if (trackedPos < pos + highlightStart)
3268  pos = trackedPos - highlightStart;
3269  } else {
3270  if (trackedPos < d->startPosition() + highlightStart) {
3271  pos = d->startPosition();
3272  } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + highlightEnd) {
3273  pos = d->endPosition() - d->size() + 1;
3274  if (pos < d->startPosition())
3275  pos = d->startPosition();
3276  } else {
3277  if (trackedPos < viewPos + highlightStart) {
3278  pos = trackedPos - highlightStart;
3279  } else if (trackedPos > viewPos + highlightEnd - trackedSize) {
3280  pos = trackedPos - highlightEnd + trackedSize;
3281  }
3282  }
3283  }
3284  } else {
3285  if (trackedPos < viewPos && d->currentItem->position() < viewPos) {
3286  pos = d->currentItem->position() < trackedPos ? trackedPos : d->currentItem->position();
3287  } else if (d->trackedItem->endPosition() >= viewPos + d->size()
3288  && d->currentItem->endPosition() >= viewPos + d->size()) {
3289  if (d->trackedItem->endPosition() <= d->currentItem->endPosition()) {
3290  pos = d->trackedItem->endPosition() - d->size() + 1;
3291  if (trackedSize > d->size())
3292  pos = trackedPos;
3293  } else {
3294  pos = d->currentItem->endPosition() - d->size() + 1;
3295  if (d->currentItem->size() > d->size())
3296  pos = d->currentItem->position();
3297  }
3298  }
3299  }
3300  if (viewPos != pos) {
3301  cancelFlick();
3302  d->calcVelocity = true;
3303  d->setPosition(pos);
3304  d->calcVelocity = false;
3305  }
3306  }
3307 }
3308 
3310 {
3312  if (!isComponentComplete())
3313  return;
3314  d->updateUnrequestedIndexes();
3315  d->moveReason = QDeclarativeListViewPrivate::Other;
3316 
3317  qreal tempPos = d->isRightToLeft() ? -d->position()-d->size() : d->position();
3318  int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
3319 
3320  if (index < 0) {
3321  int i = d->visibleItems.count() - 1;
3322  while (i > 0 && d->visibleItems.at(i)->index == -1)
3323  --i;
3324  if (i == 0 && d->visibleItems.first()->index == -1) {
3325  // there are no visible items except items marked for removal
3326  index = d->visibleItems.count();
3327  } else if (d->visibleItems.at(i)->index + 1 == modelIndex
3328  && d->visibleItems.at(i)->endPosition() < d->buffer+tempPos+d->size()-1) {
3329  // Special case of appending an item to the model.
3330  index = d->visibleItems.count();
3331  } else {
3332  if (modelIndex < d->visibleIndex) {
3333  // Insert before visible items
3334  d->visibleIndex += count;
3335  for (int i = 0; i < d->visibleItems.count(); ++i) {
3336  FxListItem *listItem = d->visibleItems.at(i);
3337  if (listItem->index != -1 && listItem->index >= modelIndex)
3338  listItem->index += count;
3339  }
3340  }
3341  if (d->currentIndex >= modelIndex) {
3342  // adjust current item index
3343  d->currentIndex += count;
3344  if (d->currentItem)
3345  d->currentItem->index = d->currentIndex;
3347  }
3348  d->scheduleLayout();
3349  d->itemCount += count;
3350  emit countChanged();
3351  return;
3352  }
3353  }
3354 
3355  // index can be the next item past the end of the visible items list (i.e. appended)
3356  int pos = 0;
3357  if (d->visibleItems.count()) {
3358  pos = index < d->visibleItems.count() ? d->visibleItems.at(index)->position()
3359  : d->visibleItems.last()->endPosition()+d->spacing+1;
3360  } else if (d->itemCount == 0 && d->header) {
3361  pos = d->header->size();
3362  }
3363 
3364  int initialPos = pos;
3365  int diff = 0;
3366  QList<FxListItem*> added;
3367  bool addedVisible = false;
3368  FxListItem *firstVisible = d->firstVisibleItem();
3369  if (firstVisible && pos < firstVisible->position()) {
3370  // Insert items before the visible item.
3371  int insertionIdx = index;
3372  int i = 0;
3373  int from = tempPos - d->buffer;
3374  for (i = count-1; i >= 0 && pos > from; --i) {
3375  if (!addedVisible) {
3376  d->scheduleLayout();
3377  addedVisible = true;
3378  }
3379  FxListItem *item = d->createItem(modelIndex + i);
3380  if (!item) {
3381  // broken or no delegate
3382  d->clear();
3383  return;
3384  }
3385  d->visibleItems.insert(insertionIdx, item);
3386  pos -= item->size() + d->spacing;
3387  item->setPosition(pos);
3388  index++;
3389  }
3390  if (i >= 0) {
3391  // If we didn't insert all our new items - anything
3392  // before the current index is not visible - remove it.
3393  while (insertionIdx--) {
3394  FxListItem *item = d->visibleItems.takeFirst();
3395  if (item->index != -1)
3396  d->visibleIndex++;
3397  d->releaseItem(item);
3398  }
3399  } else {
3400  // adjust pos of items before inserted items.
3401  for (int i = insertionIdx-1; i >= 0; i--) {
3402  FxListItem *listItem = d->visibleItems.at(i);
3403  listItem->setPosition(listItem->position() - (initialPos - pos));
3404  }
3405  }
3406  } else {
3407  int i = 0;
3408  int to = d->buffer+tempPos+d->size()-1;
3409  for (i = 0; i < count && pos <= to; ++i) {
3410  if (!addedVisible) {
3411  d->scheduleLayout();
3412  addedVisible = true;
3413  }
3414  FxListItem *item = d->createItem(modelIndex + i);
3415  if (!item) {
3416  // broken or no delegate
3417  d->clear();
3418  return;
3419  }
3420  d->visibleItems.insert(index, item);
3421  item->setPosition(pos);
3422  added.append(item);
3423  pos += item->size() + d->spacing;
3424  ++index;
3425  }
3426  if (i != count) {
3427  // We didn't insert all our new items, which means anything
3428  // beyond the current index is not visible - remove it.
3429  while (d->visibleItems.count() > index)
3430  d->releaseItem(d->visibleItems.takeLast());
3431  }
3432  diff = pos - initialPos;
3433  }
3434  if (d->itemCount && d->currentIndex >= modelIndex) {
3435  // adjust current item index
3436  d->currentIndex += count;
3437  if (d->currentItem) {
3438  d->currentItem->index = d->currentIndex;
3439  d->currentItem->setPosition(d->currentItem->position() + diff);
3440  }
3442  } else if (!d->itemCount && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
3443  d->updateCurrent(0);
3444  }
3445  // Update the indexes of the following visible items.
3446  for (; index < d->visibleItems.count(); ++index) {
3447  FxListItem *listItem = d->visibleItems.at(index);
3448  if (d->currentItem && listItem->item != d->currentItem->item)
3449  listItem->setPosition(listItem->position() + diff);
3450  if (listItem->index != -1)
3451  listItem->index += count;
3452  }
3453  // everything is in order now - emit add() signal
3454  for (int j = 0; j < added.count(); ++j)
3455  added.at(j)->attached->emitAdd();
3456 
3457  d->updateSections();
3458  d->itemCount += count;
3459  emit countChanged();
3460 }
3461 
3463 {
3465  if (!isComponentComplete())
3466  return;
3467  d->moveReason = QDeclarativeListViewPrivate::Other;
3468  d->updateUnrequestedIndexes();
3469  d->itemCount -= count;
3470 
3471  FxListItem *firstVisible = d->firstVisibleItem();
3472  int preRemovedSize = 0;
3473  bool removedVisible = false;
3474  // Remove the items from the visible list, skipping anything already marked for removal
3475  QList<FxListItem*>::Iterator it = d->visibleItems.begin();
3476  while (it != d->visibleItems.end()) {
3477  FxListItem *item = *it;
3478  if (item->index == -1 || item->index < modelIndex) {
3479  // already removed, or before removed items
3480  ++it;
3481  } else if (item->index >= modelIndex + count) {
3482  // after removed items
3483  item->index -= count;
3484  ++it;
3485  } else {
3486  // removed item
3487  if (!removedVisible) {
3488  d->scheduleLayout();
3489  removedVisible = true;
3490  }
3491  item->attached->emitRemove();
3492  if (item->attached->delayRemove()) {
3493  item->index = -1;
3494  connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
3495  ++it;
3496  } else {
3497  if (item == firstVisible)
3498  firstVisible = 0;
3499  if (firstVisible && item->position() < firstVisible->position())
3500  preRemovedSize += item->size();
3501  it = d->visibleItems.erase(it);
3502  d->releaseItem(item);
3503  }
3504  }
3505  }
3506 
3507  if (firstVisible && d->visibleItems.first() != firstVisible)
3508  d->visibleItems.first()->setPosition(d->visibleItems.first()->position() + preRemovedSize);
3509 
3510  // fix current
3511  if (d->currentIndex >= modelIndex + count) {
3512  d->currentIndex -= count;
3513  if (d->currentItem)
3514  d->currentItem->index -= count;
3516  } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
3517  // current item has been removed.
3518  d->currentItem->attached->setIsCurrentItem(false);
3519  d->releaseItem(d->currentItem);
3520  d->currentItem = 0;
3521  d->currentIndex = -1;
3522  if (d->itemCount)
3523  d->updateCurrent(qMin(modelIndex, d->itemCount-1));
3524  else
3526  }
3527 
3528  // update visibleIndex
3529  bool haveVisibleIndex = false;
3530  for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
3531  if ((*it)->index != -1) {
3532  d->visibleIndex = (*it)->index;
3533  haveVisibleIndex = true;
3534  break;
3535  }
3536  }
3537 
3538  if (!haveVisibleIndex) {
3539  d->timeline.clear();
3540  if (removedVisible && d->itemCount == 0) {
3541  d->visibleIndex = 0;
3542  d->visiblePos = d->header ? d->header->size() : 0;
3543  d->setPosition(0);
3544  d->updateHeader();
3545  d->updateFooter();
3546  update();
3547  } else {
3548  if (modelIndex < d->visibleIndex)
3549  d->visibleIndex = modelIndex+1;
3550  d->visibleIndex = qMax(qMin(d->visibleIndex, d->itemCount-1), 0);
3551  }
3552  }
3553 
3554  d->updateSections();
3555  emit countChanged();
3556 }
3557 
3559 {
3561  for (QList<FxListItem*>::Iterator it = d->visibleItems.begin();
3562  it != d->visibleItems.end();) {
3563  FxListItem *listItem = *it;
3564  if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
3565  d->releaseItem(listItem);
3566  it = d->visibleItems.erase(it);
3567  } else {
3568  ++it;
3569  }
3570  }
3571 
3572  // Correct the positioning of the items
3573  d->updateSections();
3574  d->layout();
3575 }
3576 
3577 void QDeclarativeListView::itemsMoved(int from, int to, int count)
3578 {
3580  if (!isComponentComplete())
3581  return;
3582  d->updateUnrequestedIndexes();
3583 
3584  if (d->visibleItems.isEmpty()) {
3585  refill();
3586  return;
3587  }
3588 
3589  d->moveReason = QDeclarativeListViewPrivate::Other;
3590  FxListItem *firstVisible = d->firstVisibleItem();
3591  qreal firstItemPos = firstVisible->position();
3592  QHash<int,FxListItem*> moved;
3593  int moveBy = 0;
3594 
3595  QList<FxListItem*>::Iterator it = d->visibleItems.begin();
3596  while (it != d->visibleItems.end()) {
3597  FxListItem *item = *it;
3598  if (item->index >= from && item->index < from + count) {
3599  // take the items that are moving
3600  item->index += (to-from);
3601  moved.insert(item->index, item);
3602  if (item->position() < firstItemPos)
3603  moveBy += item->size();
3604  it = d->visibleItems.erase(it);
3605  } else {
3606  // move everything after the moved items.
3607  if (item->index > from && item->index != -1)
3608  item->index -= count;
3609  ++it;
3610  }
3611  }
3612 
3613  int remaining = count;
3614  int endIndex = d->visibleIndex;
3615  it = d->visibleItems.begin();
3616  while (it != d->visibleItems.end()) {
3617  FxListItem *item = *it;
3618  if (remaining && item->index >= to && item->index < to + count) {
3619  // place items in the target position, reusing any existing items
3620  FxListItem *movedItem = moved.take(item->index);
3621  if (!movedItem)
3622  movedItem = d->createItem(item->index);
3623  if (!movedItem) {
3624  // broken or no delegate
3625  d->clear();
3626  return;
3627  }
3628  if (item->index <= firstVisible->index)
3629  moveBy -= movedItem->size();
3630  it = d->visibleItems.insert(it, movedItem);
3631  ++it;
3632  --remaining;
3633  } else {
3634  if (item->index != -1) {
3635  if (item->index >= to) {
3636  // update everything after the moved items.
3637  item->index += count;
3638  }
3639  endIndex = item->index;
3640  }
3641  ++it;
3642  }
3643  }
3644 
3645  // If we have moved items to the end of the visible items
3646  // then add any existing moved items that we have
3647  while (FxListItem *item = moved.take(endIndex+1)) {
3648  d->visibleItems.append(item);
3649  ++endIndex;
3650  }
3651 
3652  // update visibleIndex
3653  for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
3654  if ((*it)->index != -1) {
3655  d->visibleIndex = (*it)->index;
3656  break;
3657  }
3658  }
3659 
3660  // Fix current index
3661  if (d->currentIndex >= 0 && d->currentItem) {
3662  int oldCurrent = d->currentIndex;
3663  d->currentIndex = d->model->indexOf(d->currentItem->item, this);
3664  if (oldCurrent != d->currentIndex) {
3665  d->currentItem->index = d->currentIndex;
3667  }
3668  }
3669 
3670  // Whatever moved items remain are no longer visible items.
3671  while (moved.count()) {
3672  int idx = moved.begin().key();
3673  FxListItem *item = moved.take(idx);
3674  if (d->currentItem && item->item == d->currentItem->item)
3675  item->setPosition(d->positionAt(idx));
3676  d->releaseItem(item);
3677  }
3678 
3679  // Ensure we don't cause an ugly list scroll.
3680  if (!d->visibleItems.isEmpty())
3681  d->visibleItems.first()->setPosition(d->visibleItems.first()->position() + moveBy);
3682 
3683  d->updateSections();
3684  d->layout();
3685 }
3686 
3688 {
3690  d->updateSections();
3691  d->layout();
3692 }
3693 
3695 {
3698  d->regenerate();
3699  if (d->highlight && d->currentItem) {
3700  if (d->autoHighlight)
3701  d->highlight->setPosition(d->currentItem->position());
3702  d->updateTrackedItem();
3703  }
3704  d->moveReason = QDeclarativeListViewPrivate::Other;
3705  emit countChanged();
3706 }
3707 
3709 {
3711  if (d->requestedIndex != index) {
3712  item->setParentItem(contentItem());
3713  d->unrequestedItems.insert(item, index);
3714  if (d->orient == QDeclarativeListView::Vertical) {
3715  item->setY(d->positionAt(index));
3716  } else {
3717  if (d->isRightToLeft())
3718  item->setX(-d->positionAt(index)-item->width());
3719  else
3720  item->setX(d->positionAt(index));
3721  }
3722  }
3723 }
3724 
3726 {
3728  d->unrequestedItems.remove(item);
3729 }
3730 
3732 {
3735  if (d->haveHighlightRange && d->highlightRange == QDeclarativeListView::StrictlyEnforceRange)
3736  d->updateHighlight();
3737 }
3738 
3740 {
3741  return new QDeclarativeListViewAttached(obj);
3742 }
3743 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
void setFlickableDirection(FlickableDirection)
QDeclarativeItem * createComponentItem(QDeclarativeComponent *component)
virtual qreal minYExtent() const
QString section(QChar sep, int start, int end=-1, SectionFlags flags=SectionDefault) const
This function returns a section of the string.
Definition: qstring.h:781
QDeclarativeComponent * headerComponent
Q_INVOKABLE void positionViewAtBeginning()
The QKeyEvent class describes a key event.
Definition: qevent.h:224
FxListItem * snapItemAt(qreal pos)
double qreal
Definition: qglobal.h:1193
void setCriteria(SectionCriteria)
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
QDeclarativeItem * highlightItem()
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
qreal endPositionAt(int modelIndex) const
QDeclarativeListView::SnapMode snapMode
HighlightRangeMode highlightRangeMode() const
QDeclarativeParserStatus ** d
The QEasingCurve class provides easing curves for controlling animation.
Definition: qeasingcurve.h:55
const QChar at(int i) const
Returns the character at the given index position in the string.
Definition: qstring.h:698
int qCeil(qreal v)
Definition: qmath.h:63
QList< FxListItem * > visibleItems
#define it(className, varName)
void destroyingItem(QDeclarativeItem *item)
virtual qreal maxYExtent() const
bool isComponentComplete() const
Returns true if construction of the QML component is complete; otherwise returns false.
static void postEvent(QObject *receiver, QEvent *event)
Adds the event event, with the object receiver as the receiver of the event, to an event queue and re...
void itemsRemoved(int index, int count)
void setOrientation(Orientation)
virtual bool event(QEvent *)
QDeclarativeComponent * footerComponent
void highlightResizeSpeedChanged()
#define SLOT(a)
Definition: qobjectdefs.h:226
void highlightMoveDurationChanged()
static qreal position(QGraphicsObject *item, QDeclarativeAnchorLine::AnchorLine anchorLine)
QDeclarativeItem * contentItem()
static void clear(QVariant::Private *d)
Definition: qvariant.cpp:197
void setFooter(QDeclarativeComponent *)
QDeclarativeComponent * delegate() const
void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
QDeclarativeComponent * highlightComponent
virtual void keyPressEvent(QKeyEvent *event)
QDeclarativeContext * parentContext() const
Return the context&#39;s parent QDeclarativeContext, or 0 if this context has no parent or if the parent ...
qreal contentX() const
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
virtual void flick(QDeclarativeFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
QPointF pos() const
Returns the position of the item in parent coordinates.
FxListItem * itemBefore(int modelIndex) const
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
void setDelegate(QDeclarativeComponent *)
QDeclarativeListView::Orientation orient
virtual bool event(QEvent *event)
#define QML_FLICK_SNAPONETHRESHOLD
The QString class provides a Unicode character string.
Definition: qstring.h:83
T * qobject_cast(QObject *object)
Definition: qobject.h:375
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it...
Definition: qhash.h:807
QDeclarativeComponent * footer() const
void setView(QDeclarativeListView *view)
QVariant model() const
void update(const QRectF &rect=QRectF())
Schedules a redraw of the area covered by rect in this item.
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
Q_DECLARATIVE_EXPORT QDeclarativeContext * qmlContext(const QObject *)
QDeclarativeComponent * highlight() const
void itemsMoved(int from, int to, int count)
#define Q_D(Class)
Definition: qglobal.h:2482
virtual QObject * create(QDeclarativeContext *context=0)
Create an object instance from this component.
void itemGeometryChanged(QDeclarativeItem *, const QRectF &, const QRectF &)
void setVisible(bool visible)
If visible is true, the item is made visible.
qreal spacing() const
virtual qreal maxXExtent() const
Qt::LayoutDirection effectiveLayoutDirection() const
virtual qreal minYExtent() const
int currentIndex() const
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
void preferredHighlightBeginChanged()
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
#define Q_Q(Class)
Definition: qglobal.h:2483
int highlightResizeDuration() const
qreal itemPosition() const
void setParentItem(QDeclarativeItem *parent)
int key() const
Returns the code of the key that was pressed or released.
Definition: qevent.h:231
#define SIGNAL(a)
Definition: qobjectdefs.h:227
qreal positionAt(int modelIndex) const
void setNextSection(const QString &sect)
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
virtual void setContentY(qreal pos)
void positionViewAtIndex(int index, int mode)
void setProperty(const QString &)
SectionCriteria criteria() const
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
void setZValue(qreal z)
Sets the Z-value of the item to z.
void highlightRangeModeChanged()
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
bool isAccepted() const
Definition: qcoreevent.h:307
The QDeclarativeComponent class encapsulates a QML component definition.
QDeclarativeItem * item
Qt::LayoutDirection layoutDirection() const
const qreal MinimumFlickVelocity
QDeclarativeComponent * m_delegate
The QDeclarativeItem class provides the most basic of all visual items in QML.
Orientation orientation() const
qreal highlightResizeSpeed() const
bool contains(qreal x, qreal y) const
QDeclarativeListViewAttached * attached
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
void addItemChangeListener(QDeclarativeItemChangeListener *listener, ChangeTypes types)
void removeItem(QGraphicsItem *item)
Removes the item item and all its children from the scene.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
qreal preferredHighlightEnd() const
static bool init
virtual void setContentX(qreal pos)
void setLayoutDirection(Qt::LayoutDirection)
qreal height() const
Returns the height of the rectangle.
Definition: qrect.h:710
virtual qreal value() const
Return the current value.
qreal itemSize() const
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
const char * layout
LayoutDirection
Definition: qnamespace.h:1580
virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
This function is called to handle this item&#39;s changes in geometry from oldGeometry to newGeometry...
virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent)
static const char * data(const QByteArray &arr)
static Bigint * diff(Bigint *a, Bigint *b)
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
void setPrevSection(const QString &sect)
QDeclarativeGuard< QDeclarativeVisualModel > model
qreal width() const
Returns the width of the rectangle.
Definition: qrect.h:707
QDeclarativeViewSection * sectionCriteria
void moveBy(qreal dx, qreal dy)
Moves the item by dx points horizontally, and dy point vertically.
void clear()
Removes all items from the list.
Definition: qlist.h:764
FxListItem * visibleItem(int modelIndex) const
QDeclarativeComponent * header() const
static qreal component(const QPointF &point, unsigned int i)
QDeclarativeListView(QDeclarativeItem *parent=0)
void setX(qreal x)
Set&#39;s the x coordinate of the item&#39;s position.
bool highlightFollowsCurrentItem() const
void setHeader(QDeclarativeComponent *)
virtual qreal minXExtent() const
virtual qreal minXExtent() const
QHash< QDeclarativeItem *, int > unrequestedItems
qreal endPosition() const
void keyNavigationWrapsChanged()
The QList::iterator class provides an STL-style non-const iterator for QList and QQueue.
Definition: qlist.h:181
virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent)
qreal preferredHighlightBegin() const
void setSpacing(qreal spacing)
void setHighlight(QDeclarativeComponent *highlight)
void setContextProperty(const QString &, QObject *)
Set the value of the name property on this context.
QDeclarativeViewSection * sectionCriteria()
int mapFromModel(int modelIndex) const
void highlightResizeDurationChanged()
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
Disconnects signal in object sender from method in object receiver.
Definition: qobject.cpp:2895
QDeclarativeItem * currentItem()
FxListItem * createItem(int modelIndex)
void itemsInserted(int index, int count)
void removeItemChangeListener(QDeclarativeItemChangeListener *, ChangeTypes types)
QSmoothedAnimation * highlightSizeAnimator
Q_CORE_EXPORT void qFatal(const char *,...)
void setSize(qreal size)
QString currentSection() const
QDeclarativeComponent * delegate() const
void setDelegate(QDeclarativeComponent *delegate)
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
qreal position() const
QDeclarativeTimeLineValueProxy< QDeclarativeFlickablePrivate > move
qreal y() const
This convenience function is equivalent to calling pos().
FxListItem * firstVisibleItem() const
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the hash...
Definition: qhash.h:467
void QDeclarative_setParent_noEvent(QObject *object, QObject *parent)
Makes the object a child of parent.
void setPosition(qreal pos)
virtual void keyPressEvent(QKeyEvent *)
const Key key(const T &value) const
Returns the first key mapped to value.
Definition: qhash.h:674
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
qreal x() const
This convenience function is equivalent to calling pos().
static QDeclarativeListViewAttached * qmlAttachedProperties(QObject *)
void setY(qreal y)
Set&#39;s the y coordinate of the item&#39;s position.
virtual void componentComplete()
void highlightMoveSpeedChanged()
Q_INVOKABLE int indexAt(qreal x, qreal y) const
const char * property
Definition: qwizard.cpp:138
qreal sectionSize() const
Definition: qnamespace.h:54
iterator begin()
Returns an STL-style iterator pointing to the first item in the hash.
Definition: qhash.h:464
void releaseItem(FxListItem *item)
QDeclarativeListView::HighlightRangeMode highlightRange
void highlightFollowsCurrentItemChanged()
T qvariant_cast(const QVariant &)
Definition: qvariant.h:571
virtual void flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
The QDeclarativeContext class defines a context within a QML engine.
static const QGraphicsItemPrivate * get(const QGraphicsItem *item)
quint16 index
QSmoothedAnimation * highlightPosAnimator
The QDeclarativeProperty class abstracts accessing properties on objects created from QML...
QDeclarativeListView * view
int count(const Key &key) const
Returns the number of items associated with the key.
Definition: qhash.h:719
qreal highlightMoveSpeed() const
void setSnapMode(SnapMode mode)
QGraphicsScene * scene() const
Returns the current scene for the item, or 0 if the item is not stored in a scene.
Q_INVOKABLE void positionViewAtEnd()
static QDeclarativeContext * contextForObject(const QObject *)
Returns the QDeclarativeContext for the object, or 0 if no context has been set.
void refill(qreal from, qreal to, bool doBuffer=false)
virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
This function is called to handle this item&#39;s changes in geometry from oldGeometry to newGeometry...
virtual void setContentX(qreal pos)
qreal size() const
static const KeyPair *const end
int highlightMoveDuration() const
QString sectionString(const QString &value)
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
Type type() const
Returns the event type.
Definition: qcoreevent.h:303
SnapMode snapMode() const
int cacheBuffer() const
qreal qSqrt(qreal v)
Definition: qmath.h:205
QDeclarativeItem * section
void setSection(const QString &sect)
virtual void setContentY(qreal pos)
void setModel(const QVariant &)
void setHighlightRangeMode(HighlightRangeMode mode)
Q_INVOKABLE void positionViewAtIndex(int index, int mode)
FxListItem(QDeclarativeItem *i, QDeclarativeListView *v)
Q_DECL_CONSTEXPR int qRound(qreal d)
Definition: qglobal.h:1203
void preferredHighlightEndChanged()
QString sectionAt(int modelIndex)
QDeclarativeContext * creationContext() const
Returns the QDeclarativeContext the component was created in.
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
void keyPressPreHandler(QKeyEvent *)
void itemsChanged(int index, int count)
void createdItem(int index, QDeclarativeItem *item)