emailuis/nmhswidget/src/nmhswidget.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 02 Sep 2010 20:15:00 +0300
changeset 65 478bc57ad291
parent 54 997a02608b3a
child 75 47d84de1c893
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
 * 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 <QtGui>
#include <QGraphicsLinearLayout>
#include <hbcolorscheme.h>
#include <hbdocumentloader.h>
#include <QTranslator>
#include <hbframedrawer.h>
#include <hbframeitem.h>
#include <hblabel.h>
#include "nmcommon.h"
#include "nmhswidget.h"
#include "nmhswidgetemailengine.h"
#include "nmmessageenvelope.h"
#include "nmhswidgettitlerow.h"
#include "nmhswidgetemailrow.h"
#include "nmhswidgetconsts.h"
#include "nmhswidgetdatetimeobserver.h"
#include "emailtrace.h"

NmHsWidget::NmHsWidget(QGraphicsItem *parent, Qt::WindowFlags flags)
    : HbWidget(parent, flags), 
      mMainContainer(0),
      mEmptySpaceContainer(0),
      mWidgetContainer(0),
      mTitleRow(0),
      mContentContainer(0),
      mNoMailsLabel(0),
      mContentLayout(0),              
      mBackgroundFrameDrawer(0),
      mTranslator(0),
      mEngine(0),      
      mAccountId(0),
      mAccountIconName(),
      mDateObserver(0),
      mIsExpanded(false)
{
    NM_FUNCTION;
}

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

    delete mTranslator;
    mTranslator = NULL;

    delete mEngine;
    mEngine = NULL;

    delete mBackgroundFrameDrawer;
    mBackgroundFrameDrawer = NULL;

    delete mDateObserver;
    mDateObserver = NULL;
}

/*!
 \fn QPainterPath NmHsWidget::shape()

 Called by home screen fw to check widget boundaries, needed to draw
 outside widget boundingRect.
 /return QPainterPath path describing actual boundaries of widget 
  including child items
 */
QPainterPath NmHsWidget::shape() const
{
    NM_FUNCTION;
    
    QPainterPath path;
    path.setFillRule(Qt::WindingFill);
    if (mWidgetContainer){
        //add mWidgetContainer using geometry to get
        //correct point for top-left-corner
        QRectF widgetRect = mWidgetContainer->geometry();
        path.addRect(widgetRect); 
        
        //then fetch shape from title row 
        QPainterPath titlepath;
        titlepath.addPath(mTitleRow->shape());
        //translate it's location to be inside mWidgetContainer
        titlepath.translate(widgetRect.topLeft());
        //and finally add it to path
        path.addPath(titlepath);    
    }
    //simplified path, i.e. only outlines
    return path.simplified();
}

/*!
 \fn void NmHsWidget::onShow()

 called by home screen fw when widget gets visible
 */
void NmHsWidget::onShow()
{
    NM_FUNCTION;
    if (mEngine) {
        mEngine->activate();
    }
}

/*!
 \fn void NmHsWidget::onHide()

 called by home screen fw when widget gets hidden
 */
void NmHsWidget::onHide()
{
    NM_FUNCTION;
    if (mEngine) {
        mEngine->suspend();
    }
}

/*!
 \fn bool NmHsWidget::loadDocML(HbDocumentLoader &loader)
 
 loads layout data and child items from docml file. Must be called after constructor.
 /return true if loading succeeded, otherwise false. False indicates that object is unusable
 */
bool NmHsWidget::loadDocML(HbDocumentLoader &loader)
{
    NM_FUNCTION;
    
    bool ok(false);
    loader.load(KNmHsWidgetDocML, &ok);
    
    if(ok) {
        mMainContainer = static_cast<HbWidget*> (loader.findWidget(KNmHsWidgetMainContainer));  
        mWidgetContainer = static_cast<HbWidget*> (loader.findWidget(KNmHsWidgetContainer));
        mContentContainer = static_cast<HbWidget*> (loader.findWidget(KNmHsWidgetContentContainer));
        mEmptySpaceContainer = static_cast<HbWidget*> (loader.findWidget(KNmHsWidgetEmptySpaceContainer));
        mNoMailsLabel = static_cast<HbLabel*> (loader.findWidget(KNmHsWidgetNoMailsLabel));
        if (!mMainContainer || !mWidgetContainer || !mContentContainer 
                || !mEmptySpaceContainer || !mNoMailsLabel ) {
            //something failed in documentloader, no point to continue
            NM_ERROR(1,"NmHsWidget::loadDocML fail @ containers or label");
            ok = false;
        }
    }
    return ok;
}

/*!
 Initializes Localization.
 /post mTranslator constructed & localization file loaded
 */
