ganeswidgets/tsrc/fute/HgWidgetTest/src/hgwidgettestdatamodel.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 03 May 2010 13:32:54 +0300
changeset 1 e48454f237ca
parent 0 89c329efa980
child 2 49c70dcc3f17
permissions -rw-r--r--
Revision: 201015 Kit: 201018

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/

#include <QBrush>
#include <QColor>
#include <QtCore>

#include <hbicon.h>
#include <hbnamespace.h>
#include <hgwidgets/hgwidgets.h>

#include "hgwidgettestdatamodel.h"
#include "hgwidgettestalbumartmanager.h"
#include "trace.h"

typedef QPair<int, int> Range;
typedef QList<Range > RangeList;

/*!
    \class HgWidgetTestDataModel
    \brief Music Player collection data model.

    Collection data model implements the interface specified by HbAbstractDataModel,
    which defines the standard interface that item models must use to be able to
    interoperate with other components in the model/view architecture.

    Every item of data that can be accessed via a model has an associated model
    index.

    Each item has a number of data elements associated with it and they can be
    retrieved by specifying a role (see Qt::ItemDataRole) to the model's data
    returned by itemData() function.

    \sa HbAbstractDataModel
*/

/*!
 Constructs the collection data model.
 */
HgWidgetTestDataModel::HgWidgetTestDataModel(QObject *parent)
    : QAbstractListModel(parent),
      mCachingInProgress(false),
      mImageType(ImageTypeNone),
      mDefaultIcon((":/images/default.svg")),
      mUseLowResImages(false),
      mWrapper( new ThumbnailManager() ),
      mThumbnailRequestPending(false),
      mThumbnailRequestIndex(-1),
      mThumbnailRequestID(-1),
      mBufferManager(0)
{
    FUNC_LOG;
    mWrapper->setQualityPreference( ThumbnailManager::OptimizeForPerformance );

    mWrapper->setProperty("qimageSupport","true");

    QObject::connect( mWrapper, SIGNAL(thumbnailReady( QPixmap , void* , int, int ) ),
                      this, SLOT( thumbnailReady( QPixmap , void* , int , int )));

    init();
}

/*!
 Destructs the collection data model.
 */
HgWidgetTestDataModel::~HgWidgetTestDataModel()
{
    FUNC_LOG;

    disconnect( mWrapper, SIGNAL(thumbnailReady( QPixmap , void* , int , int )), this, SLOT(thumbnailReady( QPixmap , void* , int , int )) );
    delete mWrapper;
    delete mBufferManager;
}

void HgWidgetTestDataModel::setThumbnailSize(ThumbnailManager::ThumbnailSize size)
{
    mWrapper->setThumbnailSize(size);
}

void HgWidgetTestDataModel::init()
{
    FUNC_LOG;

    // Read all .jpg image paths from the c:/data/images folder
    QDir dir;
    dir.setFilter(QDir::Files | QDir:: Dirs);
#ifdef __WINS__
    dir.setPath(QString("c:/data/images"));
#else
    dir.setPath(QString("f:/data/images"));
#endif

    QFileInfoList list = dir.entryInfoList();
    for (int i = 0; i < list.size(); ++i){
        QFileInfo fileInfo = list.at(i);
        if (fileInfo.isFile()){
            QString s = fileInfo.filePath();
            if (s.indexOf(QString(".jpg"),0,Qt::CaseInsensitive)>0){
                mFiles.append(s);
                mImages.append(QImage());
                mVisibility.append(true);
            }
        }
    }

    QPixmap pixmap(":/images/default.svg");
    if (!pixmap.isNull()){
        mQIcon = QIcon(pixmap);
        if (!mQIcon.isNull()){
            mHbIcon = HbIcon(mQIcon);
        }
    }
}

/*!
 Returns the number of rows under the given \a parent.

 View will request for the row count immediately after a model is set.
 To prevent it from reading data while caching the album art for the first
 screen, return row count as zero.

 \reimp
 */
int HgWidgetTestDataModel::rowCount( const QModelIndex &parent ) const
{
    Q_UNUSED(parent);
    return mFiles.count();
}

/*!
 Returns the data stored for the item referred to by the \a index.

 \reimp
 */
