diff -r dcf0eedfc1a3 -r d189ee25cf9d emailuis/nmhswidget/src/nmhswidget.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emailuis/nmhswidget/src/nmhswidget.cpp Tue Aug 31 15:04:17 2010 +0300 @@ -0,0 +1,596 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#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 (loader.findWidget(KNmHsWidgetMainContainer)); + mWidgetContainer = static_cast (loader.findWidget(KNmHsWidgetContainer)); + mContentContainer = static_cast (loader.findWidget(KNmHsWidgetContentContainer)); + mEmptySpaceContainer = static_cast (loader.findWidget(KNmHsWidgetEmptySpaceContainer)); + mNoMailsLabel = static_cast (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 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; + } +}