src/hbwidgets/itemviews/hbabstractitemview_p.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
equal deleted inserted replaced
-1:000000000000 0:16d8024aca5e
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (developer.feedback@nokia.com)
       
     6 **
       
     7 ** This file is part of the HbWidgets module of the UI Extensions for Mobile.
       
     8 **
       
     9 ** GNU Lesser General Public License Usage
       
    10 ** This file may be used under the terms of the GNU Lesser General Public
       
    11 ** License version 2.1 as published by the Free Software Foundation and
       
    12 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
       
    13 ** Please review the following information to ensure the GNU Lesser General
       
    14 ** Public License version 2.1 requirements will be met:
       
    15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    16 **
       
    17 ** In addition, as a special exception, Nokia gives you certain additional
       
    18 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    20 **
       
    21 ** If you have questions regarding the use of this file, please contact
       
    22 ** Nokia at developer.feedback@nokia.com.
       
    23 **
       
    24 ****************************************************************************/
       
    25 
       
    26 #include "hbabstractitemview_p.h"
       
    27 #include "hbabstractitemview.h"
       
    28 #include "hbabstractviewitem.h"
       
    29 #include "hbabstractitemcontainer.h"
       
    30 #include "hbmodeliterator.h"
       
    31 
       
    32 #include <hbgesturefilter.h>
       
    33 #include <hbinstance.h>
       
    34 #include <hbscrollbar.h>
       
    35 #include <hbapplication.h>
       
    36 #include <hbeffect.h>
       
    37 
       
    38 #include <QGraphicsSceneMouseEvent>
       
    39 #include <QEvent>
       
    40 #include <QItemSelectionModel>
       
    41 #include <QGraphicsScene>
       
    42 #include <QGraphicsLayout>
       
    43 #include <QTimer>
       
    44 #include <QDebug>
       
    45 
       
    46 HbAbstractItemViewPrivate::HbAbstractItemViewPrivate() :
       
    47     mSelectionMode(HbAbstractItemView::NoSelection),
       
    48     mOptions(NoOptions),
       
    49     mSelectionSettings(None),
       
    50     mHitItem(0),
       
    51     mContainer(0),
       
    52     mSelectionModel(0),
       
    53     mContSelectionAction(QItemSelectionModel::NoUpdate),
       
    54     mWasScrolling(false),
       
    55     mFilterRemoved(false),
       
    56     mClearingSelection(false),
       
    57     mAnimateItems(false),
       
    58     mPostponedScrollHint(HbAbstractItemView::PositionAtTop),
       
    59     mPreviousSelectedCommand(QItemSelectionModel::NoUpdate),
       
    60     mInstantClickedModifiers(0),
       
    61     mAnimationTimer(0),
       
    62 	mModelIterator(0),
       
    63     mEnabledAnimations(HbAbstractItemView::All)
       
    64 {
       
    65 }
       
    66 
       
    67 HbAbstractItemViewPrivate::~HbAbstractItemViewPrivate()
       
    68 {
       
    69     if (mModelIterator) {
       
    70         delete mModelIterator;
       
    71         mModelIterator = 0;
       
    72     }
       
    73 }
       
    74 
       
    75 /*!
       
    76 
       
    77 */
       
    78 void HbAbstractItemViewPrivate::init(HbAbstractItemContainer *container, HbModelIterator *modelIterator)
       
    79 {
       
    80     Q_Q(HbAbstractItemView);
       
    81 
       
    82     q->setLongPressEnabled(true);
       
    83     q->setFlag(QGraphicsItem::ItemIsFocusable, true);
       
    84     q->setFocusPolicy(Qt::StrongFocus);
       
    85     
       
    86     q->setContentWidget(container);
       
    87 
       
    88     mContainer = container;
       
    89     mContainer->setItemView(q);
       
    90 
       
    91     mModelIterator = modelIterator;
       
    92 
       
    93     HbMainWindow *window = q->mainWindow();
       
    94     if (window
       
    95         && q->scene()) { // added to scene
       
    96         q->connect(window, SIGNAL(aboutToChangeOrientation()),
       
    97                    q, SLOT(orientationAboutToBeChanged()));
       
    98 
       
    99         q->connect(window, SIGNAL(orientationChanged(Qt::Orientation)),
       
   100                    q, SLOT(orientationChanged(Qt::Orientation)));
       
   101 
       
   102         if (q->verticalScrollBar()) {
       
   103             q->verticalScrollBar()->installSceneEventFilter(q);
       
   104         }
       
   105         if (q->horizontalScrollBar()) {
       
   106             q->horizontalScrollBar()->installSceneEventFilter(q);
       
   107         }
       
   108     }
       
   109 }
       
   110 
       
   111 /*!
       
   112     Replaces current model with the given one. This deletes the existing
       
   113     view items and calls reset() to update the view to correspond to 
       
   114     current model. 
       
   115 */
       
   116 void HbAbstractItemViewPrivate::setModel(QAbstractItemModel *model)
       
   117 {
       
   118     Q_Q(HbAbstractItemView);
       
   119 
       
   120     if (model != mModelIterator->model()) {
       
   121         mAnimateItems = false;
       
   122         clearCurrentModel();
       
   123         mModelIterator->setModel(model);
       
   124         initializeNewModel();
       
   125 
       
   126         q->reset();
       
   127 
       
   128         if (!mAnimationTimer) {
       
   129             mAnimationTimer = new QTimer(q);
       
   130             mAnimationTimer->setObjectName(QString("animationTimer"));
       
   131             mAnimationTimer->setSingleShot(true);
       
   132 
       
   133             QObject::connect(mAnimationTimer, SIGNAL(timeout()), q, SLOT(_q_animationEnabled()));
       
   134         }
       
   135 
       
   136         mAnimationTimer->start(3000);
       
   137     }
       
   138 }
       
   139 
       
   140 /*!
       
   141     Resets current model,selection Model,mRootIndex and mCurrentIndex to null. 
       
   142 */
       
   143 void HbAbstractItemViewPrivate::clearCurrentModel()
       
   144 {
       
   145     Q_Q(HbAbstractItemView);
       
   146     if (mModelIterator->model()) {
       
   147         QAbstractItemModel *model = mModelIterator->model();
       
   148         q->disconnect(model, SIGNAL(destroyed()),
       
   149                       q, SLOT(_q_modelDestroyed()));
       
   150         q->disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
       
   151                       q, SLOT( dataChanged(QModelIndex,QModelIndex)));
       
   152         q->disconnect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
       
   153                       q, SLOT(rowsInserted(QModelIndex,int,int)));
       
   154         q->disconnect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
       
   155                       q, SLOT(rowsRemoved(QModelIndex,int,int)));
       
   156         q->disconnect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
       
   157                       q, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
       
   158         q->disconnect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
       
   159                       q, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)));
       
   160         q->disconnect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
       
   161                         q, SLOT(columnsInserted(QModelIndex,int,int)));
       
   162         q->disconnect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
       
   163                         q, SLOT(columnsAboutToBeInserted(QModelIndex,int,int)));
       
   164         q->disconnect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
       
   165                         q, SLOT(columnsRemoved(QModelIndex,int,int)));
       
   166         q->disconnect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
       
   167                         q, SLOT(columnsAboutToBeRemoved(QModelIndex,int,int)));
       
   168         q->disconnect(model, SIGNAL(modelReset()), q, SLOT(reset()));
       
   169         q->disconnect(model, SIGNAL(layoutChanged()), q, SLOT(_q_layoutChanged()));
       
   170 
       
   171         mModelIterator->setModel(0);
       
   172     }
       
   173 
       
   174     setSelectionModel(0);
       
   175 
       
   176     mCurrentIndex = QModelIndex();
       
   177     mModelIterator->setRootIndex(QPersistentModelIndex());
       
   178 }
       
   179 
       
   180 /*!
       
   181     Updates current selectionModel to selectionModel.If selectionModel is invalid, current
       
   182     selectionModel is not updated.
       
   183 */
       
   184 void HbAbstractItemViewPrivate::setSelectionModel(QItemSelectionModel *selectionModel)
       
   185 {
       
   186     Q_Q( HbAbstractItemView );
       
   187     if (selectionModel
       
   188         && selectionModel->model() != mModelIterator->model()) {
       
   189         qWarning("QAbstractItemView::setSelectionModel() failed: "
       
   190                  "Trying to set a selection model, which works on "
       
   191                  "a different model than the view.");
       
   192         return;
       
   193     }
       
   194 
       
   195     if (mSelectionModel) {
       
   196         q->disconnect(mSelectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
       
   197                        q, SLOT(currentSelectionChanged(QItemSelection, QItemSelection)));
       
   198 
       
   199         q->disconnect(mSelectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
       
   200                        q, SLOT(currentIndexChanged(QModelIndex, QModelIndex)));
       
   201 
       
   202         delete mSelectionModel;
       
   203         mSelectionModel = 0;
       
   204     }
       
   205 
       
   206     mSelectionModel = selectionModel;
       
   207 
       
   208     if (mSelectionModel) {
       
   209         q->connect(mSelectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
       
   210                    q, SLOT(currentSelectionChanged(QItemSelection, QItemSelection)));
       
   211         q->connect(mSelectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
       
   212                     q, SLOT(currentIndexChanged(QModelIndex, QModelIndex)));
       
   213     }
       
   214 }
       
   215 
       
   216 /*!
       
   217     Initializes newModel
       
   218 */
       
   219 void HbAbstractItemViewPrivate::initializeNewModel()
       
   220 {
       
   221     Q_Q(HbAbstractItemView);
       
   222 
       
   223     if (mModelIterator->model()) {
       
   224         QAbstractItemModel *model = mModelIterator->model();
       
   225         // These asserts do basic sanity checking of the model
       
   226         Q_ASSERT_X(model->index(0,0) == model->index(0,0),
       
   227                    "HbAbstractItemView::setModel",
       
   228                    "A model should return the exact same index "
       
   229                    "(including its internal id/pointer) when asked for it twice in a row.");
       
   230         Q_ASSERT_X(model->index(0,0).parent() == QModelIndex(),
       
   231                    "HbAbstractItemView::setModel",
       
   232                    "The parent of a top level index should be invalid");
       
   233 
       
   234         q->connect(model, SIGNAL(destroyed()),
       
   235                    q, SLOT(_q_modelDestroyed()));
       
   236         q->connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
       
   237                    q, SLOT( dataChanged(QModelIndex,QModelIndex)));
       
   238         q->connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
       
   239                    q, SLOT(rowsInserted(QModelIndex,int,int)));
       
   240         q->connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
       
   241                    q, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
       
   242         q->connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
       
   243                    q, SLOT(rowsRemoved(QModelIndex,int,int)));
       
   244         q->connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
       
   245                    q, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)));
       
   246         q->connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
       
   247                       q, SLOT(columnsInserted(QModelIndex,int,int)));
       
   248         q->connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
       
   249                    q, SLOT(columnsAboutToBeInserted(QModelIndex,int,int)));
       
   250         q->connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
       
   251                       q, SLOT(columnsRemoved(QModelIndex,int,int)));
       
   252         q->connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
       
   253                    q, SLOT(columnsAboutToBeRemoved(QModelIndex,int,int)));
       
   254         q->connect(model, SIGNAL(modelReset()), q, SLOT(reset()));
       
   255         q->connect(model, SIGNAL(layoutChanged()), q, SLOT(_q_layoutChanged()));
       
   256 
       
   257         setSelectionModel(new QItemSelectionModel(model, q));
       
   258     }   
       
   259 }
       
   260 
       
   261 /*!
       
   262     \private
       
   263 
       
   264     Slot is called whenever the model is destroyed.
       
   265     deletes all children and disconnects all signal- slot connections
       
   266     with model and selectionmodel
       
   267 */
       
   268 void HbAbstractItemViewPrivate::_q_modelDestroyed()
       
   269 {
       
   270     Q_Q(HbAbstractItemView);
       
   271 
       
   272     mModelIterator->setModel(0);
       
   273     setSelectionModel(0);
       
   274     q->reset();
       
   275 }
       
   276 
       
   277 /*!
       
   278     \private
       
   279 
       
   280     Slot is called whenever the model layout changes. This resets the container.
       
   281 */
       
   282 void HbAbstractItemViewPrivate::_q_layoutChanged()
       
   283 {
       
   284     mContainer->setModelIndexes(mModelIterator->nextIndex(QModelIndex()));
       
   285 }
       
   286 
       
   287 void HbAbstractItemViewPrivate::_q_animationEnabled()
       
   288 {
       
   289     mAnimateItems = true;
       
   290 }
       
   291 
       
   292 void HbAbstractItemViewPrivate::_q_animationFinished(const HbEffect::EffectStatus &status)
       
   293 {
       
   294     Q_UNUSED(status);
       
   295     if ( status.effectEvent == "appear") {
       
   296         if (mPostponedScrollIndex.isValid()) { 
       
   297             int count = mAppearAnimationIndexes.count();
       
   298             for (int i=0; i<count; i++) {
       
   299                 if (mPostponedScrollIndex == mAppearAnimationIndexes.at(i)) {
       
   300                     scrollTo(mPostponedScrollIndex, mPostponedScrollHint);
       
   301                     break;
       
   302                 }
       
   303             }
       
   304         } 
       
   305         mAppearAnimationIndexes.clear();
       
   306     }
       
   307 }
       
   308 
       
   309 /*!
       
   310     \private
       
   311 
       
   312     When orientation switch occurs, 1) or 2) is applied to view after layout switch:
       
   313           1) if current item is wholly visible, it will be visible
       
   314           2) if current item is not wholly visible, first visible item before layout switch is made visible
       
   315           In either case the visible item is at top of the view or as near as possible
       
   316  */
       
   317 void HbAbstractItemViewPrivate::saveIndexMadeVisibleAfterMetricsChange()
       
   318 {
       
   319     QModelIndex firstVisibleModelIndex;
       
   320     QModelIndex lastVisibleModelIndex;
       
   321     mContainer->firstAndLastVisibleModelIndex(firstVisibleModelIndex, lastVisibleModelIndex);
       
   322 
       
   323     int firstVisibleRow = firstVisibleModelIndex.isValid() ? firstVisibleModelIndex.row() : 0;
       
   324     int lastVisibleRow = lastVisibleModelIndex.isValid() ? lastVisibleModelIndex.row() : 0;
       
   325 
       
   326     // save current, if it is visible
       
   327     firstVisibleRow = qMax(0, firstVisibleRow);
       
   328     lastVisibleRow = qMax(0, lastVisibleRow);
       
   329 
       
   330     if (mCurrentIndex.row() >= firstVisibleRow 
       
   331         && mCurrentIndex.row() <= lastVisibleRow) {
       
   332         mVisibleIndex = mCurrentIndex;
       
   333     } else if (mModelIterator->model()) {
       
   334         mVisibleIndex = mModelIterator->index(firstVisibleRow);
       
   335     }
       
   336 }
       
   337 
       
   338 /*!
       
   339     \private
       
   340 
       
   341     Minimum amount of pixels to scroll to make \a item visible.
       
   342     Negative value scrolls view up, and positive value vice versa.
       
   343     Returns 0, if no scrolling is needed.
       
   344 
       
   345     Horizontally ensures that item is visible. 
       
   346  */
       
   347 QPointF HbAbstractItemViewPrivate::pixelsToScroll(const HbAbstractViewItem *item,
       
   348                                                   HbAbstractItemView::ScrollHint hint)
       
   349 {
       
   350     Q_Q(HbAbstractItemView);
       
   351 
       
   352     QPointF result(0,0);
       
   353 
       
   354     if (item) {
       
   355         refreshContainerGeometry();
       
   356 
       
   357         QRectF itemRect = itemBoundingRect(item);
       
   358         QRectF viewRect = q->boundingRect();
       
   359 
       
   360         if (!viewRect.isValid()) {
       
   361             return result;
       
   362         }
       
   363 
       
   364         QSizeF sizeOffset;
       
   365         sizeOffset.setHeight(qMin(itemRect.height(), viewRect.height()));
       
   366         sizeOffset.setWidth(qMin(itemRect.width(), viewRect.width()));
       
   367 
       
   368         if (mScrollDirections & Qt::Vertical) {
       
   369             switch (hint) {
       
   370                 case HbAbstractItemView::PositionAtTop: {
       
   371                     result.setY(itemRect.bottom() - viewRect.top() - sizeOffset.height());
       
   372                     break;
       
   373                 }
       
   374                 case HbAbstractItemView::PositionAtBottom: {
       
   375                     result.setY(itemRect.top() + sizeOffset.height() - viewRect.bottom());
       
   376                     break;
       
   377                 }
       
   378                 case HbAbstractItemView::PositionAtCenter: {
       
   379                     qreal yCentre = viewRect.top() + (viewRect.height()) / 2 ;
       
   380                     result.setY(itemRect.top() - yCentre + sizeOffset.height()/2);
       
   381                     break;
       
   382                 }
       
   383                 case HbAbstractItemView::EnsureVisible:
       
   384                 default: {
       
   385                     if (itemRect.top() < viewRect.top()) { 
       
   386                         result.setY(itemRect.bottom() - viewRect.top() - sizeOffset.height());
       
   387                     } else if (itemRect.bottom() > viewRect.bottom()) {
       
   388                         result.setY(itemRect.top() + sizeOffset.height() - viewRect.bottom());
       
   389                     }
       
   390                     break;
       
   391                 }
       
   392             }
       
   393 
       
   394             if (itemRect.width() < viewRect.width()) {
       
   395                 if (itemRect.left() < viewRect.left()) {
       
   396                     result.setX(itemRect.left() - viewRect.left());
       
   397                 } else if (itemRect.right() > viewRect.right()) {
       
   398                     result.setX(itemRect.right() - viewRect.right());
       
   399                 }
       
   400             } else {
       
   401                 // item does not fit in the screen, always align according to 
       
   402                 // mirroring 
       
   403                 if (HbApplication::layoutDirection() == Qt::LeftToRight) {
       
   404                     result.setX(itemRect.left() - viewRect.left());
       
   405                 } else {                
       
   406                     result.setX(itemRect.right() - viewRect.right());
       
   407                 }
       
   408             }
       
   409         }
       
   410         else if (mScrollDirections & Qt::Horizontal) {
       
   411             switch (hint) {
       
   412                 case HbAbstractItemView::PositionAtTop: {    // left
       
   413                     result.setX(itemRect.right() - viewRect.left() - sizeOffset.width());
       
   414                     break;
       
   415                 }
       
   416                 case HbAbstractItemView::PositionAtBottom: { // right
       
   417                     result.setX(itemRect.left() + sizeOffset.width() - viewRect.right());
       
   418                     break;
       
   419                 }
       
   420                 case HbAbstractItemView::PositionAtCenter: {
       
   421                     qreal xCentre = viewRect.left() + (viewRect.width()) / 2 ;
       
   422                     result.setX(itemRect.left() - xCentre + sizeOffset.width()/2);
       
   423                     break;
       
   424                 }
       
   425                 case HbAbstractItemView::EnsureVisible:
       
   426                 default: {
       
   427                     if (itemRect.left() < viewRect.left()) { 
       
   428                         result.setX(itemRect.right() - viewRect.left() - sizeOffset.width());
       
   429                     } else if (itemRect.right() > viewRect.right()) {
       
   430                         result.setX(itemRect.left() + sizeOffset.width() - viewRect.right());
       
   431                     }
       
   432                     break;
       
   433                 }
       
   434             }
       
   435 
       
   436             if (itemRect.top() < viewRect.top()) {
       
   437                 result.setY(itemRect.top() - viewRect.top());
       
   438             } else if (itemRect.bottom() > viewRect.bottom()) {
       
   439                 result.setY(itemRect.bottom() - viewRect.bottom());
       
   440             }
       
   441         }
       
   442     }
       
   443 
       
   444     return result;
       
   445 }
       
   446 
       
   447 QItemSelectionModel::SelectionFlags HbAbstractItemViewPrivate::singleSelectionCommand(
       
   448         const HbAbstractViewItem *item,
       
   449         const QEvent *event)
       
   450 {
       
   451     if (item) {
       
   452         switch (event->type())  {
       
   453         case QEvent::GraphicsSceneMousePress: 
       
   454         case QEvent::GraphicsSceneMouseDoubleClick:
       
   455             if (item->selectionAreaContains(static_cast<const QGraphicsSceneMouseEvent *>(event)->scenePos())) {
       
   456                 mSelectionSettings |= Selection;
       
   457             }
       
   458             break;
       
   459         case QEvent::GraphicsSceneMouseRelease:
       
   460             if (    mHitItem
       
   461                 &&  item->modelIndex() == mHitItem->modelIndex()
       
   462                 &&  mSelectionSettings.testFlag(Selection)) {
       
   463                 mSelectionSettings &= ~Selection;
       
   464                 return QItemSelectionModel::ClearAndSelect;
       
   465             }
       
   466             break;
       
   467         default:
       
   468             break;
       
   469         }
       
   470     }
       
   471 
       
   472     return QItemSelectionModel::NoUpdate;
       
   473 }
       
   474 
       
   475 
       
   476 QItemSelectionModel::SelectionFlags HbAbstractItemViewPrivate::multiSelectionCommand(
       
   477         const HbAbstractViewItem *item,
       
   478         const QEvent *event)
       
   479 {
       
   480     if (item) {
       
   481         switch (event->type())  {
       
   482         case QEvent::GraphicsSceneMousePress: 
       
   483         case QEvent::GraphicsSceneMouseDoubleClick:
       
   484             if (item->selectionAreaContains(static_cast<const QGraphicsSceneMouseEvent *>(event)->scenePos())) {
       
   485                 mSelectionSettings |= Selection;
       
   486             }
       
   487             break;
       
   488         case QEvent::GraphicsSceneMouseRelease:
       
   489             if (mHitItem
       
   490                 && item->modelIndex() == mHitItem->modelIndex() 
       
   491                 && mSelectionSettings.testFlag(Selection)) {
       
   492                 mSelectionSettings &= ~Selection;
       
   493                 return QItemSelectionModel::Toggle;
       
   494             }
       
   495             break;
       
   496         default:
       
   497             break;
       
   498         }
       
   499     }
       
   500     return QItemSelectionModel::NoUpdate;
       
   501 }
       
   502 
       
   503 QItemSelectionModel::SelectionFlags HbAbstractItemViewPrivate::contiguousSelectionCommand(
       
   504         const HbAbstractViewItem *item,
       
   505         const QEvent *event )
       
   506 {
       
   507     Q_Q(HbAbstractItemView);
       
   508     if (item) {
       
   509         switch (event->type()) {
       
   510         case QEvent::GraphicsSceneMousePress: 
       
   511         case QEvent::GraphicsSceneMouseDoubleClick: {
       
   512             if (item->selectionAreaContains(static_cast<const QGraphicsSceneMouseEvent *>(event)->scenePos())) {
       
   513                 mSelectionSettings |= Selection;
       
   514 
       
   515                 if (mSelectionModel && mSelectionModel->isSelected(item->modelIndex())) {
       
   516                     mContSelectionAction = QItemSelectionModel::Deselect;
       
   517                 } else {
       
   518                     mContSelectionAction = QItemSelectionModel::Select;
       
   519                 }
       
   520 
       
   521                 // TODO: This should be changed to changing the gesture area of effect when that is possible...
       
   522                 // Gesture filter does not reset all of its internals: workaround is to delete and create the filter
       
   523                 q->setLongPressEnabled(false);
       
   524                 q->removeSceneEventFilter(mGestureFilter);
       
   525                 mFilterRemoved = true;
       
   526             }
       
   527             break;
       
   528             }
       
   529         case QEvent::GraphicsSceneMouseRelease: {
       
   530             QItemSelectionModel::SelectionFlag flags =  QItemSelectionModel::NoUpdate;
       
   531             if (mSelectionSettings.testFlag(Selection)){
       
   532                 flags = mContSelectionAction;
       
   533                 mSelectionSettings &= ~Selection;
       
   534                 mContSelectionAction = QItemSelectionModel::NoUpdate;
       
   535             } 
       
   536             
       
   537             if (mFilterRemoved) {
       
   538                 // setLongPressEnabled installs filter
       
   539                 q->setLongPressEnabled(true);
       
   540                 mFilterRemoved = false;
       
   541             }
       
   542             return flags;
       
   543             }
       
   544         case QEvent::GraphicsSceneMouseMove:
       
   545             return mContSelectionAction;
       
   546         default:
       
   547             break;
       
   548         }
       
   549     }
       
   550     return QItemSelectionModel::NoUpdate;
       
   551 }
       
   552 
       
   553 /*!
       
   554     Overwrites the default scroll area scrollbar updating algorithm when
       
   555     recycling is used. On recycling the scrollbar position & size is calculated
       
   556     using rows and their pixel size is not used.
       
   557 */
       
   558 void HbAbstractItemViewPrivate::updateScrollBar(Qt::Orientation orientation)
       
   559 {
       
   560     if (!handleScrollBar(orientation)) {
       
   561         HbScrollAreaPrivate::updateScrollBar(orientation);
       
   562     } else {
       
   563         if (mContainer->layout() && !mContainer->layout()->isActivated()) {
       
   564             mContainer->layout()->activate();
       
   565         }
       
   566 
       
   567         if (mContainer->uniformItemSizes()) {
       
   568             updateScrollBarForUniformSizedItems();
       
   569         } else {
       
   570             updateScrollBarForVariableSizedItems();
       
   571         }
       
   572     } 
       
   573 }
       
   574 
       
   575 /*!
       
   576     Returns the abstract view item from given scene position, if there is any.
       
   577 */
       
   578 HbAbstractViewItem *HbAbstractItemViewPrivate::itemAt(const QPointF& position) const
       
   579 {
       
   580     Q_Q(const HbAbstractItemView);
       
   581 
       
   582     HbAbstractViewItem *hitItem = 0;
       
   583     QList<QGraphicsItem *> items = q->scene()->items(position);
       
   584     
       
   585     int count = items.count();
       
   586     for (int current = 0; current < count; ++current) {
       
   587         QGraphicsItem *item = items.at(current);
       
   588         hitItem = viewItem(item);
       
   589         // second condition needed, because in form there can be radio button list 
       
   590         // and list of the form itself on top of each other
       
   591         if (hitItem && mContainer->items().indexOf(hitItem) != -1)
       
   592             return hitItem;
       
   593     }
       
   594     return hitItem;
       
   595 }
       
   596 
       
   597 /*!
       
   598     
       
   599 */
       
   600 void HbAbstractItemViewPrivate::refreshContainerGeometry()
       
   601 {
       
   602     Q_Q(const HbAbstractItemView);
       
   603 
       
   604     if (mContainer->layout())  {
       
   605         if (!mContainer->layout()->isActivated()) {
       
   606             // Make sure that the layout process has stopped.
       
   607             mContainer->layout()->activate();
       
   608         }
       
   609     } 
       
   610 
       
   611     QSizeF newSize = mContainer->effectiveSizeHint(Qt::PreferredSize);
       
   612 
       
   613     if (!mScrollDirections.testFlag(Qt::Vertical)) {
       
   614         newSize.setHeight(q->size().height());
       
   615     } 
       
   616     
       
   617     if (!mScrollDirections.testFlag(Qt::Horizontal)) {
       
   618         newSize.setWidth(q->size().width());
       
   619     }
       
   620        
       
   621     mContainer->resize( newSize );    
       
   622 }
       
   623 
       
   624 
       
   625 QRectF HbAbstractItemViewPrivate::itemBoundingRect(const QGraphicsItem *item) const
       
   626     {
       
   627         Q_Q(const HbAbstractItemView);
       
   628 
       
   629         if (mContainer) {
       
   630             QGraphicsLayout *containerLayout = mContainer->layout();
       
   631             if (containerLayout) {
       
   632                 containerLayout->activate();
       
   633             }
       
   634         }
       
   635 
       
   636         return item->mapToItem(q, item->boundingRect()).boundingRect();
       
   637     }
       
   638 
       
   639 /*!
       
   640     Returns true if given item is located within viewport (i.e.  view), otherwise
       
   641     returns false. If fullyVisible parameter is true method will return true only
       
   642     for item that is shown fully. In this case for partially visible items false is returned.
       
   643 */
       
   644 bool HbAbstractItemViewPrivate::visible(HbAbstractViewItem* item, bool fullyVisible) const
       
   645 {
       
   646     Q_Q(const HbAbstractItemView);
       
   647     bool visible = false;
       
   648     if (item) {
       
   649         QRectF itemRect(itemBoundingRect(item));
       
   650         QRectF abstractViewRect(itemBoundingRect(q));
       
   651         if (fullyVisible) {
       
   652             if (abstractViewRect.contains(itemRect)) {
       
   653                 visible = true;
       
   654             }
       
   655         } else {
       
   656             if (abstractViewRect.intersects(itemRect)) {
       
   657                 visible = true;
       
   658             }
       
   659         }
       
   660     }
       
   661     return visible;
       
   662 }
       
   663 
       
   664 /*!
       
   665     Returns current Item.
       
   666 */
       
   667 HbAbstractViewItem* HbAbstractItemViewPrivate::currentItem() const
       
   668 {
       
   669     return mContainer->itemByIndex(mCurrentIndex);
       
   670 }
       
   671 
       
   672 /*!
       
   673         Tries to convert given graphics item to HbLIstViewItem.
       
   674         qgraphicsitem_cast cannot be used here as it does not support subclassing.
       
   675         Also qobject_cast cannot be used directly as QGraphicsItem is not derived from 
       
   676         QObject. But you can ask qgraphicsitem whether it is a widget or not
       
   677         and cast the item to widget based on this information. After the item is
       
   678         casted to widget then qobject_cast can be used.
       
   679 */
       
   680 HbAbstractViewItem* HbAbstractItemViewPrivate::viewItem(QGraphicsItem *item) const
       
   681     {
       
   682         HbAbstractViewItem *result = 0;
       
   683         if (item && item->isWidget()) {
       
   684             result = qobject_cast<HbAbstractViewItem *>(static_cast<QGraphicsWidget *>(item));
       
   685         }
       
   686         return result;
       
   687     }
       
   688 
       
   689 void HbAbstractItemViewPrivate::updateItems()
       
   690 {
       
   691     QList<HbAbstractViewItem *> items = mContainer->items();
       
   692     foreach (HbAbstractViewItem *item, items) {
       
   693         item->updateChildItems();
       
   694     }
       
   695 }
       
   696 
       
   697 void HbAbstractItemViewPrivate::scrollTo(const QModelIndex &index, HbAbstractItemView::ScrollHint hint)
       
   698 {
       
   699     Q_Q(HbAbstractItemView);
       
   700     // when called from HbAbstractItemView::scrollTo(), mPostponedScrollIndex is invalid
       
   701     HbAbstractViewItem *viewItem = q->itemByIndex(index);
       
   702     if (viewItem) {
       
   703         HbScrollArea::ClampingStyle clampingStyle = mClampingStyle;
       
   704         if (clampingStyle == HbScrollArea::BounceBackClamping) {
       
   705             mClampingStyle = HbScrollArea::StrictClamping;
       
   706         }
       
   707         revealItem(viewItem, hint);
       
   708         mClampingStyle = clampingStyle;
       
   709     } else if (     index.isValid()
       
   710                 &&  index == mPostponedScrollIndex) {
       
   711         q->scrollTo(index, hint);
       
   712     }
       
   713 }
       
   714 
       
   715 void HbAbstractItemViewPrivate::revealItem(const HbAbstractViewItem *item, 
       
   716                                             HbAbstractItemView::ScrollHint hint )
       
   717 {
       
   718     Q_Q(HbAbstractItemView);
       
   719     QPointF delta = pixelsToScroll(item, hint);
       
   720     if (delta != QPointF()) {
       
   721         QPointF newPos = -mContainer->pos() + delta;
       
   722         checkBoundaries(newPos);
       
   723         // scroll area logic is oposite to real position
       
   724         q->scrollContentsTo(newPos);
       
   725     }
       
   726 }
       
   727 void HbAbstractItemViewPrivate::checkBoundaries(QPointF &newPos)
       
   728 {
       
   729     Q_Q(HbAbstractItemView);
       
   730 
       
   731     if (mClampingStyle != HbScrollArea::NoClamping) {
       
   732         QRectF viewRect = q->boundingRect();
       
   733         QSizeF containerSize = mContainer->layout()->preferredSize();
       
   734         
       
   735         if (newPos.y() < topBoundary() ) {
       
   736             newPos.setY(topBoundary());
       
   737         }
       
   738 
       
   739         // it is possible that above checking set newPos.y > 0
       
   740         if (newPos.y() > bottomBoundary()) {
       
   741             newPos.setY(bottomBoundary()); 
       
   742         }
       
   743             
       
   744         if (newPos.x() < leftBoundary() ) {
       
   745             newPos.setX(leftBoundary());
       
   746         }
       
   747 
       
   748         // it is possible that above checking set newPos.x > 0
       
   749         if (newPos.x() > rightBoundary()) {
       
   750             newPos.setX(rightBoundary()); 
       
   751         }
       
   752     }
       
   753 }
       
   754 
       
   755 void HbAbstractItemViewPrivate::updateScrollBarForUniformSizedItems()
       
   756 {
       
   757     Q_Q(const HbAbstractItemView);
       
   758     
       
   759     HbAbstractViewItem *firstItem = mContainer->items().first();
       
   760     qreal uniformItemHeight = firstItem->size().height();
       
   761     qreal containerVirtualHeight = uniformItemHeight *  (mModelIterator->indexCount());
       
   762     qreal thumbPosition(0);
       
   763     int firstBufferItemRowNumber = mModelIterator->indexPosition(firstItem->modelIndex());
       
   764      
       
   765     QRectF itemRect = itemBoundingRect(firstItem);
       
   766     qreal realTopBoundary = itemRect.top();   
       
   767     qreal virtualTopBoundary = realTopBoundary - (firstBufferItemRowNumber*uniformItemHeight); 
       
   768    
       
   769     if ((containerVirtualHeight - q->boundingRect().height()) != 0) {
       
   770         thumbPosition = 
       
   771             (-virtualTopBoundary) / (containerVirtualHeight - q->boundingRect().height());
       
   772     }  
       
   773  
       
   774     thumbPosition = qBound((qreal)0.0, thumbPosition, (qreal)1.0);
       
   775  
       
   776     if (mVerticalScrollBar) {
       
   777         if (containerVirtualHeight!=0) {
       
   778             mVerticalScrollBar->setPageSize(qBound ( (qreal)0.0,
       
   779                                      q->boundingRect().height() / containerVirtualHeight,
       
   780                                       (qreal)1.0));
       
   781         }
       
   782         mVerticalScrollBar->setValue(thumbPosition); 
       
   783     }    
       
   784 }
       
   785 
       
   786 void HbAbstractItemViewPrivate::setScrollBarMetrics(Qt::Orientation orientation)
       
   787 {   
       
   788     if (!handleScrollBar(orientation) ) {
       
   789         HbScrollAreaPrivate::setScrollBarMetrics(orientation);
       
   790     } else {
       
   791         //We just make sure that the base clas is not called
       
   792         //It set the page size wrongly
       
   793         updateScrollBar(orientation); 
       
   794     }
       
   795 }
       
   796 
       
   797 /*!
       
   798     This function combines the conditions to solve whether the scroll bar calcultion should be handled in
       
   799     this class or is the base class calculation sufficient
       
   800 */
       
   801 bool  HbAbstractItemViewPrivate::handleScrollBar(Qt::Orientation orientation)
       
   802 {
       
   803     if (!mContainer->itemRecycling()
       
   804         || mContainer->itemPrototypes().count() != 1 
       
   805         || orientation == Qt::Horizontal
       
   806         || mContainer->items().count() == 0) {
       
   807             return false;
       
   808     } else {
       
   809         return true;
       
   810     }
       
   811 }
       
   812 
       
   813 void HbAbstractItemViewPrivate::updateScrollBarForVariableSizedItems()
       
   814 {
       
   815     Q_Q(const HbAbstractItemView);
       
   816     HbAbstractViewItem *firstItem = mContainer->items().first();
       
   817  
       
   818     // View position is the amount of hidden (fully or partially)
       
   819     // rows above the view area.
       
   820     int position = mModelIterator->indexPosition(firstItem->modelIndex());
       
   821     if (position == -1) {
       
   822         return; 
       
   823     }
       
   824     qreal viewY = (qreal)(position);
       
   825 
       
   826     // View area height is the amount of rows within the view area.
       
   827     qreal viewH = 0;
       
   828 
       
   829     //Index count calculation is time consuming with tree
       
   830     int indexCount = mModelIterator->indexCount();
       
   831 
       
   832     // Total height is the amount of rows in the model.
       
   833     qreal totalH = indexCount;
       
   834 
       
   835     qreal itemTop = firstItem->mapToItem(q, firstItem->pos()).y();
       
   836     qreal viewHeight = q->size().height();
       
   837     int itemCount = mContainer->items().count();
       
   838     
       
   839     for (int i=0; i < itemCount; ++i) {
       
   840         qreal itemHeight = mContainer->items().at(i)->size().height();
       
   841         qreal itemBottom = itemTop + itemHeight;
       
   842         if (itemTop < 0) {
       
   843             // Some part of the item is above the view area.
       
   844             if (itemBottom < 0) {
       
   845                 // Fully above the view area
       
   846                 viewY += 1;
       
   847             } else {
       
   848                 // Partially at the view area and partially above the view area.
       
   849                 viewY += (1.0 - itemBottom / itemHeight);
       
   850                 viewH += itemBottom / itemHeight;
       
   851             }
       
   852         } else if (itemTop < viewHeight) {
       
   853             // So part of the item is at the view area.
       
   854             if (itemBottom < viewHeight) {
       
   855                 // Fully at the view area
       
   856                 viewH += 1;
       
   857             } else {
       
   858                 // Partially at the view area and partially below the view area.
       
   859                 viewH += (viewHeight - itemTop) / itemHeight;
       
   860             }
       
   861         } else {
       
   862             break;
       
   863         }
       
   864 
       
   865         itemTop += itemHeight;
       
   866     }
       
   867 
       
   868     // Shifting the values to scrollbar range that is from 0.0-1.0. 
       
   869     qreal pos = viewY / (totalH - viewH);
       
   870     pos = qBound((qreal)0.0, pos, (qreal)1.0);
       
   871 
       
   872     if (mVerticalScrollBar) {
       
   873         if (indexCount!=0) {
       
   874             mVerticalScrollBar->setPageSize(viewH / (qreal)(indexCount));
       
   875         }
       
   876         mVerticalScrollBar->setValue(pos);
       
   877     }    
       
   878 }
       
   879 
       
   880 void HbAbstractItemViewPrivate::rowsRemoved(const QModelIndex &parent,int start,int end)
       
   881 {
       
   882     if (mModelIterator->model()->columnCount(parent) == 0) {
       
   883         return;
       
   884     }
       
   885 
       
   886     if (start <= mCurrentIndex.row() && mCurrentIndex.row() <= end) {
       
   887         // new current: 1) next after last deleted (note that
       
   888         // start and end index in model prior to deleting)
       
   889         // 2) just before first deleted
       
   890         QModelIndex newCurrentIndex = mModelIterator->model()->index(start, 0, parent);
       
   891         if (!newCurrentIndex.isValid()) {
       
   892             newCurrentIndex = mModelIterator->model()->index(qMax(0,start-1), 0, parent);
       
   893         }
       
   894 
       
   895         if (mSelectionModel) {
       
   896             mSelectionModel->setCurrentIndex(newCurrentIndex, QItemSelectionModel::NoUpdate);
       
   897         } 
       
   898     }
       
   899 
       
   900     for (int current = end; current >= start; --current) {
       
   901         //The items are already removed from the model. That's why their indexes are already invalid.
       
   902         //Here we loop the items in container and call removeItem() with QModelIndex().
       
   903         bool animate = mEnabledAnimations & HbAbstractItemView::Disappear ? mAnimateItems : false;
       
   904         mContainer->removeItem(QModelIndex(), animate);
       
   905     }
       
   906 }
       
   907 
       
   908 QItemSelectionModel::SelectionFlags HbAbstractItemViewPrivate::selectionFlags( 
       
   909                                                     const HbAbstractViewItem *item, 
       
   910                                                     const QEvent *event)
       
   911 {
       
   912     if (!item || !item->modelIndex().isValid() || !(item->flags() & QGraphicsItem::ItemIsSelectable))
       
   913         return QItemSelectionModel::NoUpdate;
       
   914 
       
   915     QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::NoUpdate;
       
   916     if (item && mHitItem && event){
       
   917         switch (mSelectionMode) {
       
   918         case HbAbstractItemView::SingleSelection: 
       
   919             flags =  singleSelectionCommand(item, event);
       
   920             break;
       
   921         case HbAbstractItemView::MultiSelection:
       
   922             flags =  multiSelectionCommand(item, event);
       
   923             break;
       
   924         case HbAbstractItemView::ContiguousSelection: {
       
   925             flags = contiguousSelectionCommand(item, event);
       
   926             break;
       
   927         }
       
   928         case HbAbstractItemView::NoSelection: // Never update selection model
       
   929             break;
       
   930         }
       
   931     }
       
   932 
       
   933     return flags;
       
   934 }
       
   935 
       
   936 void HbAbstractItemViewPrivate::resetContainer()
       
   937 {
       
   938     mPostponedScrollIndex = QPersistentModelIndex();
       
   939     mContainer->reset();
       
   940 }
       
   941 
       
   942 void HbAbstractItemViewPrivate::startAppearEffect(const QModelIndex &parent, int start, int end)
       
   943 {
       
   944     Q_Q(HbAbstractItemView);
       
   945     if( mAppearAnimationIndexes.count()) {
       
   946         mAppearAnimationIndexes.clear();
       
   947     }
       
   948     QList< QGraphicsItem * >items;
       
   949     for (int i = start; i <= end; i++) {
       
   950         QPersistentModelIndex index = mModelIterator->index(i, parent);
       
   951         HbAbstractViewItem *item = q->itemByIndex(index);
       
   952         if (item) {
       
   953             items.append(item);
       
   954             mAppearAnimationIndexes.append(index);
       
   955         }
       
   956     }
       
   957 
       
   958     refreshContainerGeometry();
       
   959 
       
   960     HbEffect::start(items, "viewitem", "appear", q, "_q_animationFinished");
       
   961 }
       
   962 
       
   963 void HbAbstractItemViewPrivate::ensureVisible(QPointF position, qreal xMargin, qreal yMargin)
       
   964 {
       
   965     mPostponedScrollIndex = QPersistentModelIndex();
       
   966     HbScrollAreaPrivate::ensureVisible(position, xMargin, yMargin);
       
   967 }
       
   968 
       
   969