void NmHsWidget::setupLocalization()
{
    NM_FUNCTION;

    //Use correct localisation
    mTranslator = new QTranslator();
    QString lang = QLocale::system().name();
    mTranslator->load(KNmHsWidgetLocFileName + lang, KNmHsWidgetLocLocation);
    QCoreApplication::installTranslator(mTranslator);
}

/*!
 Initializes UI. Everything that is not done in docml files should be here.
 return true if ok, in error false.
 */
void NmHsWidget::setupUi()
{
    NM_FUNCTION;

    //main level layout needed to control docml objects
    QGraphicsLinearLayout *widgetLayout = new QGraphicsLinearLayout(Qt::Vertical);
    widgetLayout->setContentsMargins(KNmHsWidgetContentsMargin, KNmHsWidgetContentsMargin,
            KNmHsWidgetContentsMargin, KNmHsWidgetContentsMargin);
    widgetLayout->setSpacing(KNmHsWidgetContentsMargin);
    widgetLayout->addItem(mMainContainer);
    this->setLayout(widgetLayout);

    //fetch pointer to content container layout
    //to be able to add/remove email rows and no mails label
    mContentLayout = (QGraphicsLinearLayout*) mContentContainer->layout();
    
    //set noMailsLabel properties not supported by doc loader 
    QColor newFontColor;
    newFontColor = HbColorScheme::color("qtc_hs_list_item_content_normal");
    mNoMailsLabel->setTextColor(newFontColor);
    mNoMailsLabel->setVisible(true);   
    
    mContentLayout->removeItem(mNoMailsLabel);
    
    //widget background
    mBackgroundFrameDrawer = new HbFrameDrawer(KNmHsWidgetBackgroundImage,
        HbFrameDrawer::NinePieces);
    HbFrameItem* backgroundLayoutItem = new HbFrameItem(mBackgroundFrameDrawer);
    //set to NULL to indicate that ownership transferred
    mBackgroundFrameDrawer = NULL;
    mWidgetContainer->setBackgroundItem(backgroundLayoutItem);
}

/*!
 Initializes the widget.
 
 called by home screen fw when widget is added to home screen
 */
void NmHsWidget::onInitialize()
{
    NM_FUNCTION;
    
    QT_TRY {
	    // Use document loader to load the contents
	    HbDocumentLoader loader;
		//setup localization before docml loading
	    setupLocalization();
		
	    //load containers and mNoMailsLabel
        if (!loadDocML(loader)) {
            NM_ERROR(1,"NmHsWidget::onInitialize Fail @ loader");
            emit error(); //failure, no point to continue
            return;
        }

        //construct title row
        mTitleRow = new NmHsWidgetTitleRow(this);
        if (!mTitleRow->setupUI(loader)) {
            //title row creation failed
            NM_ERROR(1,"NmHsWidget::onInitialize fail @ titlerow");
            emit error(); //failure, no point to continue
            return;            
        }
				
        setupUi();

        //Engine construction is 2 phased. 
        mEngine = new NmHsWidgetEmailEngine(mAccountId);
        //Client must connect to exception signals before calling the initialize function
        //because we don't want to miss any signals.
        connect(mEngine, SIGNAL( exceptionOccured(const int&) ), this,
            SLOT( onEngineException(const int&) ));
        if (!mEngine->initialize()) {
            //engine construction failed. Give up.
            NM_ERROR(1,"NmHsWidget::onInitialize fail @ engine");
            emit error();
            return;
        }

        mTitleRow->updateAccountName(mEngine->accountName());

        //create observer for date/time change events
        mDateObserver = new NmHsWidgetDateTimeObserver();

        //Crete MailRows and associated connections
        createMailRowsList();

        updateMailData();
        mTitleRow->updateUnreadCount(mEngine->unreadCount());
        mTitleRow->setAccountIcon(mAccountIconName);
        mTitleRow->setExpandCollapseIcon(mIsExpanded);

        //Get signals about changes in mail data
        connect(mEngine, SIGNAL( mailDataChanged() ), this, SLOT( updateMailData() ));

        //Get Signals about changes in unread count
        connect(mEngine, SIGNAL( unreadCountChanged(const int&) )
                ,mTitleRow, SLOT( updateUnreadCount(const int&) ) );
        
        //Get signals about account name changes
        connect(mEngine, SIGNAL( accountNameChanged(const QString&) )
                ,mTitleRow, SLOT( updateAccountName(const QString&) ) );

	    //Get signals about user actions
	    connect(mTitleRow, SIGNAL( mailboxLaunchTriggered() )
	            ,mEngine, SLOT( launchMailAppInboxView() ) );
	    connect(mTitleRow, SIGNAL( expandCollapseButtonPressed() )
	            ,this, SLOT( handleExpandCollapseEvent() ) );
	    
	    setMinimumSize(mTitleRow->minimumWidth(), 
	            mEmptySpaceContainer->minimumHeight() + mTitleRow->minimumHeight());
    }
    QT_CATCH(...) {
        NM_ERROR(1,"NmHsWidget::onInitialize fail @ catch");
        emit error();
    }
}

