emailuis/nmhswidget/src/nmhswidgetemailengine.cpp
author hgs
Thu, 14 Oct 2010 17:33:43 +0300
changeset 76 38bf5461e270
parent 74 6c59112cfd31
permissions -rw-r--r--
201041

/*
 * Copyright (c) 2010 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 <QTimer>
#include <QDir>
#include <qpluginloader.h>
#include <xqapplicationmanager.h>
#include <xqaiwdeclplat.h>
#include <email_services_api.h>
#include "nmcommon.h"
#include "nmmessageenvelope.h"
#include "nmhswidgetemailengine.h"
#include "nmdataplugininterface.h"
#include "nmmailbox.h"
#include "nmmessage.h"
#include "nmfolder.h"
#include "nmdatapluginfactory.h"
#include "nmhswidgetconsts.h"
#include "emailtrace.h"
#include "nmhswidgetlistmodel.h"

/*!
 Constructor
 */
NmHsWidgetEmailEngine::NmHsWidgetEmailEngine(const NmId& monitoredMailboxId) :
    mMailboxId(monitoredMailboxId),
    mFolderId(0),
    mAccountName(),
    mUnreadCount(-1),
    mEmailInterface(0),
    mFactory(0),
    mAccountDataNeedsUpdate(false),
    mMessageDataNeedsUpdate(false),
    mSuspended(false),
    mAiwRequest(0)
{
    NM_FUNCTION;
}

/*!
 initilaize - Initializes the engine
 Works as a second phase constructor. Must be called before any other operations.
 Client should connect to exceptionOccured signal before calling this method.
 /return true if initialize succeedes otherwise false. If false the object is unusable.
 */
bool NmHsWidgetEmailEngine::initialize()
{
    NM_FUNCTION;

    if (!constructNmPlugin()) {
        //if plugin connection fails, there's no reason to proceed
        return false;
    }
    updateData();
    updateUnreadCount();
    updateAccount();

    return true;
}

/*!
 constructNmPlugin
 /post Constructs a connection to an instance of NmDataPluginInterface
 /return true if construction succeeded, otherwise false.
 */
bool NmHsWidgetEmailEngine::constructNmPlugin()
{
    NM_FUNCTION;

    QObject* pluginInstance(0);
    //Get data plugin factory instance
    mFactory = NmDataPluginFactory::instance();
    if (!mFactory) {
        NM_ERROR(1,"NmHsWidgetEmailEngine::constructNmPlugin() -- mFactory FAILED");
        return false;
    }

    //Get plugin instance
    pluginInstance = mFactory->pluginInstance(mMailboxId);
    if (!pluginInstance) {
        NM_ERROR(1,"NmHsWidgetEmailEngine::constructNmPlugin() -- pluginInstance FAILED");
        return false;
    }

    //get interface instance
    mEmailInterface = mFactory->interfaceInstance(pluginInstance);

    if (!mEmailInterface) {
        NM_ERROR(1,"NmHsWidgetEmailEngine::constructNmPlugin() -- mEmailInterface FAILED");
        return false;
    }
    //Verify that the mailbox we are interested actually exists.
    //Otherwise emit account deleted event (instead of just returning)
    QList<NmId> ids;
    mEmailInterface->listMailboxIds(ids);
    if(!ids.contains(mMailboxId)){
        NM_ERROR(1,"NmHsWidgetEmailEngine::constructNmPlugin() -- !ids.contains(mMailboxId) FAILED");
        emit exceptionOccured(NmEngineExcAccountDeleted);
        return false;
    }

    //retrieve folderID for this mailbox's inbox
    //If NmId equals zero, we don't have the Initial sync done for the account
    //This is valid at least for IMAP accounts.
    //Folder ID is then retrieved later when first message event is received
    mFolderId = mEmailInterface->getStandardFolderId(mMailboxId, NmFolderInbox);

    //Subscription is needed - otherwise the signals will not be received
    mEmailInterface->subscribeMailboxEvents(mMailboxId);

    //Connect to events
    connect(pluginInstance, SIGNAL( messageEvent(NmMessageEvent, const NmId&,
            const QList<NmId>&, const NmId&) ), this,
        SLOT( handleMessageEvent(NmMessageEvent, const NmId&,
                const QList<NmId>&, const NmId&) ));

    connect( pluginInstance, SIGNAL( folderEvent(
             NmFolderEvent, const QList<NmId>&, const NmId&) ), this,
             SLOT( handleFolderEvent( NmFolderEvent, const QList<NmId>&, const NmId&)));

    connect(pluginInstance, SIGNAL( mailboxEvent(NmMailboxEvent, const QList<NmId>& ) ), this,
        SLOT( handleMailboxEvent(NmMailboxEvent, const QList<NmId>&) ));

    return true;
}


