src/hbwidgets/itemviews/hbabstractitemcontainer.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 19 Apr 2010 14:02:13 +0300
changeset 0 16d8024aca5e
child 1 f7ac710697a9
permissions -rw-r--r--
Revision: 201011 Kit: 201015

/****************************************************************************
**
** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (developer.feedback@nokia.com)
**
** This file is part of the HbWidgets module of the UI Extensions for Mobile.
**
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at developer.feedback@nokia.com.
**
****************************************************************************/
#include "hbabstractitemcontainer.h"
#include "hbabstractitemcontainer_p.h"

#include "hbabstractviewitem.h"
#include "hbabstractitemview.h"
#include "hbabstractitemview_p.h"
#include "hbmodeliterator.h"
#include <hbapplication.h>

#include <QGraphicsLayout>
#include <QGraphicsSceneResizeEvent>
#include <QEvent>
#include <QDebug>

/*!
    @alpha
    @hbwidgets
    \class HbAbstractItemContainer
    \brief HbAbstractItemContainer represents container for HbAbstractViewItem derived items.

    
    HbAbstractItemContainer is used in HbAbstractItemView to hold the layout and view items.
    Container should have a layout, otherwise its size is zero always.
    HbAbstractItemContainer can have any kind of layout as it child.
*/

/*!
    \fn void HbAbstractItemContainer::itemAdded(int index, HbAbstractViewItem *item)

    Function is called after new \a item was added into \a index position into
    container.
*/

/*!
    \fn void HbAbstractItemContainer::itemRemoved(HbAbstractViewItem *item)

    Function is called after the \a item was removed from the container. 
*/

/*!
    \fn void HbAbstractItemContainer::viewResized(const QSizeF &size)

    Function is called when container needs to be resized.
*/

/*!
    \fn HbAbstractViewItem *createDefaultPrototype() const

    Returns the default prototype.

    Subclasses of this class must implement this function to introduce their own default prototype. 
    Default prototype is used to create view items unless the class user excplicitly sets prototype with setItemPrototype method. 
    Implementation of this method must construct and return a new view item widget. 
*/

const int HB_DEFAULT_BUFFERSIZE = 4;
const int UpdateItemBufferEvent = QEvent::registerEventType();

HbAbstractItemContainerPrivate::HbAbstractItemContainerPrivate() : 
    HbWidgetPrivate(),
    mItemView(0),
    mBufferSize(HB_DEFAULT_BUFFERSIZE),
    mItemRecycling(false),
    mUniformItemSizes(false)
{
}

HbAbstractItemContainerPrivate::~HbAbstractItemContainerPrivate()
{
}

/*!
   Returns given item's bounding rectangle in scene coordinates.
 */
QRectF HbAbstractItemContainerPrivate::itemBoundingRect(const QGraphicsItem *item) const
{
    return item->mapToItem(mItemView, item->boundingRect()).boundingRect();
}

void HbAbstractItemContainerPrivate::firstAndLastVisibleBufferIndex(
        int& firstVisibleBufferIndex,
        int& lastVisibleBufferIndex,
        const QRectF &viewRect,
        bool fullyVisible) const
{
    Q_Q(const HbAbstractItemContainer);

    if (q->layout() && !q->layout()->isActivated()) {
        q->layout()->activate();
    }

    firstVisibleBufferIndex = -1;
    lastVisibleBufferIndex = -1;

    int count = mItems.count();
    for (int i = 0; i < count; ++i) {
        if (visible(mItems.at(i), viewRect, fullyVisible)) {
            if (firstVisibleBufferIndex == -1) {
                firstVisibleBufferIndex = i;
            }
            lastVisibleBufferIndex = i;
        } else if ( lastVisibleBufferIndex != -1 ) {
            // no need to check the remaining ones.
            break;
        }
    }
}

