src/hbwidgets/itemviews/hbabstractitemview_p.cpp
changeset 34 ed14f46c0e55
parent 6 c3690ec91ef8
--- a/src/hbwidgets/itemviews/hbabstractitemview_p.cpp	Mon Oct 04 17:49:30 2010 +0300
+++ b/src/hbwidgets/itemviews/hbabstractitemview_p.cpp	Mon Oct 18 18:23:13 2010 +0300
@@ -29,7 +29,7 @@
 #include "hbabstractitemcontainer_p.h"
 #include "hbmodeliterator.h"
 
-#include <hbinstance.h>
+#include <hbmainwindow.h>
 #include <hbscrollbar.h>
 #include <hbapplication.h>
 #include <hbeffect.h>
@@ -48,6 +48,7 @@
 static const qreal CONTIGUOUS_SELECTION_SCROLL_SPEED = 0.2;
 static const qreal CONTIGUOUS_SELECTION_AREA_THRESHOLD = 0.2;
 
+
 HbAbstractItemViewPrivate::HbAbstractItemViewPrivate() :
     mSelectionMode(HbAbstractItemView::NoSelection),
     mOptions(NoOptions),
@@ -63,16 +64,16 @@
     mModelIterator(0),
     mEnabledAnimations(HbAbstractItemView::All),
     mLongPressEnabled(true),