/*!
 Destructor
 */
NmHsWidgetEmailEngine::~NmHsWidgetEmailEngine()
{
    NM_FUNCTION;

    if (mFactory) {
        NmDataPluginFactory::releaseInstance(mFactory);
    }

}


/*!
 UnreadCount

 \return count of unread mails, or -1 if there are no mails at all in the mailbox.
 */
int NmHsWidgetEmailEngine::unreadCount()
{
    NM_FUNCTION;
    return mUnreadCount;
}

/*!
 accountName

 \return name of the monitored account
 */
QString NmHsWidgetEmailEngine::accountName()
{
    NM_FUNCTION;
    return mAccountName;
}


bool NmHsWidgetEmailEngine::updateUnreadCount()
{
    //retrieve new unread count to mUnreadCount
    NmFolder* folder = NULL;
    int folderErr = mEmailInterface->getFolderById(mMailboxId, mFolderId, folder);
    if (folderErr) {
        //retrieval of valid folder failed.
        return false;
    }
    if (folder) {
        //If messageCount in the folder is zero we must indicate unread count to be -1
        if (folder->messageCount() == 0) {
            mUnreadCount = -1;
        }
        else {
            mUnreadCount = folder->unreadMessageCount();
        }
        delete folder;
        folder = NULL;
        //limit the unread count to KMaxUnreadCount
        if (mUnreadCount > KMaxUnreadCount) {
            mUnreadCount = KMaxUnreadCount;
        }
        //emit signal about changed unread count
        emit unreadCountChanged(mUnreadCount);
    }else{
        return false;
    }
    return true;
}


/*!
 * TODO: UPDATE THIS
 Refresh email data. 
 \post mEnvelopeList is refreshed with valid content so that it has
       valid data with maximum of KMaxNumberOfEnvelopesProvided envelopes.

 - emits exceptionOccured(NmEngineExcFailure) if fatal error occurs.
 - emits mailDataChanged() if new mail data is set into mEnvelopeList
 - emits unreadCountChanged(mUnreadCount), if mUnreadCount is updated

 \return true if everything succeeded, otherwise false
 */
bool NmHsWidgetEmailEngine::updateData()
{
    NM_FUNCTION;
    if (!mEmailInterface) {
        NM_ERROR(1,"NmHsWidgetEmailEngine::updateData() -- Interface missing");
        emit exceptionOccured(NmEngineExcFailure); //fatal error
        return false; //if interface is missing there's nothing to do
    }

    QList<NmMessageEnvelope*> envelopeList;
    //get messages from inbox
    int msgErr = mEmailInterface->listMessages(mMailboxId, mFolderId, envelopeList,
        KMaxNumberOfEnvelopesProvided);
    if (msgErr) {
        //retrieval of messages failed.
        return false;
    }
    //emit signal about new message data right away
	emit mailDataRefreshed(envelopeList);

    return true;
}

/*!
 handleMessageEvent slot.
 */
void NmHsWidgetEmailEngine::handleMessageEvent(
    NmMessageEvent event,
    const NmId &folderId,
    const QList<NmId> &messageIds,
    const NmId& mailboxId)
{
    NM_FUNCTION;

    if (!mEmailInterface) {
        NM_ERROR(1,"NmHsWidgetEmailEngine::handleMessageEvent() -- Interface missing");
        emit exceptionOccured(NmEngineExcFailure); //fatal error
        return; //if interface is missing there's nothing to do
    }

    if (mFolderId == NmId(0)) {
        // inbox was not created in construction phase or the folder was deleted in some point,
        //so let's get the id now as we received first mail event
        mFolderId = mEmailInterface->getStandardFolderId(mMailboxId, NmFolderInbox);
    }
    if ((folderId == mFolderId) && (mailboxId == mMailboxId)) {
        //Data is updated only if the engine is not suspended

        if (mSuspended) {
            mMessageDataNeedsUpdate = true;
            return; //no further actions
        }
        updateUnreadCount();        
        switch(event){
            case(NmMessageCreated):
                    emit mailsReceived(getEnvelopesFromIds(messageIds));
                    break;
            case(NmMessageChanged):
                    emit mailsUpdated(getEnvelopesFromIds(messageIds));
                    break;
            case(NmMessageDeleted):
                    emit mailsDeleted(messageIds);
                    break;
        }

    }
}