/*!
    \private

    Returns true if given item is located within viewport (i.e.  view), otherwise
    returns false. If fullyVisible parameter is true method will return true only
    for item that is shown fully. In this case for partially visible items false is returned.
*/
bool HbAbstractItemContainerPrivate::visible(HbAbstractViewItem* item, const QRectF &viewRect, bool fullyVisible) const
{
    if (item) {
        QRectF itemRect(itemBoundingRect(item));
        if (fullyVisible) {
            if (viewRect.contains(itemRect)) {
                return true;
            }
        } else {
            if (viewRect.intersects(itemRect)) {
                return true;
            }
        }
    }

    return false;
}

/*!
  Clears the prototype list and deletes the prototypes.
*/
void HbAbstractItemContainerPrivate::deletePrototypes()
{
    qDeleteAll(mPrototypes);
    mPrototypes.clear();
}

int HbAbstractItemContainerPrivate::findStateItem(const QModelIndex &index) const
{
    for (int current = 0; current < mItemStateList.count(); ++current) {
        if (mItemStateList.at(current).index == index) {
            return current;
        }
    }
    return -1;
}

void HbAbstractItemContainerPrivate::initPrototype(HbAbstractViewItem *prototype) const
{
    prototype->setParentItem(mItemView);
    prototype->setItemView(mItemView);
    prototype->resize(QSizeF(0, 0));
    prototype->hide();
}

HbAbstractViewItem* HbAbstractItemContainerPrivate::createItem(const QModelIndex& index)
{
    Q_Q(HbAbstractItemContainer);

    HbAbstractViewItem *result = 0;
    HbAbstractViewItem *prototype = itemPrototype(index);
    if (prototype) {
        result = prototype->createItem();
        Q_ASSERT_X(result && result->prototype() == prototype, "HbAbstractItemContainerPrivate::createItem", "Copy constructor must be used for creating concrete view items in createItem(). Create your custom view item with 'new YourCustomViewItem(*this)' instead of 'new YourCustomViewItem(this)'");
        result->setParentItem(q);
    }
    return result;
}

HbAbstractViewItem* HbAbstractItemContainerPrivate::itemPrototype(const QModelIndex& index) const
{
    Q_Q(const HbAbstractItemContainer);

    if (mPrototypes.isEmpty()) {
        HbAbstractViewItem *defaultPrototype = q->createDefaultPrototype();
        if (defaultPrototype) {
            initPrototype(defaultPrototype);

            mPrototypes.append(defaultPrototype);
        }
    }

    HbAbstractViewItem *result = 0;
    int count = mPrototypes.count() - 1;
    for (int i = count; i >= 0; i--) {
        if (mPrototypes[i]->canSetModelIndex(index)) {
            result = mPrototypes[i];
            break;
        }
    }
    return result;
}


/*!
    \private
    
    Updates item buffer to contain correct amount of items for the current situation.
*/
void HbAbstractItemContainerPrivate::updateItemBuffer()
{
    Q_Q(HbAbstractItemContainer);

    if (!mItemView) {
        return;
    }

    int targetCount = q->maxItemCount();
    int itemCount = mItems.count();

    if (itemCount == targetCount) {
        return;
    }
    
    // Store the first item position related to view.
    QPointer<HbAbstractViewItem> firstItem = mItems.value(qMax(0, itemCount - targetCount));
    QPointF firstItemPos;
    if (firstItem) {
        firstItemPos = itemBoundingRect(firstItem).topLeft();
    }

    // Perform the incresing/decreasing
    if (itemCount < targetCount) {
        increaseBufferSize(targetCount - itemCount);
    } else {
        decreaseBufferSize(itemCount - targetCount);
    }

    QGraphicsLayout *layout = q->layout();
    if (layout && !layout->isActivated()) {
        layout->activate();
    }

    // Restore the first item position related to view if it has changed.
    if (firstItem) {
        QPointF delta = itemBoundingRect(firstItem).topLeft() - firstItemPos;
        if (!delta.isNull()) {
            q->setPos(q->pos() - delta);

            if (mItemView) {
                // this will force the HbScrollArea to adjust the content correctly. Adjustment
                // is not done in the setPos generated event handling by default to speed up scrolling.
                HbAbstractItemViewPrivate::d_ptr(mItemView)->adjustContent();
            }
        }
    }
}

