radioapp/radiouiengine/src/radiotimerpool.cpp
author hgs
Fri, 15 Oct 2010 16:26:27 +0300
changeset 57 21be958eb3ce
permissions -rw-r--r--
201041

/*
* 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:
*
*/

// System includes
#include <QTimer>
#include <QMetaMethod>

// User includes
#include "radiotimerpool.h"
#include "radiologger.h"

const int TIMER_BUFFER_SIZE = 2;

/*!
 *
 */
RadioTimerPool::RadioTimerItem::RadioTimerItem( RadioTimerPool* parent ) :
    mTimer( new QTimer() )
{
    Radio::connect( mTimer.data(),  SIGNAL(timeout()),
                    parent,         SLOT(timerFired()) );
    mTimer->setSingleShot( true );
}

/*!
 *
 */
RadioTimerPool::RadioTimerItem::~RadioTimerItem()
{
}

/*!
 *
 */
void RadioTimerPool::RadioTimerItem::reset()
{
    mTimer->stop();
    mId = -1;
    mParam = QVariant();
    mReceiver = NULL;
    mReceiverMember.clear();
}

/*!
 *
 */
RadioTimerPool::RadioTimerPool( QObject* parent ) :
    QObject( parent )
{
    createItem();
}

/*!
 *
 */
RadioTimerPool::~RadioTimerPool()
{
    qDeleteAll( mTimerMap.values() );
}

/*!
 *
 */
void RadioTimerPool::startTimer( int msec, int id, QObject* receiver, const char* member, QVariant param )
{
    LOG_METHOD;
    RadioTimerItem* availableItem = NULL;
    foreach ( RadioTimerItem* item, mTimerMap.values() ) {
        if ( !item->mTimer->isActive() ) {
            availableItem = item;
        } else {
            if ( item->mReceiver == receiver && item->mId == id ) {
                LOG_FORMAT( "RadioTimerPool::startTimer. Timer %d already running for class %s", id, receiver->metaObject()->className() );
            }
        }
    }

    if ( !availableItem ) {
        availableItem = createItem();
        LOG( "RadioTimerPool::startTimer. Creating new timer" );
    }
    LOG_FORMAT( "Amount of timers: %d", mTimerMap.count() );

    availableItem->mId = id;
    availableItem->mParam = param;
    availableItem->mReceiver = receiver;

    // SIGNAL() and SLOT() macros add a number in the beginning of member function name for some internal housekeeping
    // That causes the method to not be found from the meta object so we need to trim it off
    availableItem->mReceiverMember = member;
    availableItem->mReceiverMember = availableItem->mReceiverMember.right( availableItem->mReceiverMember.length() - 1 );

    availableItem->mTimer->start( msec );
}

/*!
 *
 */
void RadioTimerPool::cancelTimer( int id, const QObject* receiver )
{
    foreach ( RadioTimerItem* item, mTimerMap.values() ) {
        if ( item->mId == id && item->mReceiver == receiver ) {
            item->reset();
            break;
        }
    }
    freeUnusedTimers();
}

/*!
 *
 */
bool RadioTimerPool::isTimerActive( int id, const QObject* receiver ) const
{
    foreach ( const RadioTimerItem* item, mTimerMap.values() ) {
        if ( item->mId == id &&
             item->mReceiver == receiver &&
             item->mTimer->isActive() ) {
            return true;
        }
    }
    return false;
}

/*!
 *
 */
void RadioTimerPool::freeUnusedTimers()
{
    QList<RadioTimerItem*> unusedItems;
    foreach ( RadioTimerItem* item, mTimerMap.values() ) {
        if ( !item->mTimer->isActive() ) {
            unusedItems.append( item );
        }
    }

    if ( unusedItems.count() > TIMER_BUFFER_SIZE ) {
        foreach( const RadioTimerItem* item, unusedItems ) {
            mTimerMap.remove( item->mTimer.data() );
            delete item;
        }
    }
}

/*!
 * Private slot
 */
void RadioTimerPool::timerFired()
{
    QTimer* timer = static_cast<QTimer*>( sender() );
    if ( mTimerMap.contains( timer ) ) {
        RadioTimerItem* item = mTimerMap.value( timer );
        if ( item->mReceiver ) {
            QByteArray normalizedSignature = QMetaObject::normalizedSignature( item->mReceiverMember.toAscii().constData() );
            int methodIndex = item->mReceiver->metaObject()->indexOfMethod( normalizedSignature );
            if ( methodIndex != -1 ) {
                QMetaMethod method = item->mReceiver->metaObject()->method( methodIndex );
                const int paramCount = method.parameterTypes().count();
                if ( paramCount == 0 ) {
                    method.invoke( item->mReceiver, Qt::QueuedConnection );
                } else if ( paramCount == 1 ) {
                    method.invoke( item->mReceiver, Qt::QueuedConnection, Q_ARG( int, item->mId ) );
                } else if ( paramCount == 2 ) {
                    method.invoke( item->mReceiver, Qt::QueuedConnection,
                                   Q_ARG( int, item->mId ), Q_ARG( QVariant, item->mParam ) );
                }
            }

            item->reset();
        }
    }
}

/*!
 *
 */
RadioTimerPool::RadioTimerItem* RadioTimerPool::createItem()
{
    RadioTimerItem* item = new RadioTimerItem( this );
    mTimerMap.insert( item->mTimer.data(), item );
    return item;
}