QVariant HgWidgetTestDataModel::data(const QModelIndex &index, int role) const
{
    QVariant returnValue = QVariant();
    if ( !index.isValid() ) {
        return returnValue;
    }

    int row = index.row();

    if( row < 0 && row >= mFiles.count() ){
        return returnValue;
    }

    if( mBufferManager )
        mBufferManager->setPosition( row );

    switch ( role )
        {
    case HgWidget::HgVisibilityRole:
    {
        returnValue = mVisibility[index.row()];
    } break;
        case Qt::DisplayRole:
            {
            QStringList texts;
            QString text( "Primary " );
            text.append(QString::number(row));
            texts << text;
            text = "Secondary ";
            text.append(QString::number(row));
            texts << text;
            returnValue = texts;
            break;
            }
        case Qt::DecorationRole:
            {
            // INFO("Requesting model item" << row << ", " << mFiles.at(row));
            if (mFiles.at(row).isEmpty()) {
                returnValue = mDefaultIcon;
            }
            else {
                QImage icon = mImages.at(row);
                if ( !icon.isNull() )
                    {
                    if (mUseLowResImages) {
                        QSize size = icon.size();
                        icon = icon.scaled(QSize(size.width()/4, size.height()/4));
                    }

                    switch(mImageType)
                        {
                        case ImageTypeHbIcon:
                            {
                            returnValue = mHbIcon;
                            break;
                            }
                        case ImageTypeQImage:
                            {
                            returnValue = icon;
                            break;
                            }
                        case ImageTypeQIcon:
                            {
                            returnValue = mQIcon;
                            break;
                            }
                        default:
                            break;
                        }

                    }
                else
                    {
                    returnValue = mDefaultIcon;
                    }
                }
            break;
            }
        case Hb::IndexFeedbackRole:
            {
            returnValue = QString::number(row);
            break;
            }
        case Qt::BackgroundRole:
            {
            if ( (index.row() % 2) == 0 ) {
                QColor color(211,211,211,127);
                QBrush brush(color);
                returnValue = brush;
            }
            else {
                QColor color(255,250,250,127);
                QBrush brush(color);
                returnValue = brush;
            }
            break;
            }

        case (Qt::UserRole+2):
            {
                QImage icon = mImages.at(row);
                if (!icon.isNull())
                {
                    returnValue = icon;
                }
            } break;
        }

    return returnValue;
}

/*!
 Must be called when data has changed and model needs to be refreshed
 to reflect the new data.
 */
void HgWidgetTestDataModel::refreshModel()
{
    // Cancel all outstanding album art request first, then reset the model.

    // TODO FIX

}

/*!
 Remove items from model (do not actually delete them).
 */
void HgWidgetTestDataModel::remove(const QItemSelection &selection)
{
    FUNC_LOG;

    QModelIndexList modelIndexes = selection.indexes();
    int removeCount = modelIndexes.count();
    int originalItemCount = mFiles.count();
    if (originalItemCount-removeCount > 0) {
        RangeList removeRanges;
        qSort(modelIndexes);
        while (!modelIndexes.isEmpty()) {
            QModelIndexList::iterator i = modelIndexes.begin();
            QModelIndexList::iterator start = i;
            int lastRow = i->row();
            while (++i != modelIndexes.end() && i->row() == lastRow+1) {
                lastRow++;
            }
            removeRanges.append(Range(start->row(), lastRow));
            modelIndexes.erase(start, i);
        }

        // Work backwards to keep the indexes consistent
        for (int i = removeRanges.count()-1; i >= 0; i--) {
            Range range = removeRanges.at(i);
            beginRemoveRows(QModelIndex(), range.first, range.second);
            for (int j = range.second; j >= range.first; j--) {
                INFO("Removing model item" << j);
                mFiles.removeAt(j);
            }
            endRemoveRows();
        }
    }
    else if (originalItemCount-removeCount == 0) {
        beginRemoveRows(QModelIndex(), 0, originalItemCount-1);
        mFiles.clear();
        endRemoveRows();
    }
}

/*!
 Move items to the target index in the model. The selection should be contiguous.
 */
void HgWidgetTestDataModel::move(const QItemSelection &selection, const QModelIndex &target)
{
    FUNC_LOG;

    QModelIndexList modelIndexes = selection.indexes();

    if (modelIndexes.count() > 0 && target.isValid()) {
        int first = modelIndexes.front().row();
        int last = modelIndexes.back().row();
        int targetRow = target.row();
        INFO("Move indexes" << first << "-" << last << "to" << targetRow);
        if (targetRow < first) {
            beginMoveRows(QModelIndex(), first, last, QModelIndex(), targetRow);
            for (int i = 0; i <= last-first; i++) {
                mFiles.move(first+i, targetRow+i);
            }
            endMoveRows();
        }
        else if (targetRow > last) {
            beginMoveRows(QModelIndex(), first, last, QModelIndex(), targetRow);
            for (int i = 0; i <= last-first; i++) {
                mFiles.move(last-i, targetRow);
            }
            endMoveRows();
        }
    }
}

/*!
 Add count dummy items at the target index in the model.
 */