/*!
    Increases the item buffer size with given \a amount.

    First tries to add as many items after the last item with valid
    index as it can. If there is not enough valid indexes then inserts items
    before the first item with valid index.
*/
void HbAbstractItemContainerPrivate::increaseBufferSize(int amount)
{
    Q_Q(HbAbstractItemContainer);

    // Append new items.
    QModelIndex index;
    for (int i = mItems.count() - 1; i >= 0; --i) {
        index = mItems.at(i)->modelIndex();
        if (index.isValid()) {
            break;
        }
    }

    int itemsAdded = 0;
    // in practise following conditions must apply: itemview is empty and scrollTo() has been called.
    // Starts populating items from given mFirstItemIndex
    if (    !index.isValid()
        &&  mFirstItemIndex.isValid()) {
        index = mFirstItemIndex;
        q->insertItem(mItems.count(), index);
        itemsAdded++;

        mFirstItemIndex = QModelIndex();
    }
 
    while (itemsAdded < amount) {
        index = mItemView->modelIterator()->nextIndex(index);
        if (!index.isValid()) {
            break;
        }
        
        q->insertItem(mItems.count(), index);
        itemsAdded++;
    }

    if (itemsAdded == amount) {
        return;
    } 

    // Prepend new items.
    for (int i = 0; i < mItems.count(); ++i) {
        index = mItems.at(i)->modelIndex();
        if (index.isValid()) {
            break;
        }
    }

    while (itemsAdded < amount) {
        index = mItemView->modelIterator()->previousIndex(index);
        if (!index.isValid()) {
            break;
        }

        q->insertItem(0, index);
        itemsAdded++;
    }
}

/*!
    Decreases the item buffer size with given \a amount.

    Tries to avoid deleting visible items and keep the buffer balanced.
*/
void HbAbstractItemContainerPrivate::decreaseBufferSize(int amount)
{
    Q_UNUSED(amount)

    int firstVisible = 0;
    int lastVisible = 0;
    firstAndLastVisibleBufferIndex(firstVisible, lastVisible, itemBoundingRect(mItemView), false);

    int deletableItemsOnTop = firstVisible - 1;
    int deletableItemsOnBottom = mItems.count() - lastVisible - 1;
    int itemsDeleted = 0;
    HbAbstractViewItem* item = 0;

    // in decreasing the buffer we try to keep it balanced
    while (itemsDeleted < amount ) {
        if (deletableItemsOnTop > deletableItemsOnBottom) {
            item = mItems.takeFirst();
            deletableItemsOnTop--;
        } else {
            item = mItems.takeLast();
            deletableItemsOnBottom--;
        }
        deleteItem(item);
        ++itemsDeleted;
     }

}

/*!
    \private
*/
HbAbstractViewItem* HbAbstractItemContainerPrivate::item(const QModelIndex &index) const
{
    int itemCount = mItems.count();
    for (int i = 0; i < itemCount; ++i) {
        // This could use binary search as model indexes are in sorted.
        if (mItems.at(i)->modelIndex() == index) {
            return mItems.at(i);
        }
    }

    // TODO: The lower (commented out) part of the code is an optimized version of the above.
    // However, there are problems with TreeView's deep models concerning the optimized version.
    // The optimized version should be fixed and taken into use later on.

    /*
    int itemCount = mItems.count();
    if (itemCount > 0) {
        if (index.isValid()) {
            int itemIndex = mItemView->indexPosition(index) - mItemView->indexPosition(mItems.first()->modelIndex());
            return mItems.value(itemIndex);
        } else {
            for (int i = 0; i < itemCount; ++i) {
                // This could use binary search as model indexes are in sorted.
                HbAbstractViewItem *item = mItems.at(i);
                if (item->modelIndex() == index) {
                    return item;
                }
            }
        }
    }
    */

    return 0;
}

/*!
    \private

    Removes \a item with model index \a index.
*/
void HbAbstractItemContainerPrivate::doRemoveItem(HbAbstractViewItem *item, const QModelIndex &index, bool animate)
{
    Q_Q(HbAbstractItemContainer);
    
    if (item) {
        deleteItem(item, animate);
        q->setItemState(index, QMap<int, QVariant>());
    }
}