-    mDoingContiguousSelection(false)
+    mDoingContiguousSelection(false),
+    mItemPixmapCacheEnabled(false),
+    mIconLoadPolicy(HbAbstractItemView::LoadAsynchronouslyAlways),
+    mEmptyView(0)
 {
 }
 
 HbAbstractItemViewPrivate::~HbAbstractItemViewPrivate()
 {
-    if (mModelIterator) {
-        delete mModelIterator;
-        mModelIterator = 0;
-    }
+    delete mModelIterator;
 }
 
 /*!
@@ -82,27 +83,25 @@
 {
     Q_Q(HbAbstractItemView);
 
-    q->setLongPressEnabled(true);
     q->setFlag(QGraphicsItem::ItemIsFocusable, true);
     q->setFocusPolicy(Qt::StrongFocus);
     
     q->setContentWidget(container);
 
-    q->grabGesture(Qt::PanGesture);
-
-    //mAlignment = 0; // no alignment - there is no sense with recycling
-
     mContainer = container;
     mContainer->setItemView(q);
 
     mModelIterator = modelIterator;
 
+    mEmptyView = new HbEmptyViewWidget(q);
+
     q->connect(mContainer, SIGNAL(itemCreated(HbAbstractViewItem *)),
             q, SLOT(itemCreated(HbAbstractViewItem *)));
+    q->connect(mContainer, SIGNAL(itemAboutToBeDeleted(HbAbstractViewItem *)),
+                q, SLOT(_q_itemAboutToBeDeleted(HbAbstractViewItem *)));
 
     HbMainWindow *window = q->mainWindow();
-    if (window
-        && q->scene()) { // added to scene
+    if (window && q->scene()) { // added to scene
         q->connect(window, SIGNAL(aboutToChangeOrientation()),
                    q, SLOT(orientationAboutToBeChanged()));
 
@@ -303,7 +302,6 @@
             }
         } 
 
-        status.item->setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
         mAppearAnimationIndexes.clear();
     }
 }
@@ -353,23 +351,26 @@
     HbPanGesture *gesture = static_cast<HbPanGesture *>(event->gesture(Qt::PanGesture));
 
     switch (gesture->state()) {
-        case Qt::GestureStarted:
+        case Qt::GestureStarted: {
             mOptions |= PanningActive;
-            // Fallthrough
+            mPanningDirection = calculatePanningDirection(gesture);
+            mStartSelectionIndex = QModelIndex();
+        }
+
+        // Fallthrough
         case Qt::GestureUpdated: {
             QPointF scenePos = event->mapToGraphicsScene(gesture->hotSpot());
             if (mDoingContiguousSelection) {
 
                 // loop through the items in the scene
-                qreal scenePosY = scenePos.y();
                 QPointF lastScenePos = scenePos + gesture->lastOffset() - gesture->offset();
-                qreal lastScenePosY = lastScenePos.y();
                 QPolygonF polygon;
                 polygon << lastScenePos << scenePos;
                 QList<QGraphicsItem *> items = q->scene()->items(polygon);
                 int itemCount = items.count();
+                HbAbstractViewItem *item = 0;
                 for (int current = 0; current < itemCount ; ++current) {
-                    HbAbstractViewItem *item = viewItem(items.at(current));
+                    item = viewItem(items.at(current));
                     if (item && item->itemView() == q) {
                         QModelIndex itemIndex(item->modelIndex());
                         QGraphicsSceneMouseEvent mouseMoveEvent(QEvent::GraphicsSceneMouseMove);
@@ -384,11 +385,48 @@
                             retVal = true;
                         }
 
-                        if ( itemIndex != mPreviousSelectedIndex
-                          || command != mPreviousSelectedCommand) {
+                        int panningDirection = calculatePanningDirection(gesture);
+
+                        // user action crosses item boundary, all selection and panning direction actions 
+                        // are handled here
+                        if (itemIndex != mPreviousSelectedIndex) {
+                              
+                            // The following block handles the case where the panning direction changes.
+                            // In that case we need to reverse the selection action. We also make sure that 
+                            // the item on which the direction was changed, gets its selection reversed.
+                            // This is done only when view is not scrolling (excluding the bounceback
+                            // animation) to not let tiny finger movements disturb selection while the user 
+                            // is keeping the finger down at the end of the screen in order to scroll the 
+                            // list while selecting. 
+                            if (!mIsAnimating || isBouncebackOngoing()) {
+                                if ((panningDirection != 0) 
+                                    && (panningDirection != mPanningDirection)) {
+                                    if (mStartSelectionIndex != mPreviousSelectedIndex) {
+                                        mContSelectionAction = mContSelectionAction == QItemSelectionModel::Select  
+                                        ? QItemSelectionModel::Deselect 
+                                        : QItemSelectionModel::Select;
+                                    }
+                                    mSelectionModel->select(mPreviousSelectedIndex, mContSelectionAction);
+                                    mPanningDirection = panningDirection;
+                                }
+                            } 
+                            
+                            // When the user action crosses item boundary back to the start item the 
+                            // selection action is reversed
+                            if (mStartSelectionIndex == itemIndex) {
+                                mContSelectionAction = mContSelectionAction == QItemSelectionModel::Select  
+                                    ? QItemSelectionModel::Deselect 
+                                    : QItemSelectionModel::Select;
+                            } else {
+                                // this is the "normal" selection action
+                                mSelectionModel->select(itemIndex, mContSelectionAction);
+                            }
+
+                            mPreviousSelectedCommand = command;
+                            if (!mPreviousSelectedIndex.isValid()) {
+                                mStartSelectionIndex = itemIndex;
+                            }
                             mPreviousSelectedIndex = itemIndex;
-                            mPreviousSelectedCommand = command;
-                            mSelectionModel->select(itemIndex, command);
                             HbWidgetFeedback::triggered(q, Hb::InstantSelectionChanged, Hb::ModifierScrolling);
                         }
 
@@ -398,21 +436,21 @@
                         if (pos.y() < (q->size().height() * CONTIGUOUS_SELECTION_AREA_THRESHOLD)) {
                              if (q->isScrolling()
                                  || (!q->isScrolling()
-                                     && lastScenePosY >= scenePosY)) {                                
+                                     && panningDirection > 0)) {
                                  scrollDirection = 1;
                              }
                         } else if (pos.y() > (q->size().height() * (1 - CONTIGUOUS_SELECTION_AREA_THRESHOLD))) {
                              if (q->isScrolling()
                                  || (!q->isScrolling()
-                                     && lastScenePosY <= scenePosY)) {
+                                     && panningDirection < 0)) {
                                  scrollDirection = -1;
                              }                        
                         }
 
-                        // Start scrolling if needed. 
+                        // Start scrolling if needed
                         if (scrollDirection != 0) {
+                            mPositionInContiguousSelection = scenePos;
                             if (!mIsAnimating) {
-                                mPositionInContiguousSelection = scenePos;
                                 QObject::connect(q, SIGNAL(scrollPositionChanged(QPointF)), q, SLOT(_q_scrolling(QPointF)));    
                                 QObject::connect(q, SIGNAL(scrollingEnded()), q, SLOT(_q_scrollingEnded()));    
                                 QObject::connect(q, SIGNAL(scrollingStarted()), q, SLOT(_q_scrollingStarted()));    
@@ -425,6 +463,9 @@
                         }
                         break;
                     }
+                } 
+                if (!item) {
+                    retVal = true;
                 }
             }
             else {
@@ -460,11 +501,18 @@
     Q_UNUSED(newPosition);
 
     HbAbstractViewItem* hitItem = itemAt(mPositionInContiguousSelection);
-    if (hitItem) {
+    if (hitItem && !isBouncebackOngoing()) {
         QModelIndex itemIndex(hitItem->modelIndex());
         if ( itemIndex != mPreviousSelectedIndex) {
+            // if scrolling over the pan start item, the selection action is reversed
+            if (mStartSelectionIndex.isValid() && (mStartSelectionIndex == itemIndex)) {
+                mContSelectionAction = mContSelectionAction == QItemSelectionModel::Select  
+                    ? QItemSelectionModel::Deselect 
+                    : QItemSelectionModel::Select;
+            } else {
+                mSelectionModel->select(itemIndex, mContSelectionAction);
+            }
             mPreviousSelectedIndex = itemIndex;
-            mSelectionModel->select(itemIndex, mPreviousSelectedCommand);
         }
     }
 }
@@ -498,7 +546,7 @@
     When orientation switch occurs, 1) or 2) is applied to view after layout switch:
           1) if last item is wholly visible, it will be visible
           2) if last item is not fully visible, the first fully visible item before layout switch is made the 
-		     first fully visible item
+             first fully visible item
  */
 void HbAbstractItemViewPrivate::saveIndexMadeVisibleAfterMetricsChange()
 {
@@ -709,6 +757,11 @@
     Q_Q(const HbAbstractItemView);
 
     HbAbstractViewItem *hitItem = 0;
+
+    if (mContainer && mContainer->layout() && !mContainer->layout()->isActivated()) {
+        mContainer->layout()->activate();
+    }
+
     QList<QGraphicsItem *> items = q->scene()->items(position);
     
     int count = items.count();
@@ -749,6 +802,8 @@
     bool visible = false;
     if (item) {
         QRectF itemRect(itemBoundingRect(item));
+        // 0.5 tolerance otherwise it fail - for instance if pos.y = -5.68434e-14 then item will be not fullyVisible
+        itemRect.adjust(0.5, 0.5, -0.5, -0.5);
         QRectF abstractViewRect(itemBoundingRect(q));
         if (fullyVisible) {
             if (abstractViewRect.contains(itemRect)) {
@@ -929,7 +984,9 @@
         qreal firstVisibleRow = mModelIterator->indexPosition(mContainer->items().first()->modelIndex());
         firstVisibleRow += -containerPos / itemHeight;
         qreal thumbPos = firstVisibleRow / (qreal)modelRowCount;
-        mVerticalScrollBar->setValue(thumbPos);
+        if (mVerticalScrollBar) {
+            mVerticalScrollBar->setValue(thumbPos);
+        }
     }
 }
 
@@ -1017,7 +1074,7 @@
     HbEffect::start(items, itemType, effectEvent, q, "_q_animationFinished");
 }
 
-void HbAbstractItemViewPrivate::ensureVisible(QPointF position, qreal xMargin, qreal yMargin)
+void HbAbstractItemViewPrivate::ensureVisible(const QPointF &position, qreal xMargin, qreal yMargin)
 {
     mPostponedScrollIndex = QPersistentModelIndex();
     HbScrollAreaPrivate::ensureVisible(position, xMargin, yMargin);
@@ -1031,3 +1088,49 @@
         return mEnabledAnimations & HbAbstractItemView::Disappear ? mAnimateItems : false;
     }
 }
