ganeswidgets/src/HgContainer.cpp
changeset 0 89c329efa980
child 1 e48454f237ca
equal deleted inserted replaced
-1:000000000000 0:89c329efa980
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 #include <QGesture>
       
    19 #include <QPainter>
       
    20 #include <QTimer>
       
    21 #include <hbgridviewitem>
       
    22 #include <hbmainwindow>
       
    23 #include "hgcontainer.h"
       
    24 #include "hgmediawallrenderer.h"
       
    25 #include "hgquad.h"
       
    26 #include "hgvgquadrenderer.h"
       
    27 #include "hgvgimage.h"
       
    28 #include "hgwidgetitem.h"
       
    29 #include "trace.h"
       
    30 
       
    31 #include <hbgridviewitem>
       
    32 #include <hbgridview>
       
    33 #include <hbiconitem>
       
    34 #include <qabstractitemmodel>
       
    35 #include "hglongpressvisualizer.h"
       
    36 
       
    37 static const qreal KSpringKScrolling(50.0);
       
    38 static const qreal KSpringKScrollBar(10.0);
       
    39 static const qreal KSpringDampingScrolling(20.0);
       
    40 static const qreal KSpringDampingScrollBar(5.0);
       
    41 static const qreal KFramesToZeroVelocity(60.0);
       
    42 static const int   KLongTapDuration(400);
       
    43 
       
    44 
       
    45 HgContainer::HgContainer(QGraphicsItem* parent) :
       
    46     HbWidget(parent),
       
    47     mQuadRenderer(0),
       
    48     mRenderer(0),
       
    49     mTapCount(0),
       
    50     mAnimateUsingScrollBar(false),
       
    51     mSelectionMode(HgWidget::NoSelection),
       
    52     mSelectionModel(0),
       
    53     mMarkImage(0),
       
    54     mSpringVelAtDragStart(0),
       
    55     mDragged(false),
       
    56     mFramesDragged(0),
       
    57     mHitItemView(NULL),
       
    58     mLongPressVisualizer(NULL),
       
    59     mLongPressTimer(NULL),
       
    60     mHitItemIndex(NULL)
       
    61 {
       
    62     FUNC_LOG;
       
    63     
       
    64     grabGesture(Qt::PanGesture);
       
    65     grabGesture(Qt::TapGesture);
       
    66     grabGesture(Qt::TapAndHoldGesture);
       
    67 }
       
    68 
       
    69 HgContainer::~HgContainer()
       
    70 {
       
    71     FUNC_LOG;
       
    72 
       
    73     for (QList<HgWidgetItem*>::iterator i = mItems.begin(); i != mItems.end(); ++i) {
       
    74         delete (*i);
       
    75     }
       
    76     mItems.clear();
       
    77     delete mMarkImage;
       
    78     delete mRenderer;
       
    79 }
       
    80 
       
    81 void HgContainer::setItemCount(int itemCount)
       
    82 {
       
    83     FUNC_LOG;
       
    84 
       
    85     mItems.clear();
       
    86     for (int i=0; i<itemCount; i++) {
       
    87         HgWidgetItem* item = new HgWidgetItem(mQuadRenderer);
       
    88         mItems.append(item);
       
    89     }
       
    90 }
       
    91 
       
    92 int HgContainer::itemCount() const
       
    93 {
       
    94     return mItems.count();
       
    95 }
       
    96 
       
    97 int HgContainer::rowCount() const
       
    98 {
       
    99     return mRenderer ? mRenderer->getRowCount() : 0;
       
   100 }
       
   101 
       
   102 QList<HgWidgetItem*> HgContainer::items() const
       
   103 {
       
   104     return mItems;
       
   105 }
       
   106 
       
   107 HgWidgetItem* HgContainer::itemByIndex(const QModelIndex& index) const
       
   108 {
       
   109     foreach (HgWidgetItem* item, mItems) {
       
   110         if (item->modelIndex() == index)
       
   111             return item;
       
   112     }
       
   113 
       
   114     return 0;
       
   115 }
       
   116 
       
   117 HgWidgetItem* HgContainer::itemByIndex(const int& index) const
       
   118 {
       
   119     if (mItems.count() > index && index >= 0)
       
   120         return mItems.at(index);
       
   121     else
       
   122         return 0;
       
   123 }
       
   124 
       
   125 /*!
       
   126     Changes the selection model of the container.
       
   127     Ownership is not transferred.
       
   128     Widget is redrawn to make new selection visible.
       
   129 */
       
   130 void HgContainer::setSelectionModel(QItemSelectionModel *selectionModel)
       
   131 {
       
   132     FUNC_LOG;
       
   133     HANDLE_ERROR_NULL(selectionModel); // Parameter is always a valid QItemSelectionModel
       
   134 
       
   135     if (mSelectionModel != selectionModel) {
       
   136         if (mSelectionModel) { // mSelectionModel is 0 when called first time
       
   137             mSelectionModel->disconnect(SIGNAL(currentChanged(QModelIndex,QModelIndex)), this);
       
   138 
       
   139             if (mSelectionModel->currentIndex().isValid() &&
       
   140                 !(selectionModel->currentIndex().isValid())) {
       
   141                 selectionModel->setCurrentIndex(mSelectionModel->currentIndex(),
       
   142                     QItemSelectionModel::Current);
       
   143             }
       
   144         }
       
   145         mSelectionModel = selectionModel;
       
   146         connect(mSelectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
       
   147                                  SLOT(updateByCurrentIndex(QModelIndex)));
       
   148         update();
       
   149     }
       
   150 }
       
   151 
       
   152 /*!
       
   153     Returns the selection model of the container.
       
   154     Ownership is not transferred.
       
   155 */
       
   156 QItemSelectionModel *HgContainer::selectionModel() const
       
   157 {
       
   158     FUNC_LOG;
       
   159 
       
   160     return mSelectionModel;
       
   161 }
       
   162 
       
   163 /*!
       
   164     Changes the selection mode of the container (no selection/multiselection).
       
   165 */
       
   166 void HgContainer::setSelectionMode(HgWidget::SelectionMode mode, bool resetSelection)
       
   167 {
       
   168     FUNC_LOG;
       
   169 
       
   170     if (mSelectionMode != mode) {
       
   171         mSelectionMode = mode;
       
   172 
       
   173         if (mSelectionModel && resetSelection) {
       
   174             mSelectionModel->clearSelection();
       
   175             update();
       
   176         }
       
   177     }
       
   178 }
       
   179 
       
   180 /*!
       
   181     Returns the selection mode of the container (no selection/multiselection).
       
   182 */
       
   183 HgWidget::SelectionMode HgContainer::selectionMode() const
       
   184 {
       
   185     FUNC_LOG;
       
   186 
       
   187     return mSelectionMode;
       
   188 }
       
   189 
       
   190 void HgContainer::dimensions(qreal &screenSize, qreal &worldSize)
       
   191 {
       
   192     const QRectF containerRect(rect());
       
   193 
       
   194     // TODO, fix logic
       
   195     if (containerRect.height() > containerRect.width()) {
       
   196         // assume we are in portrait mode, ofcource this might not be the case
       
   197         screenSize = containerRect.height()/(mRenderer->getImageSize().height() + mRenderer->getSpacing().height());
       
   198         worldSize = worldWidth();
       
   199     }
       
   200     else{
       
   201         screenSize = containerRect.width()/(mRenderer->getImageSize().width() + mRenderer->getSpacing().width());
       
   202         worldSize = worldWidth();
       
   203     }
       
   204 }
       
   205 
       
   206 Qt::Orientation HgContainer::orientation() const
       
   207 {
       
   208     FUNC_LOG;
       
   209 
       
   210     return mRenderer->getOrientation();
       
   211 }
       
   212 
       
   213 void HgContainer::setOrientation(Qt::Orientation orientation, bool animate)
       
   214 {
       
   215     FUNC_LOG;
       
   216 
       
   217     mRenderer->setOrientation(orientation, animate);
       
   218 }
       
   219 
       
   220 void HgContainer::scrollToPosition(qreal value, bool animate)
       
   221 {
       
   222     FUNC_LOG;
       
   223 
       
   224     scrollToPosition(QPointF(value*worldWidth(), 0), animate);
       
   225 }
       
   226 
       
   227 void HgContainer::scrollToPosition(const QPointF& pos, bool animate)
       
   228 {
       
   229     FUNC_LOG;
       
   230 
       
   231     mAnimateUsingScrollBar = animate;
       
   232     initSpringForScrollBar();
       
   233 
       
   234     if (animate)
       
   235         mSpring.animateToPos(pos);
       
   236     else
       
   237         mSpring.gotoPos(pos);
       
   238 }
       
   239 
       
   240 void HgContainer::scrollTo(const QModelIndex &index)
       
   241 {
       
   242     FUNC_LOG;
       
   243 
       
   244     if (index.isValid()) {
       
   245         scrollToPosition(QPointF(index.row(), index.column()), false);
       
   246     }
       
   247 }
       
   248 
       
   249 void HgContainer::itemDataChanged(const QModelIndex &firstIndex, const QModelIndex &lastIndex)
       
   250 {
       
   251     FUNC_LOG;
       
   252 
       
   253     // TODO, fix this
       
   254     int columns = firstIndex.model()->columnCount(QModelIndex());
       
   255 
       
   256     // Check this!!
       
   257     int index = columns*firstIndex.row()+firstIndex.column();
       
   258     int index2 = columns*lastIndex.row()+lastIndex.column();
       
   259 
       
   260     // convert indeces to match one dimensional item array
       
   261     itemDataChanged( index, index2 );
       
   262 }
       
   263 
       
   264 void HgContainer::addItems(int start, int end)
       
   265 {
       
   266     FUNC_LOG;
       
   267 
       
   268     int first = qBound(0, start, mItems.count()-1);
       
   269     int last = qBound(0, end, mItems.count()-1);
       
   270     for (int i = 0; i <= end-start; i++) {
       
   271         HgWidgetItem* item = new HgWidgetItem(mQuadRenderer);
       
   272         mItems.insert(start, item);
       
   273     }
       
   274 }
       
   275 
       
   276 void HgContainer::removeItems(int start, int end)
       
   277 {
       
   278     FUNC_LOG;
       
   279 
       
   280     int first = qBound(0, start, mItems.count()-1);
       
   281     int last = qBound(0, end, mItems.count()-1);
       
   282     for (int i = last; i >= first; i--) {
       
   283         delete mItems.at(i);
       
   284         mItems.removeAt(i);
       
   285     }
       
   286 }
       
   287 
       
   288 void HgContainer::moveItems(int start, int end, int destination)
       
   289 {
       
   290     FUNC_LOG;
       
   291 
       
   292     int first = qBound(0, start, mItems.count()-1);
       
   293     int last = qBound(0, end, mItems.count()-1);
       
   294     int target = qBound(0, destination, mItems.count()-1);
       
   295 
       
   296     if (target < first) {
       
   297         for (int i = 0; i <= last-first; i++) {
       
   298             mItems.move(first+i, target+i);
       
   299         }
       
   300     }
       
   301     else if (target > last) {
       
   302         for (int i = 0; i <= last-first; i++) {
       
   303             mItems.move(last-i, target);
       
   304         }
       
   305     }
       
   306     // else do nothing
       
   307 }
       
   308 
       
   309 int HgContainer::imageCount() const
       
   310 {
       
   311     return mItems.count();
       
   312 }
       
   313 
       
   314 const HgImage *HgContainer::image(int index) const
       
   315 {
       
   316     return mItems[index]->image();
       
   317 }
       
   318 
       
   319 int HgContainer::flags(int index) const
       
   320 {
       
   321     if (index >= 0 && index < itemCount()) {
       
   322         if (mSelectionModel && mSelectionModel->isSelected(mSelectionModel->model()->index(index, 0))) {
       
   323             return 1; // TODO: Assign flag to mark indicator
       
   324         }
       
   325     }
       
   326     return 0;
       
   327 }
       
   328 
       
   329 const HgImage *HgContainer::indicator(int flags) const
       
   330 {
       
   331     if (flags & 1) {
       
   332         return mMarkImage;
       
   333     }
       
   334 
       
   335     return 0;
       
   336 }
       
   337 
       
   338 void HgContainer::updateBySpringPosition()
       
   339 {
       
   340     update();
       
   341 
       
   342     // spring works always in one dimension, that is, x coord.
       
   343     qreal pos = mSpring.pos().x();
       
   344 
       
   345     onScrollPositionChanged(pos);
       
   346 
       
   347     emit scrollPositionChanged(pos, mAnimateUsingScrollBar);
       
   348 }
       
   349 
       
   350 void HgContainer::redraw()
       
   351 {
       
   352     update();
       
   353 }
       
   354 
       
   355 void HgContainer::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
       
   356 {
       
   357     Q_UNUSED(option)
       
   358     Q_UNUSED(widget)
       
   359 
       
   360     if (mSpring.updatePositionIfNeeded())
       
   361     {
       
   362         // spring works always in one dimension, that is, x coord.
       
   363         qreal pos = mSpring.pos().x();
       
   364         onScrollPositionChanged(pos);
       
   365         emit scrollPositionChanged(pos, mAnimateUsingScrollBar);        
       
   366     }
       
   367     
       
   368     QRectF vp = painter->viewport();
       
   369     QRectF rts = mapRectToScene(rect());
       
   370     QRectF r;
       
   371 
       
   372     // transform rectangle to vg space &
       
   373     // rotate rendering according to orientation
       
   374     if (mainWindow()->orientation() == Qt::Horizontal) {
       
   375         r = QRectF(vp.width()-(rts.height()+rts.top()), rts.left(), rts.height(), rts.width());
       
   376         mRenderer->setCameraRotationZ(-90);
       
   377     }
       
   378     else {
       
   379         r = QRectF(rts.left(), vp.height()-(rts.height()+rts.top()), rts.width(), rts.height());
       
   380         mRenderer->setCameraRotationZ(0);
       
   381     }
       
   382 
       
   383     // interpolate spring velocity towards zero, this is done
       
   384     // so that spring velocity for rendering doesn't drop directly to
       
   385     // zero when dragging starts
       
   386     qreal springVel = mSpring.velocity().x();
       
   387     if (mDragged) {
       
   388         qreal t = qBound(mFramesDragged / KFramesToZeroVelocity, 0.0f, 1.0f);
       
   389         springVel = mSpringVelAtDragStart * (1.0f - t);
       
   390         mFramesDragged++;
       
   391     }
       
   392 
       
   393     // setup rendering and draw the current view
       
   394     mRenderer->setCameraDistance(getCameraDistance(springVel));
       
   395     mRenderer->setCameraRotationY(getCameraRotationY(springVel));
       
   396     mRenderer->setRect(r);
       
   397     mRenderer->draw(mSpring.startPos(), mSpring.pos(), mSpring.endPos(),
       
   398                     springVel, painter);
       
   399         
       
   400 }
       
   401 
       
   402 void HgContainer::resizeEvent(QGraphicsSceneResizeEvent *event)
       
   403 {
       
   404     FUNC_LOG;
       
   405 
       
   406     HbWidget::resizeEvent(event);
       
   407 }
       
   408 
       
   409 // this needs to be implemented for gesture framework to work
       
   410 void HgContainer::mousePressEvent(QGraphicsSceneMouseEvent *event)
       
   411 {
       
   412     Q_UNUSED(event);
       
   413 }
       
   414 
       
   415 void HgContainer::gestureEvent(QGestureEvent *event)
       
   416 {
       
   417     FUNC_LOG;
       
   418 
       
   419     // Event may contain more than one gesture type
       
   420     if (QGesture *gesture = event->gesture(Qt::TapAndHoldGesture)) {
       
   421         QTapAndHoldGesture *tapAndHold = static_cast<QTapAndHoldGesture *>(gesture);
       
   422         handleLongTap(tapAndHold->state(),
       
   423             mapFromScene(event->mapToGraphicsScene(tapAndHold->position())));
       
   424     }
       
   425     else if (QGesture *gesture = event->gesture(Qt::TapGesture)) {
       
   426         // Tap and hold is not working yet in HW, tap gesture is delivered instead
       
   427         QTapGesture *tap = static_cast<QTapGesture *>(gesture);
       
   428         handleTap(tap->state(),
       
   429             mapFromScene(event->mapToGraphicsScene(tap->position())));
       
   430     }
       
   431     else if (QGesture *pan = event->gesture(Qt::PanGesture)) {
       
   432         handlePanning(static_cast<QPanGesture*>(pan));
       
   433     }
       
   434 }
       
   435 
       
   436 void HgContainer::init(Qt::Orientation scrollDirection)
       
   437 {
       
   438     FUNC_LOG;
       
   439 
       
   440     mRenderer = createRenderer();
       
   441     if (mRenderer->coverflowModeEnabled())
       
   442         mRenderer->setOrientation(Qt::Horizontal, false);
       
   443     else
       
   444         mRenderer->setOrientation(scrollDirection, false);
       
   445         
       
   446     mQuadRenderer = mRenderer->getRenderer();
       
   447 
       
   448     QImage markImage(":/images/mark.svg");
       
   449     if (markImage.isNull()) {
       
   450         ERROR("Failed to load :/images/mark.svg");
       
   451     }
       
   452     mMarkImage = mQuadRenderer->createNativeImage();
       
   453     HANDLE_ERROR_NULL(mMarkImage);
       
   454     if (mMarkImage) {
       
   455         mMarkImage->setImage(markImage);
       
   456     }
       
   457 
       
   458     connect(&mSpring, SIGNAL(updated()), SLOT(updateBySpringPosition()));
       
   459     connect(&mSpring, SIGNAL(ended()), SLOT(onScrollingEnded()));
       
   460     connect(&mSpring, SIGNAL(ended()), SIGNAL(scrollingEnded()));
       
   461     connect(&mSpring, SIGNAL(started()), SIGNAL(scrollingStarted()));
       
   462     connect(mRenderer, SIGNAL(renderingNeeded()), SLOT(redraw()));
       
   463 
       
   464 }
       
   465 
       
   466 qreal HgContainer::worldWidth() const
       
   467 {
       
   468     return (qreal)mRenderer->getWorldWidth();
       
   469 }
       
   470 
       
   471 void HgContainer::initSpringForScrollBar()
       
   472 {
       
   473     FUNC_LOG;
       
   474 
       
   475     mSpring.setDamping(KSpringDampingScrollBar);
       
   476     mSpring.setK(KSpringKScrollBar);
       
   477 }
       
   478 
       
   479 void HgContainer::initSpringForScrolling()
       
   480 {
       
   481     FUNC_LOG;
       
   482 
       
   483     mSpring.setDamping(KSpringDampingScrolling);
       
   484     mSpring.setK(KSpringKScrolling);
       
   485 }
       
   486 
       
   487 void HgContainer::boundSpring()
       
   488 {
       
   489     FUNC_LOG;
       
   490 
       
   491     qreal x = mSpring.endPos().x();
       
   492     x = qBound(qreal(0), x, worldWidth());
       
   493     if (mRenderer->coverflowModeEnabled()) {
       
   494         qreal i = floorf(x);
       
   495         x = (x - i > 0.5f) ? ceilf(x) : i;
       
   496         mSpring.animateToPos(QPointF(x, 0));
       
   497     }
       
   498 
       
   499     mSpring.animateToPos(QPointF(x, 0));
       
   500 
       
   501 }
       
   502 
       
   503 void HgContainer::handlePanning(QPanGesture *gesture)
       
   504 {
       
   505     mAnimateUsingScrollBar = false;
       
   506     initSpringForScrolling();
       
   507 
       
   508     qreal pos = mSpring.pos().x();
       
   509     qreal delta(0);
       
   510     qreal itemSide(0);
       
   511 
       
   512     if (mRenderer->getOrientation() == mainWindow()->orientation()) {
       
   513         delta = gesture->delta().y();
       
   514     }
       
   515     else {
       
   516         delta = gesture->delta().x();
       
   517     }
       
   518 
       
   519     if (mRenderer->getOrientation() == Qt::Vertical)
       
   520         itemSide = mRenderer->getImageSize().height()+mRenderer->getSpacing().height();
       
   521     else
       
   522         itemSide = mRenderer->getImageSize().width()+mRenderer->getSpacing().width();
       
   523 
       
   524     if (gesture->state() == Qt::GestureStarted) {
       
   525         mOffsetAtDragStart = gesture->offset();
       
   526     }
       
   527     else if (gesture->state() == Qt::GestureUpdated) {
       
   528         QPointF offset = gesture->offset();
       
   529         QPointF offsetDelta = offset - mOffsetAtDragStart;
       
   530         if (!mDragged && (qAbs(offsetDelta.x()) > 8 ||
       
   531             qAbs(offsetDelta.y()) > 8)) {
       
   532             mDragged = true;
       
   533             mDrag.reset(delta, mSpring.pos().x());
       
   534             mDragged = true;
       
   535             mSpringVelAtDragStart = mSpring.velocity().x();
       
   536             mFramesDragged = 0;
       
   537         }
       
   538 
       
   539         if (mDragged)
       
   540         {
       
   541             emit scrollingStarted();
       
   542 
       
   543             qreal newPosition = mDrag.update(delta, pos, itemSide);
       
   544             if (qAbs(newPosition - mSpring.pos().x()) > 0.01f)
       
   545             {
       
   546                 mSpring.gotoPos(QPointF(newPosition, 0));
       
   547                 update();
       
   548             }
       
   549         }
       
   550     }
       
   551     else if (mDragged && gesture->state() == Qt::GestureFinished) {
       
   552         mDrag.update(delta, pos, itemSide);
       
   553         mDragged = false;
       
   554         qreal newPos(0);
       
   555         if (mDrag.finish(pos, mRenderer->coverflowModeEnabled(), newPos)) {
       
   556             mSpring.animateToPos(QPointF(qBound(qreal(0), newPos, worldWidth()), 0));
       
   557             HgWidgetItem* item = itemByIndex(newPos);
       
   558             if (item && item->modelIndex() != mSelectionModel->currentIndex()) {
       
   559             //    mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
   560             }
       
   561         }
       
   562         else {
       
   563             boundSpring();
       
   564         }
       
   565     }
       
   566     else if (gesture->state() == Qt::GestureCanceled) {
       
   567         boundSpring();
       
   568     }
       
   569 }
       
   570 
       
   571 
       
   572 
       
   573 void HgContainer::handleTap(Qt::GestureState state, const QPointF &pos)
       
   574 {
       
   575     FUNC_LOG;
       
   576 
       
   577     if (state == Qt::GestureStarted) {
       
   578         mTapDuration.start();
       
   579 
       
   580         startLongPressWatcher(pos);
       
   581     }
       
   582     else if (state == Qt::GestureCanceled)
       
   583     {
       
   584         stopLongPressWatcher();
       
   585     }
       
   586     else if (state == Qt::GestureFinished) {
       
   587 
       
   588         stopLongPressWatcher();
       
   589         handleItemAction(pos, mTapDuration.elapsed() > KLongTapDuration ? LongTap : NormalTap);
       
   590     }
       
   591 }
       
   592 
       
   593 void HgContainer::handleLongTap(Qt::GestureState state, const QPointF &pos)
       
   594 {
       
   595     FUNC_LOG;
       
   596 
       
   597     mAnimateUsingScrollBar = false;
       
   598     initSpringForScrolling();
       
   599 
       
   600     if (state == Qt::GestureFinished) {
       
   601         handleItemAction(pos, LongTap);
       
   602     }
       
   603 }
       
   604 
       
   605 /*!
       
   606     Handle tap, lang tap and double tap action.
       
   607     Finds out the item in the tap position and sends out suitable signal,
       
   608     Sets the item as the current item and in multiselection mode toggles the
       
   609     item selection status.
       
   610 */
       
   611 void HgContainer::handleItemAction(const QPointF &pos, ItemActionType action)
       
   612 {
       
   613     FUNC_LOG;
       
   614 
       
   615     // If there is content, mSelectionModel must always exist - either default or client-provided
       
   616     if (!mSelectionModel) return;
       
   617 
       
   618     mHitItem = getItemAt(pos, mHitItemIndex);
       
   619     if (mHitItem)
       
   620     {
       
   621         int index = mHitItemIndex;
       
   622 
       
   623 
       
   624         HgWidgetItem* item = itemByIndex(index);
       
   625         if (item && action != DoubleTap) {
       
   626             mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
   627 
       
   628             if (action == LongTap) {
       
   629                 INFO("Long tap:" << item->modelIndex().row());
       
   630 
       
   631                 if (!mRenderer->coverflowModeEnabled())
       
   632                     selectItem();
       
   633 
       
   634                 emit longPressed(item->modelIndex(), pos);
       
   635             }
       
   636             else if (mSelectionMode == HgWidget::MultiSelection) {
       
   637                 INFO("Select:" << item->modelIndex().row());
       
   638                 mSelectionModel->select(item->modelIndex(), QItemSelectionModel::Toggle);
       
   639                 update(); // It would be enough to update the item
       
   640             }
       
   641             else if (mSelectionMode == HgWidget::SingleSelection) {
       
   642                 INFO("Select:" << item->modelIndex().row());
       
   643                 mSelectionModel->select(item->modelIndex(), QItemSelectionModel::ClearAndSelect);
       
   644                 update(); // It would be enough to update the item
       
   645             }
       
   646             else if (mSelectionMode == HgWidget::ContiguousSelection) {
       
   647                 QModelIndex newSelected = item->modelIndex();
       
   648                 QModelIndexList oldSelection = mSelectionModel->selectedIndexes();
       
   649                 INFO("Select:" << newSelected.row());
       
   650                 if (oldSelection.count() > 0 && !mSelectionModel->isSelected(newSelected)) {
       
   651                     if (newSelected.row() < oldSelection.front().row()) {
       
   652                         mSelectionModel->select(QItemSelection(newSelected, oldSelection.back()),
       
   653                             QItemSelectionModel::Select);
       
   654                     }
       
   655                     else { // newSelected.row() > oldSelection.back().row()
       
   656                         mSelectionModel->select(QItemSelection(oldSelection.front(), newSelected),
       
   657                             QItemSelectionModel::Select);
       
   658                     }
       
   659                 }
       
   660                 else {
       
   661                     mSelectionModel->select(newSelected, QItemSelectionModel::Select);
       
   662                 }
       
   663                 update(); // It would be enough to update the item
       
   664             }
       
   665             else {
       
   666                 INFO("Tap:" << item->modelIndex().row());
       
   667 
       
   668                 if (mRenderer->coverflowModeEnabled())
       
   669                 {
       
   670                     if (qAbs(qreal(index) - mSpring.pos().x()) < 0.01f)
       
   671                     {
       
   672                         emit activated(item->modelIndex());
       
   673                     }
       
   674                     else
       
   675                     {
       
   676                         mSpring.animateToPos(QPointF(index, 0));
       
   677                     }
       
   678                 }
       
   679                 else
       
   680                 {
       
   681                     selectItem();
       
   682                     emit activated(item->modelIndex());
       
   683                 }
       
   684 
       
   685             }
       
   686         }
       
   687     }
       
   688     else {
       
   689         INFO("No quad at pos:" << pos);
       
   690 
       
   691         unselectItem();
       
   692     }
       
   693 }
       
   694 
       
   695 bool HgContainer::getItemPoints(int index, QPolygonF& points)
       
   696 {
       
   697     QPolygonF poly;
       
   698     if (!mRenderer->getItemPoints(index, poly))
       
   699         return false;
       
   700 
       
   701     bool invertible;
       
   702     QTransform t = qtToVgTransform().inverted(&invertible);
       
   703 
       
   704     points = t.map(poly);
       
   705     return true;
       
   706 }
       
   707 
       
   708 QList<QModelIndex> HgContainer::getVisibleItemIndices() const
       
   709 {
       
   710     QList<HgQuad*> quads = mRenderer->getVisibleQuads();
       
   711     QList<QModelIndex> result;
       
   712     for (int i = 0; i < quads.count(); i++) {
       
   713         bool ok;
       
   714         int index = quads.at(i)->userData().toInt(&ok);
       
   715         result.append(itemByIndex(index)->modelIndex());
       
   716     }
       
   717     qSort(result);
       
   718     return result;
       
   719 }
       
   720 
       
   721 void HgContainer::itemDataChanged(const int &firstIndex, const int &lastIndex)
       
   722 {
       
   723     FUNC_LOG;
       
   724 
       
   725     // TODO FIX THIS FUNCTION!!!!!!!!!!!!!!!!!!!!!!
       
   726 
       
   727     int firstItemOnScreen = 0, lastItemOnScreen = 0;
       
   728     firstItemOnScreen = mSpring.pos().x();
       
   729     firstItemOnScreen *= rowCount();
       
   730 
       
   731     // This code doesnt take into count if there is some empty space at the
       
   732     // beginning or at the end of the widget
       
   733 
       
   734     int itemsOnScreen = 0;
       
   735     if (mRenderer->getOrientation() == Qt::Vertical) {
       
   736         itemsOnScreen = this->rect().height()/mRenderer->getImageSize().height();
       
   737         itemsOnScreen += rowCount();
       
   738     }
       
   739     else {
       
   740         // Doesnt work here. Use some magic for now.
       
   741         itemsOnScreen = this->rect().width()/mRenderer->getImageSize().width();
       
   742         itemsOnScreen += 4;
       
   743     }
       
   744     itemsOnScreen *= rowCount();
       
   745     lastItemOnScreen = firstItemOnScreen+itemsOnScreen;
       
   746 
       
   747     if ((firstIndex >= firstItemOnScreen && firstIndex <= lastItemOnScreen) ||
       
   748         (lastIndex >= firstItemOnScreen && lastIndex <= lastItemOnScreen)) {
       
   749         update( this->rect() );
       
   750     }
       
   751 }
       
   752 
       
   753 void HgContainer::selectItem()
       
   754 {
       
   755     // TODO: replace this with own selection implementation
       
   756 
       
   757     if (mHitItemView)
       
   758     {
       
   759         delete mHitItemView;
       
   760         mHitItemView = NULL;
       
   761     }
       
   762 
       
   763     mHitItemView = new HbGridViewItem(this);
       
   764     mHitItemView->setVisible(false);
       
   765 
       
   766     QModelIndex modelIndex = mItems[mHitItemIndex]->modelIndex();
       
   767     const QAbstractItemModel* model = modelIndex.model();
       
   768     mHitItemView->resize(mRenderer->getImageSize().width() + 10,
       
   769         mRenderer->getImageSize().height() + 10);
       
   770 
       
   771     QVariant iconVariant = model->data(modelIndex, Qt::DecorationRole);
       
   772     mHitItemPixmap = iconVariant.value<QPixmap>();
       
   773     HbIcon icon(mHitItemPixmap);
       
   774 
       
   775     QGraphicsItem* item = mHitItemView->style()->createPrimitive(HbStyle::P_GridViewItem_icon, mHitItemView);
       
   776     HbIconItem *iconItem = static_cast<HbIconItem*>(item);
       
   777     iconItem->setIcon(icon);
       
   778     iconItem->setAlignment(Qt::AlignCenter);
       
   779     iconItem->setAspectRatioMode(Qt::KeepAspectRatio);
       
   780 
       
   781     mHitItemView->setModelIndex(modelIndex);
       
   782     mHitItemView->setPos(QPointF(-10,-10));
       
   783     mHitItemView->setPressed(true, false);
       
   784     mHitItemView->updatePrimitives();
       
   785 
       
   786 }
       
   787 
       
   788 void HgContainer::updateSelectedItem()
       
   789 {
       
   790     if (!mHitItemView || mHitItemIndex == -1)
       
   791         return;
       
   792 
       
   793     QPolygonF points;
       
   794     if (!getItemPoints(mHitItemIndex, points))
       
   795     {
       
   796         // the item was not rendered, we must hide
       
   797         // our qt item
       
   798         mHitItemView->setVisible(false);
       
   799     }
       
   800 
       
   801     if (mHitItemPixmap.isNull())
       
   802     {
       
   803         mHitItemView->setVisible(false);
       
   804         return;
       
   805     }
       
   806 
       
   807     QPolygonF img;
       
   808     img.append(QPointF(0,mHitItemPixmap.height()));
       
   809     img.append(QPointF(mHitItemPixmap.width(),mHitItemPixmap.height()));
       
   810     img.append(QPointF(mHitItemPixmap.width(),0));
       
   811     img.append(QPointF(0,0));
       
   812 
       
   813     QTransform t;
       
   814     QTransform::quadToQuad(img, points, t);
       
   815 
       
   816     mHitItemView->setTransform(t);
       
   817     mHitItemView->setVisible(true);
       
   818 }
       
   819 
       
   820 void HgContainer::unselectItem()
       
   821 {
       
   822     mHitItemIndex = -1;
       
   823     if (mHitItemView)
       
   824     {
       
   825         mHitItemView->setPressed(false, false);
       
   826         mHitItemView->setVisible(false);
       
   827     }
       
   828 }
       
   829 
       
   830 void HgContainer::updateLongPressVisualizer()
       
   831 {
       
   832     int elapsed = mLongTapDuration.elapsed();
       
   833     
       
   834     if (elapsed > 80)
       
   835     {    
       
   836         int frame = 100.0f * qreal(elapsed - 80) / qreal(KLongTapDuration - 80);
       
   837         mLongPressVisualizer->setFrame(frame);
       
   838     }
       
   839 }
       
   840 
       
   841 void HgContainer::updateByCurrentIndex(const QModelIndex &current)
       
   842 {
       
   843     handleCurrentChanged(current);
       
   844 }
       
   845 
       
   846 HgWidgetItem* HgContainer::getItemAt(const QPointF& pos, int& index)
       
   847 {
       
   848     QPointF p = mapQtToVg(pos);
       
   849     HgQuad* quad = mRenderer->getQuadAt(p);
       
   850     if (quad)
       
   851     {
       
   852         bool ok;
       
   853         index = quad->userData().toInt(&ok);
       
   854 
       
   855         HgWidgetItem* item = itemByIndex(index);
       
   856         return item;
       
   857     }
       
   858     return NULL;
       
   859 }
       
   860 
       
   861 void HgContainer::startLongPressWatcher(const QPointF& pos)
       
   862 {
       
   863     if (!mLongPressVisualizer)
       
   864     {
       
   865         mLongPressVisualizer = new HgLongPressVisualizer(this);
       
   866         mLongPressVisualizer->setZValue(zValue()+1);
       
   867     }
       
   868 
       
   869     mLongPressVisualizer->start(pos);
       
   870 
       
   871     if (!mLongPressTimer)
       
   872     {
       
   873         mLongPressTimer = new QTimer(this);
       
   874         QObject::connect(mLongPressTimer, SIGNAL(timeout()), this, SLOT(updateLongPressVisualizer()));
       
   875     }
       
   876 
       
   877     mLongPressTimer->start(20);
       
   878 
       
   879     mLongTapDuration.start();
       
   880 }
       
   881 
       
   882 void HgContainer::stopLongPressWatcher()
       
   883 {
       
   884     if (mLongPressTimer && mLongPressVisualizer)
       
   885     {
       
   886         mLongPressTimer->stop();
       
   887         mLongPressVisualizer->stop();
       
   888     }
       
   889 }
       
   890 
       
   891 QTransform HgContainer::qtToVgTransform() const
       
   892 {
       
   893     QTransform t;
       
   894     if (mainWindow()->orientation() == Qt::Vertical)
       
   895     {
       
   896         t.translate(0, rect().height());
       
   897         t.scale(1, -1);
       
   898     }
       
   899     else // horizontal
       
   900     {
       
   901         t.translate(rect().height(), 0);
       
   902         t.scale(-1, 1);
       
   903         t.translate(0, rect().width());
       
   904         t.rotate(-90, Qt::ZAxis);
       
   905     }
       
   906     return t;
       
   907 }
       
   908 
       
   909 QPointF HgContainer::mapQtToVg(const QPointF& p) const
       
   910 {
       
   911     QTransform t = qtToVgTransform();
       
   912     return t.map(p);
       
   913 }
       
   914 
       
   915 qreal HgContainer::getCameraDistance(qreal springVelocity)
       
   916 {
       
   917     Q_UNUSED(springVelocity)
       
   918     return 0;
       
   919 }
       
   920 
       
   921 qreal HgContainer::getCameraRotationY(qreal springVelocity)
       
   922 {
       
   923     Q_UNUSED(springVelocity)
       
   924     return 0;
       
   925 }
       
   926 
       
   927 void HgContainer::handleTapAction(const QPointF& pos, HgWidgetItem* hitItem, int hitItemIndex)
       
   928 {
       
   929     Q_UNUSED(pos)
       
   930     Q_UNUSED(hitItem)
       
   931     Q_UNUSED(hitItemIndex)
       
   932 }
       
   933 
       
   934 void HgContainer::handleLongTapAction(const QPointF& pos, HgWidgetItem* hitItem, int hitItemIndex)
       
   935 {
       
   936     Q_UNUSED(pos)
       
   937     Q_UNUSED(hitItem)
       
   938     Q_UNUSED(hitItemIndex)
       
   939 }
       
   940 
       
   941 void HgContainer::onScrollPositionChanged(qreal pos)
       
   942 {
       
   943     Q_UNUSED(pos)
       
   944 }
       
   945 
       
   946 void HgContainer::handleCurrentChanged(const QModelIndex &current)
       
   947 {
       
   948     Q_UNUSED(current)
       
   949     // By default do nothing
       
   950 }
       
   951 
       
   952 void HgContainer::onScrollingEnded()
       
   953 {
       
   954 /*    int index;
       
   955     HgWidgetItem* item = getItemAt(rect().center(), index);
       
   956     if (item && item->modelIndex() != mSelectionModel->currentIndex()) {
       
   957         mSelectionModel->setCurrentIndex(item->modelIndex(), QItemSelectionModel::Current);
       
   958     }*/    
       
   959 }
       
   960