/*!
    \private

    Deletes \a item.
*/
void HbAbstractItemContainerPrivate::deleteItem(HbAbstractViewItem *item, bool animate)
{
    Q_Q(HbAbstractItemContainer);

    q->setItemState(item->modelIndex(), item->state());

    mItems.removeOne(item);
    q->itemRemoved(item, animate);

#ifndef HB_EFFECTS
    delete item;
#else
    if (!HbEffect::effectRunning(item, "disappear")) {
        delete item;
    }
#endif
}

/*
    \private
    The previous and the next index must be in the buffer. We cannot assume in this base class 
    that the container is a list we just have to loop through the items and find if the previous
    and next exist in the buffer

*/
bool HbAbstractItemContainerPrivate::intoContainerBuffer(const QModelIndex &index) const
{    
    QModelIndex nextIndex = mItemView->modelIterator()->nextIndex(index);
    QModelIndex previousIndex = mItemView->modelIterator()->previousIndex(index);
    bool nextFound = false;
    bool previousFound = false;

    foreach (const HbAbstractViewItem *bufferItem, mItems) {
        if (bufferItem->modelIndex() == nextIndex){
            nextFound=true;
        } else if (bufferItem->modelIndex() == previousIndex) {
            previousFound=true;
        }
        if (previousFound && nextFound) {
            return true;
        }
    }
    return false;
} 

int HbAbstractItemContainerPrivate::containerBufferIndexForModelIndex(const QModelIndex &index) const
{   
    int bufferIndex = 0;
    QModelIndex nextIndex = mItemView->modelIterator()->nextIndex(index);
    while (bufferIndex < mItems.count()) {
        if (mItems.at(bufferIndex)->modelIndex() == nextIndex) {
            break;
        }
        ++bufferIndex;
    }
    return bufferIndex;
}

/*!
    Constructs a new HbAbstractItemContainer with \a parent.
*/
HbAbstractItemContainer::HbAbstractItemContainer(QGraphicsItem *parent) : 
    HbWidget(*new HbAbstractItemContainerPrivate(), parent) 
{
    Q_D(HbAbstractItemContainer);
	d->q_ptr = this;
}

/*!
    Constructs an item with private class object \a dd and \a parent. 
*/
HbAbstractItemContainer::HbAbstractItemContainer(HbAbstractItemContainerPrivate &dd, QGraphicsItem *parent) :
    HbWidget(dd, parent)
{
    Q_D(HbAbstractItemContainer);

    d->q_ptr = this;
}

/*!
    Destroys the container.
*/
HbAbstractItemContainer::~HbAbstractItemContainer()
{
}

/*!
    \reimp
*/
bool HbAbstractItemContainer::event(QEvent *e)
{
    if (e->type() == QEvent::LayoutRequest) {
        QGraphicsWidget *parentWid = parentWidget();
        if (!parentLayoutItem() 
            && parentWid) {
            HbApplication::postEvent(parentWid, new QEvent(QEvent::LayoutRequest));
        }
        Q_D(HbAbstractItemContainer);
        d->updateItemBuffer();
    } else if (e->type() == UpdateItemBufferEvent) {
        Q_D(HbAbstractItemContainer);
        d->updateItemBuffer();
   }

    return HbWidget::event(e);
}

/*!
    Returns view item object corresponding given model \a index. This might be 0 pointer if
    there is no view item representing given index or given \a index is invalid.
*/
HbAbstractViewItem* HbAbstractItemContainer::itemByIndex(const QModelIndex &index) const
{
    Q_D(const HbAbstractItemContainer);
    
    if (!index.isValid()) {
        return 0;
    }
    return d->item(index);
}

/*!
    This function is provided for convenience. 
    
    It removes all the items from the container and clears the internal state model.
*/
void HbAbstractItemContainer::removeItems()
{
    Q_D(HbAbstractItemContainer);

    qDeleteAll(d->mItems);
    d->mItems.clear();
    d->mItemStateList.clear();
}

