emailuis/nmhswidget/src/nmhswidget.cpp
author hgs
Wed, 15 Sep 2010 12:09:55 +0300
changeset 68 83cc6bae1de8
parent 62 a8c646b56683
child 74 6c59112cfd31
permissions -rw-r--r--
201037

/*
 * 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 <QTranslator>
#include <QGraphicsLinearLayout>
#include <hbcolorscheme.h>
#include <hbdocumentloader.h>
#include <hbframedrawer.h>
#include <hbframeitem.h>
#include <hblabel.h>
#include <hbstyleloader.h>
#include <hblistview.h>
#include <hbdeviceprofile.h>
#include "nmcommon.h"
#include "nmmessageenvelope.h"
#include "nmhswidget.h"
#include "nmhswidgetemailengine.h"
#include "nmhswidgettitlerow.h"
#include "nmhswidgetconsts.h"
#include "nmhswidgetdatetimeobserver.h"
#include "nmhswidgetlistviewitem.h"
#include "nmhswidgetlistmodel.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),
      mListView(0),
	  mListModel(0)
{
    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));
        mListView = static_cast<HbListView*> (loader.findWidget("mailListView"));
        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();

    //try to load translation from c drive. If not found then try z.
    bool loadingSucceed = mTranslator->load(KNmHsWidgetLocFileName + lang, "c:" + KNmHsWidgetLocLocation);
    if(!loadingSucceed){
        mTranslator->load(KNmHsWidgetLocFileName + lang, "z:" + 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);
}

/*!
 Sets correct properties and mail item proto type for mail list view 
 */
void NmHsWidget::createMailRowsList()
{
	  NM_FUNCTION;
    connect(mListView, SIGNAL(activated(const QModelIndex&)), this,
        SLOT(openMessage(const QModelIndex&)));

    // Set the list widget properties.
    NmHsWidgetListViewItem *prototype = new NmHsWidgetListViewItem(mListView);
    mListView->setItemPrototype(prototype);
    mListModel = new NmHsWidgetListModel();
    mListView->setModel(mListModel);  
}

/*!
 Initializes the widget.
 
 called by home screen fw when widget is added to home screen
 */
void NmHsWidget::onInitialize()
{
    NM_FUNCTION;
    
    QT_TRY {
    
	    HbStyleLoader::registerFilePath(":/layout/nmhswidgetlistviewitem.widgetml");
	    HbStyleLoader::registerFilePath(":/layout/nmhswidgetlistviewitem.css");
	    
	    // 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;
        }

		//set account name to title row
        mTitleRow->updateAccountName(mEngine->accountName());

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

      	//Crete list for mail items
        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() ) );
	    
	    //Get date/time events from date observer
	    connect(mDateObserver, SIGNAL(dateTimeChanged())
	            , this, SLOT(updateMailData()));
	    setMinimumSize(mTitleRow->minimumWidth(), 
	            mEmptySpaceContainer->minimumHeight() + mTitleRow->minimumHeight());
    }
    QT_CATCH(...) {
        NM_ERROR(1,"NmHsWidget::onInitialize fail @ catch");
        emit error();
    }
}

/*!
 Uninitializes the widget.
 
 called by home screen fw when widget is removed from home screen
 */
void NmHsWidget::onUninitialize()
{
    NM_FUNCTION;
    HbStyleLoader::unregisterFilePath(":/layout/nmhswidgetlistviewitem.widgetml");
    HbStyleLoader::unregisterFilePath(":/layout/nmhswidgetlistviewitem.css");
}

/*!
 updateMailData slot
 */
void NmHsWidget::updateMailData()
{
    NM_FUNCTION;
    QT_TRY {
        QList<NmMessageEnvelope*> envelopes; 
        int count = 0;
        if (mIsExpanded) {
            count = mEngine->getEnvelopes(envelopes, KMaxNumberOfMailsShown);
        }
        mListModel->refresh( envelopes );
        updateLayout(count);
    }QT_CATCH(...) {
           NM_ERROR(1,"NmHsWidget::updateMailData fail @ catch");
           emit error();
    }
}

/*!
 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 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;
    
	//collapsed size
    qreal totalHeight = mEmptySpaceContainer->preferredHeight() + mTitleRow->containerHeight();
    
    if (mIsExpanded) {
        //when expanded, grow as big as possible
        totalHeight = KNmHsWidgetHSMaxWidgetHeightInUnits * HbDeviceProfile::current().unitValue();
        mContentContainer->setVisible(true);
        if (mailCount == 0) {
            addNoMailsLabelToLayout();
            removeEmailRowsFromLayout();
        }
        else {
            removeNoMailsLabelFromLayout();
            addEmailRowsToLayout();
        }
    }
    else {
        removeNoMailsLabelFromLayout();
        removeEmailRowsFromLayout();
        mContentContainer->setVisible(false);        
    }

    //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
    //TODO: check if this is still needed as list used
    resize(mTitleRow->maximumWidth(), totalHeight);
    mMainContainer->resize(mTitleRow->maximumWidth(), totalHeight);
    mWidgetContainer->resize(mTitleRow->maximumWidth(), totalHeight - mEmptySpaceContainer->preferredHeight());
}

/*!
 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() ) {
        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 list widget to content layout
 */
void NmHsWidget::addEmailRowsToLayout()
{
    NM_FUNCTION;
    
    mContentLayout->addItem(mListView);
    
    mListView->setVisible(true);
    
}

/*!
 removeEmailRowsFromLayout removes and hides list widget 
 from content layout
 */
void NmHsWidget::removeEmailRowsFromLayout()
{
    NM_FUNCTION;
    mContentLayout->removeItem(mListView);
    mListView->setVisible(false);
}

/*!
 openMessage slot
 */
void NmHsWidget::openMessage(const QModelIndex& index)
{
     QVariant var = mListModel->data(index,Qt::DisplayRole);
     if(!var.isNull()){
         NmMessageEnvelope *envelope = var.value<NmMessageEnvelope*>();
         mEngine->launchMailAppMailViewer(envelope->messageId());
     }

}

/*!
 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;
    }
}