hgcacheproxymodel/src/hgdataprovidermodel.cpp
changeset 1 e48454f237ca
child 2 49c70dcc3f17
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgcacheproxymodel/src/hgdataprovidermodel.cpp	Mon May 03 13:32:54 2010 +0300
@@ -0,0 +1,387 @@
+/*
+* 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:
+*
+*  Version     : %version: 3 %
+*/
+#include <e32debug.h>
+#include <QVariant>
+#include <HbIcon.h>
+#include <qpixmapdata_p.h>
+#include <hgwidgets/hgdataprovidermodel.h>
+#include <hgwidgets/hgcacheproxymodel.h>
+#include "hglogger.h"
+
+
+const int KQPixmapCacheEmergencyBuffer = 5;
+
+HgDataProviderModel::HgDataProviderModel(QObject *parent) : 
+    QAbstractItemModel(parent),
+    mCache(new QList<QMap<int, QVariant>*>()),
+    mCacheSize(0),
+    mUnallocatedPixmaps(0),
+    mObserver(0)
+{
+    TX_ENTRY
+    TX_EXIT
+}
+
+HgDataProviderModel::~HgDataProviderModel()
+{
+    TX_ENTRY    
+    clearCache();
+    delete mCache;
+    qDeleteAll( mFreePixmaps.begin(), mFreePixmaps.end() );
+    mFreePixmaps.clear();
+    qDeleteAll( mUsedPixmaps.begin(), mUsedPixmaps.end() );
+    mUsedPixmaps.clear();
+    TX_EXIT    
+}
+
+void HgDataProviderModel::release(QList<int> list, bool silent)
+{
+    TX_ENTRY    
+    int i=0;
+    int min = count();
+    int max = 0;
+    
+    for ( int idx = 0; idx < list.count(); idx++){
+        i = list[idx];
+        if ( i >=0 && i<count()){
+            if ( i < min)
+                min = i;
+            if ( i > max)
+                max = i;
+            resetIcon(i);
+        }
+    }
+    
+    doReleaseData(list, silent);
+    
+    if (min<max){ //min<max is true if at least one item is in range <0,count())
+        emitDataChanged(min, max, silent);
+    }
+    TX_EXIT    
+}
+
+void HgDataProviderModel::request(QList<int> list, bool silent)
+{
+    doRequestData(list, silent); 
+}
+
+void HgDataProviderModel::registerObserver(HgDataProviderModelObserver* obs)
+{
+    TX_ENTRY
+    mObserver = obs;
+    TX_EXIT    
+}
+
+QModelIndex HgDataProviderModel::index(int row, int column,
+                                     const QModelIndex &parent) const
+{   
+    Q_UNUSED(parent);
+    if (  row >= rowCount() ){
+        row = -1;
+    }
+    if (  column >= columnCount() ){
+        column = -1;
+    }
+    
+    return QAbstractItemModel::createIndex(row, column); 
+}
+
+QModelIndex HgDataProviderModel::parent(const QModelIndex &child) const
+{
+    Q_UNUSED(child);
+    return QModelIndex();   //returns always invalid model index
+}
+
+int HgDataProviderModel::rowCount(const QModelIndex &parent) const
+{
+    Q_UNUSED(parent);
+    return count();
+}
+
+int HgDataProviderModel::columnCount(const QModelIndex &parent) const
+{
+    Q_UNUSED(parent);
+    return 1;
+}
+
+QVariant HgDataProviderModel::data(const QModelIndex &index, int role) const
+{
+    return data(index.row(), role);
+}
+
+QVariant HgDataProviderModel::data(int idx, int role) const
+{
+    QVariant res;
+    if ( containsRole(idx, role)){
+        res = mCache->at(idx)->value(role);
+    } else if (role == Qt::DecorationRole ){
+        res = defaultIcon();
+    }
+    return res;
+}
+
+QMap<int, QVariant> HgDataProviderModel::itemData(const QModelIndex &index) const
+{
+    QMap<int, QVariant> res;
+    if ( index.row()>=0 && index.row()<count() ){
+        res = QMap<int, QVariant>(*mCache->at(index.row()));
+    }   
+    return res;
+}
+
+void HgDataProviderModel::clearCache()
+{
+    qDeleteAll( mCache->begin(), mCache->end() );
+    mCache->clear();
+}
+
+int HgDataProviderModel::count() const
+{
+    return mCache->count();
+}
+
+bool HgDataProviderModel::update(int pos, QList< QPair< QVariant, int > >* list, bool silent)
+{
+    bool change(false);
+    if (list && list->count() && pos >=0 && pos<count() && mCache->at(pos)) {
+        while(list->count()){
+            QPair< QVariant, int > pair = list->takeFirst();
+            change = update(pos, pair.first, pair.second, true)|change;
+        }
+        if ( !silent && change ){
+            emitDataChanged(pos, pos, false);
+        }
+    }
+    return change;
+}
+
+bool HgDataProviderModel::update(int pos, QVariant obj, int role, bool silent)
+{
+    bool change(false);
+    
+    if ( pos >=0 && pos<count() && mCache->at(pos)){
+        mCache->at(pos)->insert(role, obj); //this will remove old one if needed
+        change = true;
+    }
+    
+    if ( !silent && change ){
+        emitDataChanged(pos, pos, false);
+    }
+    return change;
+}
+
+bool HgDataProviderModel::updateIcon(int pos, QVariant obj, bool silent)
+{
+    if (obj.isValid()==false)
+        return false;
+    
+    bool change(false);
+    if ( pos >=0 && pos<count() && mCache->at(pos)){
+        mCache->at(pos)->insert(Qt::DecorationRole, obj); //will remove old if needed
+        change = true;
+    }
+    
+    if (!silent && change){
+        TX_LOG
+        if ( mObserver){
+            mObserver->dataUpdated(pos,pos);
+        } else {
+            QModelIndex topLeft = index(pos, 0);
+            QModelIndex bottomRight = index(pos, 0);
+            emit dataChanged(topLeft,bottomRight);
+        }
+    }
+    return change;
+}
+
+void HgDataProviderModel::resetIcon(int pos)
+{
+    if ( containsRole(pos, Qt::DecorationRole)){
+        mCache->at(pos)->remove(Qt::DecorationRole);
+    }
+}
+
+void HgDataProviderModel::newItem(QList< QPair< QVariant, int > >* list, bool silent)
+{
+    insertItem(mCache->count(), list, silent);
+}
+
+void HgDataProviderModel::newItem(QPair< QVariant, int > item, bool silent)
+{
+    insertItem(mCache->count(), item, silent);
+}
+
+void HgDataProviderModel::insertItem(int pos, QList< QPair< QVariant, int > >* list, bool silent)
+{
+    doInsertItem(pos, list, silent);
+}
+
+void HgDataProviderModel::insertItem(int pos, QPair< QVariant, int > item, bool silent)
+{
+    QList< QPair< QVariant, int > > list;
+    list.append(item);
+    doInsertItem(pos, &list, silent);
+}
+
+void HgDataProviderModel::doInsertItem(int pos, QList< QPair< QVariant, int > >* list, bool silent)
+{
+    if (pos >mCache->count()){
+        pos = mCache->count();
+    } else if (pos <0){
+        pos = 0;
+    }
+    
+    if ( !silent){
+        beginInsertRows(QModelIndex(), pos, pos);
+    }
+    
+    mCache->insert(pos, new QMap<int, QVariant>());
+    if (list && list->count()){
+        update(pos, list, true);
+    }
+    
+    if ( !silent){
+        endInsertRows();
+    } 
+}
+
+
+void HgDataProviderModel::removeItem(int pos)
+{
+    removeItems(pos, 1);
+}
+
+void HgDataProviderModel::removeItems(int pos, int size)
+{
+    if (pos >mCache->count())
+        return;
+    else if (pos <0){
+        size = size + pos; //pos <0
+        pos = 0;
+    }
+    
+    if (size >mCache->count()){
+        size = mCache->count();
+    } else if (size <0){
+        return;
+    }
+    
+    beginRemoveRows(QModelIndex(),pos, pos+size-1);
+    for (int i=0; i<size && pos<mCache->count(); i++){
+        mCache->removeAt(pos);
+    }
+    endRemoveRows();
+}
+        
+void HgDataProviderModel::resetModel() 
+{
+    beginResetModel();
+    doResetModel();
+    endResetModel();
+}
+
+void HgDataProviderModel::emitDataChanged(int from, int to, bool silent)
+{
+    if ( !silent ){
+        TX_LOG    
+        QModelIndex topLeft = index(from, 0);
+        QModelIndex bottomRight = index(to, 0);
+        emit dataChanged(topLeft,bottomRight);
+    }
+}
+
+void HgDataProviderModel::resizeQPixmapPool(int newSize)
+{
+    mQPixmapsLock.lock();
+    int currentSize = mFreePixmaps.count() + mUsedPixmaps.count();
+    int diff = currentSize - newSize - KQPixmapCacheEmergencyBuffer;
+    mUnallocatedPixmaps = 0;
+    while (diff != 0){
+        if (diff < 0){
+            mUnallocatedPixmaps++;
+            diff++;
+        }else{
+            if (mUnallocatedPixmaps>0){
+                mUnallocatedPixmaps--;
+            } else if (mFreePixmaps.count()){
+                mFreePixmaps.removeLast();
+            } //else will be deleted with releasePixmap;
+            diff--;
+        }
+    }
+    mQPixmapsLock.unlock();
+    mCacheSize = newSize;
+}
+
+void HgDataProviderModel::releasePixmap(int idx)
+{
+    mQPixmapsLock.lock();
+    if (mUsedPixmaps.contains(idx)){
+        QPixmap* pix = mUsedPixmaps.take(idx);
+        if ( mFreePixmaps.count() + mUsedPixmaps.count() + mUnallocatedPixmaps> mCacheSize + KQPixmapCacheEmergencyBuffer){
+            delete pix; //we have too many pixmaps
+        }else{
+            mFreePixmaps.append(pix);
+        }
+    }else{
+        TX_LOG_ARGS( QString("can't release pixmap for idx=%0").arg(idx));
+    }
+    mQPixmapsLock.unlock();    
+}
+
+QVariant HgDataProviderModel::createIcon(int index, QPixmap aPixmap)
+{
+	QPixmap* pix = getPixmap(index);
+	if (pix){
+		if ( pix->pixmapData() ){
+			pix->pixmapData()->fromImage(aPixmap.toImage(), Qt::AutoColor );  
+		} else {
+			*pix = aPixmap;
+		}
+		mQPixmapsLock.lock();
+		mUsedPixmaps.insert(index, pix);
+		mQPixmapsLock.unlock();
+		return HbIcon(QIcon(*pix));	
+	}
+	TX_EXIT_ARGS( QString("No pixmap avilable"));
+	return QVariant();
+}
+
+QPixmap* HgDataProviderModel::getPixmap(int idx)
+{
+    TX_ENTRY
+    QPixmap* res = NULL;
+    mQPixmapsLock.lock();
+    if ( mUsedPixmaps.contains(idx)){
+        res = mUsedPixmaps.take(idx);//let's just replace pixmapdata for that pixmap
+    } else {
+        if (!mFreePixmaps.isEmpty()){
+            res = mFreePixmaps.takeFirst();
+        }else if (mUnallocatedPixmaps){
+            mUnallocatedPixmaps--;
+            res = new QPixmap();
+        } else {
+            TX_LOG_ARGS(QString("no free pixmaps"));
+        }        
+    }
+    mQPixmapsLock.unlock();
+    TX_EXIT    
+    return res;
+}
+
+//eof