/*!
    Returns the item view that container is connected.
*/
HbAbstractItemView *HbAbstractItemContainer::itemView() const
{
    Q_D(const HbAbstractItemContainer);
    return d->mItemView;
}

/*!
    Sets item \a view that container is connected.
*/
void HbAbstractItemContainer::setItemView(HbAbstractItemView *view)
{
    Q_D(HbAbstractItemContainer);

    if (view != d->mItemView) {
        if (d->mItemView) {
            d->mItemView->removeEventFilter(this);
        }

        d->mItemView = view;

        foreach (HbAbstractViewItem *prototype, d->mPrototypes) {
            d->initPrototype(prototype);
        }

        if (d->mItemView) {
            setParentItem(view);
            d->mItemView->installEventFilter(this);
        }
    }
}

/*!
    Assigns new model \a index to the given \a item. Item's current state is saved
    and state for \a index is restored to item.
*/
void HbAbstractItemContainer::setItemModelIndex(HbAbstractViewItem *item, const QModelIndex &index)
{

    if (item && item->modelIndex() != index) { 

        setItemState(item->modelIndex(), item->state());

        // Transfer the state from item currently representing index to new item, if such exists.
        HbAbstractViewItem *oldItem = itemByIndex(index);
        if (oldItem) {
            item->setState(oldItem->state());
        } else {
            item->setState(itemState(index));
        }

        item->setModelIndex(index);
    }
}

/*!
    Sets item's model indexes starting from given \a startIndex. If \a startIndex is
    QModelIndex() then startIndex is taken from the first item. 

    \note If there are not enough model indexes from \a startIndex to last model index 
    for all the items then QModelIndex() is assigned to rest of the view items.
*/
void HbAbstractItemContainer::setModelIndexes(const QModelIndex &startIndex)
{
    Q_D(HbAbstractItemContainer);

    if (!d->mItemView || !d->mItemView->model()) {
        return;
    }

    QModelIndex index = startIndex;
    if (!index.isValid()) {
        if (!d->mItems.isEmpty()) {
            index = d->mItems.first()->modelIndex();
        } 
        
        if (!index.isValid()) {
            index = d->mItemView->modelIterator()->nextIndex(index);
        }
    }

    QModelIndexList indexList;

    int itemCount(d->mItems.count());

    if (itemCount != 0 && index.isValid()) {
        indexList.append(index);
    }

    for (int i = indexList.count(); i < itemCount; ++i) {
        index = d->mItemView->modelIterator()->nextIndex(indexList.last());

        if (index.isValid()) {
            indexList.append(index);
        } else {
            break;
        }
    }

    for (int i = indexList.count(); i < itemCount; ++i) {
        index = d->mItemView->modelIterator()->previousIndex(indexList.first());

        if (index.isValid()) {
            indexList.prepend(index);
        } else {
            break;
        }
    }

    // if items have been added/removed in the middle of the buffer, there might be items 
	// that can be reused at the end of the buffer. The following block will scan for 
	// those items and move them in correct position 
    int lastUsedItem = -1;
    for (int indexCounter = 0; indexCounter < indexList.count(); ++indexCounter) {
        HbAbstractViewItem *item = d->mItems.at(indexCounter);
        if (item && item->modelIndex() == indexList.at(indexCounter)) { 
            lastUsedItem = indexCounter;
        } else {
            for (int itemCounter = lastUsedItem + 1; itemCounter < d->mItems.count(); itemCounter++) {
                HbAbstractViewItem *item2 = d->mItems.at(itemCounter);
                if (item2->modelIndex() == indexList.at(indexCounter)) { 
                    d->mItems.swap(indexCounter, itemCounter);
                    itemRemoved(d->mItems.at(indexCounter), false);
                    itemRemoved(d->mItems.at(itemCounter), false);
                    itemAdded(qMin(indexCounter, itemCounter), d->mItems.at(qMin(indexCounter, itemCounter)), false);
                    itemAdded(qMax(indexCounter, itemCounter), d->mItems.at(qMax(indexCounter, itemCounter)), false);
                    lastUsedItem = itemCounter;
                    break;
                }
            }
        }
    }

    int indexCount(indexList.count());
    for (int i = 0; i < itemCount; ++i) {
        HbAbstractViewItem *item = d->mItems.at(i);
        HbAbstractViewItem *prototype = 0;
        // setItemModelIndex() is considered recycling. It is called only, if recycling is permitted
        if (i < indexCount) {
            prototype = d->itemPrototype(indexList.at(i));
        }
        if (prototype) {
            if (    prototype == item->prototype()
                &&  d->mItemRecycling) {
                setItemModelIndex(item, indexList.at(i));
            } else if (     d->mItemRecycling
                       ||   (   !d->mItemRecycling
                            &&  item->modelIndex() != indexList.at(i))) {
                d->deleteItem(item);
                insertItem(i, indexList.at(i));
            } // else: !d->mItemRecycling && item->modelIndex().isValid() == indexList.at(i))
        } else {
            d->deleteItem(item);
            itemCount--;
            i--;
        }
    }
}