+
+void HbAbstractItemViewPrivate::_q_itemAboutToBeDeleted(HbAbstractViewItem *item)
+{
+    Q_UNUSED(item);
+
+    if (mContainer->items().count() < 1) {
+        mEmptyView->setVisible(true);
+    }
+}
+
+/*!
+    Determines whether the current gesture movement is up or down in the
+    current device orientation.
+*/
+int HbAbstractItemViewPrivate::calculatePanningDirection(HbPanGesture *gesture)
+{
+    Q_Q(HbAbstractItemView);
+
+    qreal offsetDifferenceInScrollingDirection = 0;
+    int panningDirection = 0;
+    if (q->mainWindow()->orientation() == Qt::Vertical) {
+        offsetDifferenceInScrollingDirection = gesture->lastOffset().y() - gesture->offset().y();
+    } else {
+        offsetDifferenceInScrollingDirection = gesture->offset().x() - gesture->lastOffset().x();
+    }
+    if (offsetDifferenceInScrollingDirection > 0 ) {
+        panningDirection = 1;
+    } else if (offsetDifferenceInScrollingDirection < 0 ) {
+        panningDirection = -1;
+    } 
+    return panningDirection;
+}
+bool HbAbstractItemViewPrivate::isBouncebackOngoing() 
+{
+    Q_Q(HbAbstractItemView);
+
+    if (mIsAnimating) {
+        QRectF containerRect = mContainer->mapToItem(q, mContainer->boundingRect()).boundingRect();
+        if (containerRect.top() >= 0
+            || q->boundingRect().height() - containerRect.top() >= containerRect.height()) {
+            return true;
+        }
+    }
+    return false;
+}
+