/*!
 updateMailData slot
 */
void NmHsWidget::updateMailData()
{
    NM_FUNCTION;

    QList<NmMessageEnvelope> envelopes;
    int count = 0;
    if (mIsExpanded) {
        count = mEngine->getEnvelopes(envelopes, KMaxNumberOfMailsShown);
    }

    updateLayout(count);
    //count is safe for envelopes and mMailRows
    for (int i = 0; i < count; i++) {
        mMailRows.at(i)->updateMailData(envelopes.at(i));
    }
}

/*!
 Sets monitored account id from given string
 Needed for home screen framework which supports only QString type properties
 */
void NmHsWidget::setAccountId(const QString &text)
{
    NM_FUNCTION;

    bool ok;
    quint64 id = text.toULongLong(&ok);
    if (!ok) {
        NM_ERROR(1, "NmHsWidget::setAccountId: invalid account ID data, signal finished()!!!");
        //No valid account id so give up
        emit finished();
        return;
    }

    mAccountId.setId(id);
}

/*!
 Returns monitored account id as a string
 Needed for home screen framework which supports only QString type properties
 */
QString NmHsWidget::accountId() const
{
    NM_FUNCTION;
    return QString::number(mAccountId.id());
}

/*!
 Sets monitored account icon name from given string
 */
void NmHsWidget::setAccountIconName(const QString &text)
{
    NM_FUNCTION;
    mAccountIconName = text;
}

/*!
 Returns monitored account icon name
 */
QString NmHsWidget::accountIconName() const
{
    NM_FUNCTION;
    return mAccountIconName;
}

/*!
 Slot to handle expand/collapse trigger event
 */
void NmHsWidget::handleExpandCollapseEvent()
{
    NM_FUNCTION;
    toggleExpansionState();
}

/*!
 Sets widget expand/collapse state
 /post widget expansion state is changed
 */
void NmHsWidget::toggleExpansionState()
{
    NM_FUNCTION;

    mIsExpanded = !mIsExpanded;

    //save new state to home screen
    QStringList propertiesList;
    propertiesList.append("widgetState");
    emit setPreferences(propertiesList);

    //handle state change drawing
    updateMailData();

    mTitleRow->setExpandCollapseIcon(mIsExpanded);
}

/*!
 Sets expand/collapse state from given string (needed by homescreen)
 */
void NmHsWidget::setWidgetStateProperty(QString value)
{
    NM_FUNCTION;
    if (value == KNmHsWidgetStateCollapsed) {
        mIsExpanded = false;
    }
    else {
        mIsExpanded = true;
    }
}

/*!
 Returns widget expand/collapse state as string (needed by homescreen) 
 */
QString NmHsWidget::widgetStateProperty()
{
    NM_FUNCTION;
    if (mIsExpanded) {
        return KNmHsWidgetStateExpanded;
    }
    else {
        return KNmHsWidgetStateCollapsed;
    }
}

/*!
 Updates mMailRows list to include KMaxNumberOfMailsShown mail row widgets
 /post mMailRows contains KMaxNumberOfMailsShown mailRows 
 */
void NmHsWidget::createMailRowsList()
{
    NM_FUNCTION;

    //make sure that there are as many email rows as needed
    while (mMailRows.count() < KMaxNumberOfMailsShown) {
        NmHsWidgetEmailRow *row = new NmHsWidgetEmailRow(this);
        if (!row->setupUI()) {
            NM_ERROR(1, "NmHsWidget::createMailRowsList row->setUpUI() fails");
            //if setupUI fails no point to proceed
            emit error();
            return;
        }
        connect(row, SIGNAL(mailViewerLaunchTriggered(const NmId&)), mEngine,
            SLOT(launchMailAppMailViewer(const NmId&)));
        connect(mDateObserver, SIGNAL(dateTimeChanged()), row, SLOT(updateDateTime()));
        mMailRows.append(row);
    }

}

/*!
 Updates the Layout to contain the right items
 /param mailCount defines how many emails is to be shown
 /post If widget is collapsed, the layout contains only titleRow widget.
 If widget is expanded and mailCount is 0 layout will contain
 titlerow & noMailsLabel. 
 If widget is expanded and mailCount is greter
 than zero, layout will contain titlerow and KMaxNumberOfMailsShown times
 emailrow(s)
 */