/*!
    \deprecated HbAbstractItemContainer::firstItemIndex() const
        is deprecated.

    This function is provided for convenience. 

    Returns model index of first item inside item buffer.
*/
QModelIndex HbAbstractItemContainer::firstItemIndex() const
{
    qWarning("HbAbstractItemContainer::firstItemIndex() is deprecated!");

    Q_D(const HbAbstractItemContainer);
    if (!d->mItems.isEmpty()){
        return d->mItems.first()->modelIndex();
    } else {
        return QModelIndex();
    }
}

/*!
    \deprecated HbAbstractItemContainer::lastItemIndex() const
        is deprecated.

    This function is provided for convenience. 

    Returns model index of last item inside item buffer.
*/
QModelIndex HbAbstractItemContainer::lastItemIndex() const
{
    qWarning("HbAbstractItemContainer::lastItemIndex() is deprecated!");

    Q_D(const HbAbstractItemContainer);
    if (!d->mItems.isEmpty()){
        return d->mItems.last()->modelIndex();
    } else {
        return QModelIndex();
    }
}

/*!
    Returns list of items inside item buffer.
*/
QList<HbAbstractViewItem *> HbAbstractItemContainer::items() const
{
    Q_D(const HbAbstractItemContainer);
    return d->mItems;
}

/*!
    Adds item for model \a index to container.
*/
void HbAbstractItemContainer::addItem(const QModelIndex &index, bool animate)
{
    Q_D(HbAbstractItemContainer);

    // Add new item if maximum item count allows it or item falls within the range of
    // item buffer items. 
    if (d->mItems.count() < maxItemCount() 
        || (d->mItems.count() > 0
           && d->intoContainerBuffer(index))) {

        int bufferIndex = 0;
        if (d->mItems.count() != 0) {
            bufferIndex = d->containerBufferIndexForModelIndex(index); 
        }

        if (bufferIndex >= d->mItems.count()
            || d->mItems.at(bufferIndex)->modelIndex() != index) {
            insertItem(bufferIndex, index, animate);

            if (d->mItemRecycling) {
                d->updateItemBuffer();
            }
        }
    }  
}

/*!
    Removes item representing \a index from container.
*/
void HbAbstractItemContainer::removeItem(const QModelIndex &index, bool animate)
{
    Q_D(HbAbstractItemContainer);

    HbAbstractViewItem *item = d->item(index);
    d->doRemoveItem(item, index, animate);
}

/*!
    Removes item from \a pos.
*/
void HbAbstractItemContainer::removeItem(int pos, bool animate)
{
    Q_D(HbAbstractItemContainer);

    Q_ASSERT(pos >= 0 && pos < d->mItems.count());        

    HbAbstractViewItem *item = d->mItems.at(pos);
    QModelIndex index = item->modelIndex();
    d->doRemoveItem(item, index, animate);
}

/*!
    Derived class should implement this function to perform item recycling based on container \a delta.
    Given \a delta is the distance between container's current position and desired new position. Recycling
    should be done based on the new position and function should return the actual delta. Actual delta could
    be modified value from \a delta. Delta modification can be useful e.g. to compensate the item changes
    that are caused by relayouting of items after changing the item position within layout.

    Default implementation does not recycle items and returns the \a delta unchanged.
*/
QPointF HbAbstractItemContainer::recycleItems(const QPointF &delta)
{
    return delta;
}

