61 mPreviousSelectedCommand(QItemSelectionModel::NoUpdate), |
62 mPreviousSelectedCommand(QItemSelectionModel::NoUpdate), |
62 mAnimationTimer(0), |
63 mAnimationTimer(0), |
63 mModelIterator(0), |
64 mModelIterator(0), |
64 mEnabledAnimations(HbAbstractItemView::All), |
65 mEnabledAnimations(HbAbstractItemView::All), |
65 mLongPressEnabled(true), |
66 mLongPressEnabled(true), |
66 mDoingContiguousSelection(false) |
67 mDoingContiguousSelection(false), |
|
68 mItemPixmapCacheEnabled(false), |
|
69 mIconLoadPolicy(HbAbstractItemView::LoadAsynchronouslyAlways), |
|
70 mEmptyView(0) |
67 { |
71 { |
68 } |
72 } |
69 |
73 |
70 HbAbstractItemViewPrivate::~HbAbstractItemViewPrivate() |
74 HbAbstractItemViewPrivate::~HbAbstractItemViewPrivate() |
71 { |
75 { |
72 if (mModelIterator) { |
76 delete mModelIterator; |
73 delete mModelIterator; |
|
74 mModelIterator = 0; |
|
75 } |
|
76 } |
77 } |
77 |
78 |
78 /*! |
79 /*! |
79 |
80 |
80 */ |
81 */ |
81 void HbAbstractItemViewPrivate::init(HbAbstractItemContainer *container, HbModelIterator *modelIterator) |
82 void HbAbstractItemViewPrivate::init(HbAbstractItemContainer *container, HbModelIterator *modelIterator) |
82 { |
83 { |
83 Q_Q(HbAbstractItemView); |
84 Q_Q(HbAbstractItemView); |
84 |
85 |
85 q->setLongPressEnabled(true); |
|
86 q->setFlag(QGraphicsItem::ItemIsFocusable, true); |
86 q->setFlag(QGraphicsItem::ItemIsFocusable, true); |
87 q->setFocusPolicy(Qt::StrongFocus); |
87 q->setFocusPolicy(Qt::StrongFocus); |
88 |
88 |
89 q->setContentWidget(container); |
89 q->setContentWidget(container); |
90 |
90 |
91 q->grabGesture(Qt::PanGesture); |
|
92 |
|
93 //mAlignment = 0; // no alignment - there is no sense with recycling |
|
94 |
|
95 mContainer = container; |
91 mContainer = container; |
96 mContainer->setItemView(q); |
92 mContainer->setItemView(q); |
97 |
93 |
98 mModelIterator = modelIterator; |
94 mModelIterator = modelIterator; |
99 |
95 |
|
96 mEmptyView = new HbEmptyViewWidget(q); |
|
97 |
100 q->connect(mContainer, SIGNAL(itemCreated(HbAbstractViewItem *)), |
98 q->connect(mContainer, SIGNAL(itemCreated(HbAbstractViewItem *)), |
101 q, SLOT(itemCreated(HbAbstractViewItem *))); |
99 q, SLOT(itemCreated(HbAbstractViewItem *))); |
|
100 q->connect(mContainer, SIGNAL(itemAboutToBeDeleted(HbAbstractViewItem *)), |
|
101 q, SLOT(_q_itemAboutToBeDeleted(HbAbstractViewItem *))); |
102 |
102 |
103 HbMainWindow *window = q->mainWindow(); |
103 HbMainWindow *window = q->mainWindow(); |
104 if (window |
104 if (window && q->scene()) { // added to scene |
105 && q->scene()) { // added to scene |
|
106 q->connect(window, SIGNAL(aboutToChangeOrientation()), |
105 q->connect(window, SIGNAL(aboutToChangeOrientation()), |
107 q, SLOT(orientationAboutToBeChanged())); |
106 q, SLOT(orientationAboutToBeChanged())); |
108 |
107 |
109 q->connect(window, SIGNAL(orientationChanged(Qt::Orientation)), |
108 q->connect(window, SIGNAL(orientationChanged(Qt::Orientation)), |
110 q, SLOT(orientationChanged(Qt::Orientation))); |
109 q, SLOT(orientationChanged(Qt::Orientation))); |
351 Q_Q(HbAbstractItemView); |
349 Q_Q(HbAbstractItemView); |
352 int retVal = false; |
350 int retVal = false; |
353 HbPanGesture *gesture = static_cast<HbPanGesture *>(event->gesture(Qt::PanGesture)); |
351 HbPanGesture *gesture = static_cast<HbPanGesture *>(event->gesture(Qt::PanGesture)); |
354 |
352 |
355 switch (gesture->state()) { |
353 switch (gesture->state()) { |
356 case Qt::GestureStarted: |
354 case Qt::GestureStarted: { |
357 mOptions |= PanningActive; |
355 mOptions |= PanningActive; |
358 // Fallthrough |
356 mPanningDirection = calculatePanningDirection(gesture); |
|
357 mStartSelectionIndex = QModelIndex(); |
|
358 } |
|
359 |
|
360 // Fallthrough |
359 case Qt::GestureUpdated: { |
361 case Qt::GestureUpdated: { |
360 QPointF scenePos = event->mapToGraphicsScene(gesture->hotSpot()); |
362 QPointF scenePos = event->mapToGraphicsScene(gesture->hotSpot()); |
361 if (mDoingContiguousSelection) { |
363 if (mDoingContiguousSelection) { |
362 |
364 |
363 // loop through the items in the scene |
365 // loop through the items in the scene |
364 qreal scenePosY = scenePos.y(); |
|
365 QPointF lastScenePos = scenePos + gesture->lastOffset() - gesture->offset(); |
366 QPointF lastScenePos = scenePos + gesture->lastOffset() - gesture->offset(); |
366 qreal lastScenePosY = lastScenePos.y(); |
|
367 QPolygonF polygon; |
367 QPolygonF polygon; |
368 polygon << lastScenePos << scenePos; |
368 polygon << lastScenePos << scenePos; |
369 QList<QGraphicsItem *> items = q->scene()->items(polygon); |
369 QList<QGraphicsItem *> items = q->scene()->items(polygon); |
370 int itemCount = items.count(); |
370 int itemCount = items.count(); |
|
371 HbAbstractViewItem *item = 0; |
371 for (int current = 0; current < itemCount ; ++current) { |
372 for (int current = 0; current < itemCount ; ++current) { |
372 HbAbstractViewItem *item = viewItem(items.at(current)); |
373 item = viewItem(items.at(current)); |
373 if (item && item->itemView() == q) { |
374 if (item && item->itemView() == q) { |
374 QModelIndex itemIndex(item->modelIndex()); |
375 QModelIndex itemIndex(item->modelIndex()); |
375 QGraphicsSceneMouseEvent mouseMoveEvent(QEvent::GraphicsSceneMouseMove); |
376 QGraphicsSceneMouseEvent mouseMoveEvent(QEvent::GraphicsSceneMouseMove); |
376 QPointF scenePosInItemCoordinates = item->mapFromScene(scenePos); |
377 QPointF scenePosInItemCoordinates = item->mapFromScene(scenePos); |
377 QPointF position(qBound((qreal)0.0, scenePosInItemCoordinates.x(), item->size().width()), |
378 QPointF position(qBound((qreal)0.0, scenePosInItemCoordinates.x(), item->size().width()), |
382 // in contiguousselectionarea there shall be no panning from HbScrollArea, thus return true |
383 // in contiguousselectionarea there shall be no panning from HbScrollArea, thus return true |
383 if (command != QItemSelectionModel::NoUpdate) { |
384 if (command != QItemSelectionModel::NoUpdate) { |
384 retVal = true; |
385 retVal = true; |
385 } |
386 } |
386 |
387 |
387 if ( itemIndex != mPreviousSelectedIndex |
388 int panningDirection = calculatePanningDirection(gesture); |
388 || command != mPreviousSelectedCommand) { |
389 |
|
390 // user action crosses item boundary, all selection and panning direction actions |
|
391 // are handled here |
|
392 if (itemIndex != mPreviousSelectedIndex) { |
|
393 |
|
394 // The following block handles the case where the panning direction changes. |
|
395 // In that case we need to reverse the selection action. We also make sure that |
|
396 // the item on which the direction was changed, gets its selection reversed. |
|
397 // This is done only when view is not scrolling (excluding the bounceback |
|
398 // animation) to not let tiny finger movements disturb selection while the user |
|
399 // is keeping the finger down at the end of the screen in order to scroll the |
|
400 // list while selecting. |
|
401 if (!mIsAnimating || isBouncebackOngoing()) { |
|
402 if ((panningDirection != 0) |
|
403 && (panningDirection != mPanningDirection)) { |
|
404 if (mStartSelectionIndex != mPreviousSelectedIndex) { |
|
405 mContSelectionAction = mContSelectionAction == QItemSelectionModel::Select |
|
406 ? QItemSelectionModel::Deselect |
|
407 : QItemSelectionModel::Select; |
|
408 } |
|
409 mSelectionModel->select(mPreviousSelectedIndex, mContSelectionAction); |
|
410 mPanningDirection = panningDirection; |
|
411 } |
|
412 } |
|
413 |
|
414 // When the user action crosses item boundary back to the start item the |
|
415 // selection action is reversed |
|
416 if (mStartSelectionIndex == itemIndex) { |
|
417 mContSelectionAction = mContSelectionAction == QItemSelectionModel::Select |
|
418 ? QItemSelectionModel::Deselect |
|
419 : QItemSelectionModel::Select; |
|
420 } else { |
|
421 // this is the "normal" selection action |
|
422 mSelectionModel->select(itemIndex, mContSelectionAction); |
|
423 } |
|
424 |
|
425 mPreviousSelectedCommand = command; |
|
426 if (!mPreviousSelectedIndex.isValid()) { |
|
427 mStartSelectionIndex = itemIndex; |
|
428 } |
389 mPreviousSelectedIndex = itemIndex; |
429 mPreviousSelectedIndex = itemIndex; |
390 mPreviousSelectedCommand = command; |
|
391 mSelectionModel->select(itemIndex, command); |
|
392 HbWidgetFeedback::triggered(q, Hb::InstantSelectionChanged, Hb::ModifierScrolling); |
430 HbWidgetFeedback::triggered(q, Hb::InstantSelectionChanged, Hb::ModifierScrolling); |
393 } |
431 } |
394 |
432 |
395 // check if we need to start or keep on scrolling |
433 // check if we need to start or keep on scrolling |
396 int scrollDirection = 0; |
434 int scrollDirection = 0; |
397 QPointF pos = q->mapFromScene(scenePos); |
435 QPointF pos = q->mapFromScene(scenePos); |
398 if (pos.y() < (q->size().height() * CONTIGUOUS_SELECTION_AREA_THRESHOLD)) { |
436 if (pos.y() < (q->size().height() * CONTIGUOUS_SELECTION_AREA_THRESHOLD)) { |
399 if (q->isScrolling() |
437 if (q->isScrolling() |
400 || (!q->isScrolling() |
438 || (!q->isScrolling() |
401 && lastScenePosY >= scenePosY)) { |
439 && panningDirection > 0)) { |
402 scrollDirection = 1; |
440 scrollDirection = 1; |
403 } |
441 } |
404 } else if (pos.y() > (q->size().height() * (1 - CONTIGUOUS_SELECTION_AREA_THRESHOLD))) { |
442 } else if (pos.y() > (q->size().height() * (1 - CONTIGUOUS_SELECTION_AREA_THRESHOLD))) { |
405 if (q->isScrolling() |
443 if (q->isScrolling() |
406 || (!q->isScrolling() |
444 || (!q->isScrolling() |
407 && lastScenePosY <= scenePosY)) { |
445 && panningDirection < 0)) { |
408 scrollDirection = -1; |
446 scrollDirection = -1; |
409 } |
447 } |
410 } |
448 } |
411 |
449 |
412 // Start scrolling if needed. |
450 // Start scrolling if needed |
413 if (scrollDirection != 0) { |
451 if (scrollDirection != 0) { |
|
452 mPositionInContiguousSelection = scenePos; |
414 if (!mIsAnimating) { |
453 if (!mIsAnimating) { |
415 mPositionInContiguousSelection = scenePos; |
|
416 QObject::connect(q, SIGNAL(scrollPositionChanged(QPointF)), q, SLOT(_q_scrolling(QPointF))); |
454 QObject::connect(q, SIGNAL(scrollPositionChanged(QPointF)), q, SLOT(_q_scrolling(QPointF))); |
417 QObject::connect(q, SIGNAL(scrollingEnded()), q, SLOT(_q_scrollingEnded())); |
455 QObject::connect(q, SIGNAL(scrollingEnded()), q, SLOT(_q_scrollingEnded())); |
418 QObject::connect(q, SIGNAL(scrollingStarted()), q, SLOT(_q_scrollingStarted())); |
456 QObject::connect(q, SIGNAL(scrollingStarted()), q, SLOT(_q_scrollingStarted())); |
419 animateScroll(QPointF (0.0f, scrollDirection * CONTIGUOUS_SELECTION_SCROLL_SPEED)); |
457 animateScroll(QPointF (0.0f, scrollDirection * CONTIGUOUS_SELECTION_SCROLL_SPEED)); |
420 retVal = true; |
458 retVal = true; |
458 void HbAbstractItemViewPrivate::_q_scrolling(QPointF newPosition) |
499 void HbAbstractItemViewPrivate::_q_scrolling(QPointF newPosition) |
459 { |
500 { |
460 Q_UNUSED(newPosition); |
501 Q_UNUSED(newPosition); |
461 |
502 |
462 HbAbstractViewItem* hitItem = itemAt(mPositionInContiguousSelection); |
503 HbAbstractViewItem* hitItem = itemAt(mPositionInContiguousSelection); |
463 if (hitItem) { |
504 if (hitItem && !isBouncebackOngoing()) { |
464 QModelIndex itemIndex(hitItem->modelIndex()); |
505 QModelIndex itemIndex(hitItem->modelIndex()); |
465 if ( itemIndex != mPreviousSelectedIndex) { |
506 if ( itemIndex != mPreviousSelectedIndex) { |
|
507 // if scrolling over the pan start item, the selection action is reversed |
|
508 if (mStartSelectionIndex.isValid() && (mStartSelectionIndex == itemIndex)) { |
|
509 mContSelectionAction = mContSelectionAction == QItemSelectionModel::Select |
|
510 ? QItemSelectionModel::Deselect |
|
511 : QItemSelectionModel::Select; |
|
512 } else { |
|
513 mSelectionModel->select(itemIndex, mContSelectionAction); |
|
514 } |
466 mPreviousSelectedIndex = itemIndex; |
515 mPreviousSelectedIndex = itemIndex; |
467 mSelectionModel->select(itemIndex, mPreviousSelectedCommand); |
|
468 } |
516 } |
469 } |
517 } |
470 } |
518 } |
471 |
519 |
472 /*! |
520 /*! |
1029 return mEnabledAnimations & HbAbstractItemView::Appear ? mAnimateItems : false; |
1086 return mEnabledAnimations & HbAbstractItemView::Appear ? mAnimateItems : false; |
1030 } else { |
1087 } else { |
1031 return mEnabledAnimations & HbAbstractItemView::Disappear ? mAnimateItems : false; |
1088 return mEnabledAnimations & HbAbstractItemView::Disappear ? mAnimateItems : false; |
1032 } |
1089 } |
1033 } |
1090 } |
|
1091 |
|
1092 void HbAbstractItemViewPrivate::_q_itemAboutToBeDeleted(HbAbstractViewItem *item) |
|
1093 { |
|
1094 Q_UNUSED(item); |
|
1095 |
|
1096 if (mContainer->items().count() < 1) { |
|
1097 mEmptyView->setVisible(true); |
|
1098 } |
|
1099 } |
|
1100 |
|
1101 /*! |
|
1102 Determines whether the current gesture movement is up or down in the |
|
1103 current device orientation. |
|
1104 */ |
|
1105 int HbAbstractItemViewPrivate::calculatePanningDirection(HbPanGesture *gesture) |
|
1106 { |
|
1107 Q_Q(HbAbstractItemView); |
|
1108 |
|
1109 qreal offsetDifferenceInScrollingDirection = 0; |
|
1110 int panningDirection = 0; |
|
1111 if (q->mainWindow()->orientation() == Qt::Vertical) { |
|
1112 offsetDifferenceInScrollingDirection = gesture->lastOffset().y() - gesture->offset().y(); |
|
1113 } else { |
|
1114 offsetDifferenceInScrollingDirection = gesture->offset().x() - gesture->lastOffset().x(); |
|
1115 } |
|
1116 if (offsetDifferenceInScrollingDirection > 0 ) { |
|
1117 panningDirection = 1; |
|
1118 } else if (offsetDifferenceInScrollingDirection < 0 ) { |
|
1119 panningDirection = -1; |
|
1120 } |
|
1121 return panningDirection; |
|
1122 } |
|
1123 bool HbAbstractItemViewPrivate::isBouncebackOngoing() |
|
1124 { |
|
1125 Q_Q(HbAbstractItemView); |
|
1126 |
|
1127 if (mIsAnimating) { |
|
1128 QRectF containerRect = mContainer->mapToItem(q, mContainer->boundingRect()).boundingRect(); |
|
1129 if (containerRect.top() >= 0 |
|
1130 || q->boundingRect().height() - containerRect.top() >= containerRect.height()) { |
|
1131 return true; |
|
1132 } |
|
1133 } |
|
1134 return false; |
|
1135 } |
|
1136 |