void NmHsWidget::updateLayout(const int mailCount)
{
    NM_FUNCTION;

    if (mIsExpanded) {
        //set container height to content height 
        qreal contentHeight = KMaxNumberOfMailsShown
                * mMailRows.first()->maximumHeight();
        mContentContainer->setMaximumHeight(contentHeight);
        mContentContainer->setVisible(true);
        if (mailCount == 0) {
            addNoMailsLabelToLayout();
            removeEmailRowsFromLayout();
        }
        else {
            removeNoMailsLabelFromLayout();
            addEmailRowsToLayout();
        }
    }
    else {
        removeNoMailsLabelFromLayout();
        removeEmailRowsFromLayout();
        mContentContainer->setVisible(false);
        mContentContainer->setMaximumHeight(0);        
    }

    //resize the widget to new layout size
    qreal totalHeight = mEmptySpaceContainer->preferredHeight() + mTitleRow->containerHeight() + mContentContainer->maximumHeight();
    //set maximum sizes, otherwise widget will stay huge also when collapsed
    setMaximumHeight(totalHeight);
    mMainContainer->setMaximumHeight(totalHeight);
    mWidgetContainer->setMaximumHeight(totalHeight - mEmptySpaceContainer->preferredHeight());
    //resize here or widget cannot draw mail rows when expanding
    resize(mTitleRow->maximumWidth(), totalHeight);
    mMainContainer->resize(mTitleRow->maximumWidth(), totalHeight);
    mWidgetContainer->resize(mTitleRow->maximumWidth(), totalHeight - mEmptySpaceContainer->preferredHeight());

    updateMailRowsVisibility(mailCount);
}

/*!
 Updates mNoMailsLabel visibility based on widget state
 /param mailCount defines how many mail rows is needed
 /post if mail count is 0 and mIsExpanded equals true, then
 the mNoMailLabel is added to the mContentLayout. 
 */
void NmHsWidget::addNoMailsLabelToLayout()
{
    NM_FUNCTION;

    if (mNoMailsLabel->isVisible() || mMailRows.isEmpty()) {
        return;
    }
    //Add mNoMailsLabel to layout if not yet there and show it
    mContentLayout->addItem(mNoMailsLabel);
    //resize the widget to new layout size
    mNoMailsLabel->show();
}

/*!
 removeNoMailsLabelFromLayout removes mNoMailsLabel from the layout
 /post mNoMailsLabel is not in mContentLayout
 */
void NmHsWidget::removeNoMailsLabelFromLayout()
{
    NM_FUNCTION;
    //remove mNoMailsLabel from Layout and hide it
    mContentLayout->removeItem(mNoMailsLabel);
    mNoMailsLabel->hide();
}

/*!
 addEmailRowsToLayout adds every emailrow to the layout
 /post all elements in mMailRows are added to mContentLayout
 */
void NmHsWidget::addEmailRowsToLayout()
{
    NM_FUNCTION;
    foreach(NmHsWidgetEmailRow *row, mMailRows)
        {
            mContentLayout->addItem(row);
        }
}

/*!
 removeEmailRowsFromLayout removes every emailrow from the layout
 /post none of the elements in mMailRows are in mContentLayout
 */
void NmHsWidget::removeEmailRowsFromLayout()
{
    NM_FUNCTION;
    foreach(NmHsWidgetEmailRow *row, mMailRows)
        {
            mContentLayout->removeItem(row);
        }
}

/*!
 Updates mail row visibilities in static widget
 /param visibleCount defines how many items do have mail data
 /post all row items having mail data are visible, other rows are hidden
 */
void NmHsWidget::updateMailRowsVisibility(const int visibleCount)
{
    NM_FUNCTION;

    // set visible as many rows as requested by visibleCount param
    bool isVisible;

    for (int i = 0; i < mMailRows.count(); i++) {
        isVisible = false;
        if ((mIsExpanded) && (i < visibleCount)) {
            isVisible = true;
        }
        mMailRows.at(i)->setVisible(isVisible);
    }
}

/*!
 onEngineException (NmHsWidgetEmailEngineExceptionCode exc)
 signals widget to be finalized
 /param exc exception type
 */
void NmHsWidget::onEngineException(const int& exc)
{
    NM_FUNCTION;
    switch (exc) {
        case (NmEngineExcAccountDeleted):
            emit finished(); //succesful ending
            break;
        case (NmEngineExcFailure):
            emit error(); //failure
            break;
        default:
            break;
    }
}