/*!
    \reimp
*/
bool HbAbstractItemContainer::eventFilter(QObject *obj, QEvent *event)
{
    Q_D(HbAbstractItemContainer);

    if (obj == d->mItemView) {
        switch (event->type()){
            case QEvent::GraphicsSceneResize: {
                viewResized(d->mItemView->size());
                d->updateItemBuffer();
                break;
            }
            default:
                break;
        }
    }

    return HbWidget::eventFilter(obj, event);
}

/*!
    Returns maximum amount of items that item buffer can hold. 

    Default implementation returns the total number of indexes that can
    be accessed on current view.

    Derived class that supports item recycling should define their own implementation
    for this function.

    \note Return value should not be more than HbAbstractItemView::indexCount()
*/
int HbAbstractItemContainer::maxItemCount() const
{    
    Q_D(const HbAbstractItemContainer);

    if (d->mItemView) {
        return d->mItemView->modelIterator()->indexCount();
    } else {
        return 0;
    }
}

/*!
    Deletes other prototypes and sets \a prototype as only prototype.

    Returns true if the prototype list was changed; otherwise returns false.
*/
bool HbAbstractItemContainer::setItemPrototype(HbAbstractViewItem *prototype)
{
    QList<HbAbstractViewItem *> prototypeList;
    prototypeList.append(prototype);
    return setItemPrototypes(prototypeList);
}

/*!
    Returns the list of item prototypes.
*/
QList<HbAbstractViewItem *> HbAbstractItemContainer::itemPrototypes() const
{
    Q_D(const HbAbstractItemContainer);
    
    if (d->mPrototypes.isEmpty()) {
        HbAbstractViewItem *defaultPrototype = createDefaultPrototype();
        if (defaultPrototype) {
            d->initPrototype(defaultPrototype);

            d->mPrototypes.append(defaultPrototype);
        }
    }

    return d->mPrototypes;
}

/*!
    Sets the list of prototypes. 
    
    Returns true if the prototype list was changed; otherwise returns false.
*/
bool HbAbstractItemContainer::setItemPrototypes(const QList<HbAbstractViewItem *> &prototypes)
{
    Q_D(HbAbstractItemContainer);
    
    bool changed = false;

    if (prototypes.count() > 0) {
        if (d->mPrototypes != prototypes) {
            foreach (HbAbstractViewItem *prototype, d->mPrototypes) {
                if (!prototypes.contains(prototype)) {
                    delete prototype;
                }
            }

            foreach (HbAbstractViewItem *prototype, prototypes) {
                if (!d->mPrototypes.contains(prototype)) {
                    d->initPrototype(prototype);
                }
            }
            changed = true;
        }

        d->mPrototypes = prototypes;
    }

    return changed;
    
}

/*!
    Returns state of view item with \a index.
*/
QMap<int,QVariant> HbAbstractItemContainer::itemState(const QModelIndex &index) const
{
    Q_D(const HbAbstractItemContainer);

    QMap<int,QVariant> result;

    if (index.isValid()) {
        int listIndex = d->findStateItem(index);
        if (listIndex != -1) {
            result = d->mItemStateList.at(listIndex).state;
        }
    }

    return result;
}

/*!
   This is an overloaded member function, provided for convenience.

   Sets single state \a key to \a value for a view item with \a index.
*/
void HbAbstractItemContainer::setItemStateValue(const QModelIndex &index, int key, QVariant value)
{
    Q_D(HbAbstractItemContainer);
    if (index.isValid()) {
        int listIndex = d->findStateItem(index);
        if (listIndex != -1) {
            d->mItemStateList[listIndex].state.insert(key,value);
        } else {
            HbAbstractItemContainerPrivate::StateItem stateItem;
            stateItem.index = index;
            stateItem.state.insert(key,value);

            d->mItemStateList.append(stateItem);
        }
    }
}