void HgWidgetTestDataModel::add(const QModelIndex &target, int count)
{
    FUNC_LOG;

    if (target.isValid()) {
        beginInsertRows(QModelIndex(), target.row(), target.row()+count-1);
        for (int i = 0; i < count; i++) {
            mFiles.insert(target.row(), QString());
            mVisibility.insert(target.row(), true);
        }
        endInsertRows();
    }
}

void HgWidgetTestDataModel::reset()
{
    emit beginResetModel();
    mImages.removeAt(0);
    mFiles.removeAt(0);
    emit endResetModel();
}

/*!
 Slot to be called when album art for the \a index needs to be updated.
 */
void HgWidgetTestDataModel::updateAlbumArt( int index )
{
    if ( index >= 0 && index < mFiles.count() ) {
        QModelIndex modelIndex = QAbstractItemModel::createIndex(index, 0);
        emit dataChanged(modelIndex, modelIndex);
    }
}

/*!
 Slot to be called when album art cache is ready.
 */
void HgWidgetTestDataModel::albumCacheReady()
{
    if ( mCachingInProgress ) {
        mCachingInProgress = false;
        reset();
    }
}

HgTestImageType HgWidgetTestDataModel::imageDataType() const
{
    return mImageType;
}

void HgWidgetTestDataModel::setImageDataType(HgTestImageType type)
{
    mImageType = type;
}

bool HgWidgetTestDataModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
    if (role == HgWidget::HgVisibilityRole)
    {
        mVisibility[index.row()] = value.toBool();
        emit dataChanged(index, index);
        return true;
    }
    return false;
}

void HgWidgetTestDataModel::enableLowResImages(bool enabled) {

    mUseLowResImages = enabled;
}

bool HgWidgetTestDataModel::lowResImagesEnabled() const {

    return mUseLowResImages;
}

void HgWidgetTestDataModel::getNextThumbnail()
{
    if ( !mThumbnailRequestPending && mWaitingThumbnails.count()){
        QString image = mWaitingThumbnails.takeFirst();
        int index = mFiles.indexOf(image);
        int *clientData = new int(index);
        mThumbnailRequestID = mWrapper->getThumbnail(image, clientData, -1);
        mThumbnailRequestIndex = index;
        mThumbnailRequestPending = true;
    }
}

void HgWidgetTestDataModel::setBuffer(int buffer, int treshhold)
{
    mWaitingThumbnails.clear();

    if (mThumbnailRequestID!=-1){
        mWrapper->cancelRequest(mThumbnailRequestID);
    }

    mThumbnailRequestID = -1;
    mThumbnailRequestIndex = -1;
    mThumbnailRequestPending = false;

    delete mBufferManager;
    mBufferManager = 0;
    mBufferManager = new BufferManager(this, buffer, treshhold, 0, mFiles.count());
    for (int i = 0; i<mImages.count();i++) {
        mImages.replace(i, QImage());
    }
}

void HgWidgetTestDataModel::release(int start, int end)
{
    bool requestNew = false;
    int first = (start<=end)?start:end;
    if (first<0)
        first =0;

    int last = end>=start?end:start;
    if (last>=mFiles.count())
        last=mFiles.count()-1;


    for (int i(first); i<=last; i++){
        mWaitingThumbnails.removeOne(mFiles.at(i));
        if (mThumbnailRequestIndex==i && mThumbnailRequestID!=-1){
            mWrapper->cancelRequest(mThumbnailRequestID);
            requestNew = true;
        }
        mImages.replace(i,QImage());
    }

    if (requestNew){
        mThumbnailRequestIndex = -1;
        mThumbnailRequestID = -1;
        mThumbnailRequestPending = false;
        getNextThumbnail();
    }
}

void HgWidgetTestDataModel::request(int start, int end, requestsOrder order)
{
    int first = start;
    int last = end;

    if (first<0)
        first =0;

    if (last>=mFiles.count())
        last=mFiles.count()-1;

    if (order == ascending){
        for (int i(first); i<=last; i++){
            mWaitingThumbnails.append(mFiles.at(i));
        }
    } else if (order ==descending){
        for (int i(last); i>=first; i--){
            mWaitingThumbnails.append(mFiles.at(i));
        }
    }

    getNextThumbnail();
}

void HgWidgetTestDataModel::thumbnailReady( QPixmap pixmap, void* data, int /*id*/, int error )
{
    if (!error && !pixmap.isNull() ){
//        int idx = reinterpret_cast<int>(data);
        mImages.replace(mThumbnailRequestIndex,pixmap.toImage().convertToFormat(QImage::Format_RGB16));
        QModelIndex modelIndex = QAbstractItemModel::createIndex(mThumbnailRequestIndex, 0);
        emit dataChanged(modelIndex, modelIndex);
    }
    mThumbnailRequestIndex = -1;
    mThumbnailRequestID = -1;
    mThumbnailRequestPending = false;
    getNextThumbnail();
}