QList<NmMessageEnvelope*> NmHsWidgetEmailEngine::getEnvelopesFromIds(const QList<NmId> messageIds)
{
    NM_FUNCTION;
    QList<NmMessageEnvelope*> ret;
    foreach(NmId id, messageIds){
        NmMessageEnvelope *msgEnvelope = NULL;
        msgEnvelope = envelopeById(id);
        if(msgEnvelope){
            ret.append(msgEnvelope);
        }
    }
    return ret;
}

/*!
    Get new NmMessageEnvelope object by id \a messageId from any folder.
    Ownership is transferred to the caller. NULL pointer is returned if
    message id is not found.
 */
NmMessageEnvelope *NmHsWidgetEmailEngine::envelopeById(const NmId &messageId)
{
    NM_FUNCTION;
    
    NmMessageEnvelope *msgEnvelope(NULL);
    NmMessage *newMessageObject(NULL);
    int retVal(NmNotFoundError);
    
    retVal = mEmailInterface->getMessageById(mMailboxId, mFolderId, messageId, newMessageObject);
    if (retVal < NmNoError || !newMessageObject) {
        // Return null object if fetching failed
        delete newMessageObject;
        newMessageObject = NULL;
        return NULL;
    }

    msgEnvelope = new NmMessageEnvelope(newMessageObject->envelope());

    delete newMessageObject;
    newMessageObject = NULL;
    return msgEnvelope;
}


/*!
 handleFolderEvent slot.
 If the monitored folder is deleted, clear the envelope list and unread count.
 Also the mFolderId is set to 0 to indicate the current state so that in device boot up
 we don't query any messages. When the first message event arrives, the folder ID must be
 retrieved again.
 */
void NmHsWidgetEmailEngine::handleFolderEvent( NmFolderEvent event,
    const QList<NmId> &folderIds, const NmId& mailboxId)
{
    NM_FUNCTION;
    //react only if the monitored folder for monitored account is deleted
    if (event == NmFolderIsDeleted && mailboxId == mMailboxId && folderIds.contains(mFolderId) )
    {
        emit mailDataCleared(); //emit mail data clearance
        mUnreadCount = 0;       //unread count to 0
        mFolderId = NmId(0);    //folder id to zero (indicates the situation where folder is not available)
        emit unreadCountChanged(mUnreadCount); // emit unread count change to UI
    }
}


/*!
 handleMailboxEvent slot.
 */
void NmHsWidgetEmailEngine::handleMailboxEvent(NmMailboxEvent event, const QList<NmId> &mailboxIds)
{
    NM_FUNCTION;
    if (mailboxIds.contains(mMailboxId)) {
        switch (event) {
            case (NmMailboxChanged): {
                if (mSuspended) {
                    mAccountDataNeedsUpdate = true;
                }
                else {
                    updateAccount();
                }
                break;
            }
            case (NmMailboxDeleted): {
                emit exceptionOccured(NmEngineExcAccountDeleted);
                break;
            }
            default:
                //ignored
                break;
        }
    }
}


/*!
 Update Account data
 \post if mEmailInterface exists, the mAccountName is refreshed from adapter
 and accountNameChanged signal is emitted.
 */
bool NmHsWidgetEmailEngine::updateAccount()
{
    NM_FUNCTION;

    NmMailbox* box = NULL;
    if (mEmailInterface) {
        int err = mEmailInterface->getMailboxById(mMailboxId, box);
        if (err) {
            //By specification return and wait another event
            return false;
        }
    }
    if (box) {
        mAccountName = box->name();
        delete box;
        box = NULL;
        emit accountNameChanged(mAccountName);
    }
    return true;
}


/*!
 forceUpdate slot.
 \post If engine is not suspended, this will force full update immediately.
 */
void NmHsWidgetEmailEngine::forceUpdate()
{
    NM_FUNCTION;
    if(mSuspended){
        mMessageDataNeedsUpdate = true; //this is enough to force update when activated
    }else{
        updateData();
        updateUnreadCount();
    }
}

/*!
 suspend slot.
 \post engine will not emit signals or refresh its data during suspension.
 */