/*!
    Sets state of a view item with \a index to a \a map.
*/
void HbAbstractItemContainer::setItemState(const QModelIndex &index, QMap<int,QVariant> state)
{
    Q_D(HbAbstractItemContainer);
    if (index.isValid() && !state.isEmpty()) {
        int listIndex = d->findStateItem(index);
        if (listIndex != -1) {
            d->mItemStateList[listIndex].state = state;
        } else {
            HbAbstractItemContainerPrivate::StateItem stateItem;
            stateItem.index = index;
            stateItem.state = state;

            d->mItemStateList.append(stateItem);
        }
    }
}

/*!
    \reimp
*/
QVariant HbAbstractItemContainer::itemChange(GraphicsItemChange change, const QVariant & value)
{
    return HbWidget::itemChange(change, value);
}

/*!
    Returns the model indexes of items that are located on top left and bottom right corners
    of visible area.
*/
void HbAbstractItemContainer::firstAndLastVisibleModelIndex(
        QModelIndex& firstVisibleModelIndex,
        QModelIndex& lastVisibleModelIndex,
        bool fullyVisible) const
{
    Q_D(const HbAbstractItemContainer);

    QRectF viewRect(d->itemBoundingRect(d->mItemView));

    int firstVisibleBufferIndex( -1 );
    int lastVisibleBufferIndex( -1 );
    d->firstAndLastVisibleBufferIndex( firstVisibleBufferIndex, lastVisibleBufferIndex, viewRect, fullyVisible );
    if (firstVisibleBufferIndex != -1) {
        firstVisibleModelIndex = d->mItems.at(firstVisibleBufferIndex)->modelIndex();
    }
    if (lastVisibleBufferIndex != -1) {
        lastVisibleModelIndex = d->mItems.at(lastVisibleBufferIndex)->modelIndex();
    }
}

/*!
    Clears the state model.
*/
void HbAbstractItemContainer::removeItemStates()
{
    Q_D(HbAbstractItemContainer);
    d->mItemStateList.clear();
}

/*!
    Sets item recycling to \a enabled.
    By default recycling is off.
 */
void HbAbstractItemContainer::setItemRecycling(bool enabled)
{
    Q_D(HbAbstractItemContainer);
    if (d->mItemRecycling != enabled) {
        d->mItemRecycling = enabled;
        if (!enabled) {
            removeItemStates();
        }

        d->updateItemBuffer();
    }
}

/*!
    Returns whether item recycling feature is in use.
 */
bool HbAbstractItemContainer::itemRecycling() const
{
    Q_D(const HbAbstractItemContainer);
    return d->mItemRecycling;
}

/*!
    Sets the feature informing whether all items in the item view have the same size.
    In case all the items have the same size, the item view can do some 
    optimizations for performance purposes.
*/
void HbAbstractItemContainer::setUniformItemSizes(bool enable)
{
    Q_D(HbAbstractItemContainer);
    d->mUniformItemSizes = enable;
}

/*!
    Returns whether the uniform item sizes feature is in use.
 */
bool HbAbstractItemContainer::uniformItemSizes() const
{
    Q_D(const HbAbstractItemContainer);
    return d->mUniformItemSizes;
}

/*!
    Inserts item for \a index to \a pos.
*/
void HbAbstractItemContainer::insertItem(int pos, const QModelIndex &index, bool animate)
{
    Q_D(HbAbstractItemContainer);
    HbAbstractViewItem *item = d->createItem(index);

    if (item) {
        d->mItems.insert(pos, item);
        itemAdded(pos, item, animate);

        setItemModelIndex(item, index);
    }
}

/*!
    Reset the internal state of the container.
*/
void HbAbstractItemContainer::reset()
{
    removeItems(); 
    QCoreApplication::postEvent(this, new QEvent((QEvent::Type)UpdateItemBufferEvent));
}

/*!
    \deprecated HbAbstractItemContainer::type() const
        is deprecated.

    \reimp
*/
int HbAbstractItemContainer::type() const
{
    qWarning("HbAbstractItemContainer::type() const is deprecated!");

    return Type;
}

#include "moc_hbabstractitemcontainer.cpp"