void NmHsWidgetEmailEngine::suspend()
{
    NM_FUNCTION;
    mSuspended = true;
}

/*!
 activate slot.
 \post Engine will immediately refresh all the data that has been announced to
 have changed during the suspension. Events are enabled.
 */
void NmHsWidgetEmailEngine::activate()
{
    NM_FUNCTION;
    mSuspended = false;
    if (mAccountDataNeedsUpdate) {
        mAccountDataNeedsUpdate = false;
        updateAccount();
    }
    if (mMessageDataNeedsUpdate) {
        mMessageDataNeedsUpdate = false;
        updateData();
        updateUnreadCount();
    }
}


/*!
 launchMailAppInboxView slot.
 \post Mail application is launched to inbox view corresponding widget's mailbox id
 */
void NmHsWidgetEmailEngine::launchMailAppInboxView()
{
    NM_FUNCTION;
    NM_TIMESTAMP("Launch mail application from widget.");

    QT_TRY{
        if (!mAiwRequest) {
            XQApplicationManager appManager;
            mAiwRequest = appManager.create(
                    XQI_EMAIL_INBOX_VIEW, XQOP_EMAIL_INBOX_VIEW,
                    false);

            if (mAiwRequest) {
                connect(mAiwRequest, SIGNAL( requestError(int, const QString&) ),
                        this, SLOT( aiwRequestError(int, const QString&) ));
                connect(mAiwRequest, SIGNAL( requestOk(const QVariant&) ),
                        this, SLOT( aiwRequestOk(const QVariant&) ));
                QList<QVariant> list;
                list.append(QVariant(mMailboxId.id()));

                mAiwRequest->setSynchronous(false);
                mAiwRequest->setArguments(list);
                mAiwRequest->send();
            }
        }
    }
    QT_CATCH(...){
        // no actions taken.
        // try-catch mechanism added to avoid crashing widget, in case XQAiwRequest
        // creation raise exception.
    }
}

/*!
 launchMailAppMailViewer slot.
 \param messageId Defines the message opened to viewer
 \post Mail application is launched and viewing mail specified by
 */
void NmHsWidgetEmailEngine::launchMailAppMailViewer(const NmId &messageId)
{
    NM_FUNCTION;
    NM_TIMESTAMP("Launch mail viewer from widget.");

    QT_TRY{
        if (!mAiwRequest) {
            XQApplicationManager appManager;
            mAiwRequest = appManager.create(
                    XQI_EMAIL_MESSAGE_VIEW, "viewMessage(QVariant,QVariant)",
					//XQOP_EMAIL_MESSAGE_VIEW,
                    false);

            if (mAiwRequest) {
                connect(mAiwRequest, SIGNAL( requestError(int, const QString&) ),
                        this, SLOT( aiwRequestError(int, const QString&) ));
                connect(mAiwRequest, SIGNAL( requestOk(const QVariant&) ),
                        this, SLOT( aiwRequestOk(const QVariant&) ));

                QVariantList messageIdList;
                messageIdList.append(mMailboxId.id());
                messageIdList.append(mFolderId.id());
                messageIdList.append(messageId.id());

                QList<QVariant> argList;
                argList.append(QVariant(messageIdList));
                argList.append(quint64(EmailBackReturnsToMessageList));

                mAiwRequest->setSynchronous(false);
                mAiwRequest->setArguments(argList);
                mAiwRequest->send();
            }
        }
    }
    QT_CATCH(...){
        // no actions taken.
        // try-catch mechanism added to avoid crashing widget, in case XQAiwRequest
        // creation raise exception.
    }
}

/*!
 aiwRequestOk slot.
 */
void NmHsWidgetEmailEngine::aiwRequestOk(const QVariant& result)
{
    NM_FUNCTION;

    Q_UNUSED(result);

    deleteAiwRequest();
}

/*!
 aiwRequestError slot.
 */
void NmHsWidgetEmailEngine::aiwRequestError(int errorCode, const QString& errorMessage)
{
    NM_FUNCTION;

    Q_UNUSED(errorCode);
    Q_UNUSED(errorMessage);

    deleteAiwRequest();
}

/*!
 deleteAiwRequest function.
 */
void NmHsWidgetEmailEngine::deleteAiwRequest()
{
    NM_FUNCTION;

    delete mAiwRequest;
    mAiwRequest = NULL;
}