/*
* 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: Message editor header container class. Collects the header widgets.
*
*/
#include "nmuiheaders.h"
// Layout
// These match to the defintions in nmeditorview.docml
static const char *NMUI_EDITOR_CONTAINER = "scrollAreaContents";
static const char *NMUI_EDITOR_SUBJECT_FIELD = "editorSubjectField";
static const char *NMUI_EDITOR_SUBJECT_EDIT = "editorSubjectEdit";
static const char *NMUI_EDITOR_TO_FIELD = "editorToField";
static const char *NMUI_EDITOR_CC_FIELD = "editorCcField";
static const char *NMUI_EDITOR_BCC_FIELD = "editorBccField";
static const char *NMUI_EDITOR_PRIORITY_ICON = "editPriorityIcon";
static const char *NMUI_EDITOR_FOLLOWUP_ICON = "editFollowUpIcon";
static const char *NMUI_EDITOR_ATTACHMENT_LIST = "attachmentListWidget";
static const char *NMUI_EDITOR_PREFIX_TO = "editorTo";
static const char *NMUI_EDITOR_PREFIX_CC = "editorCc";
static const char *NMUI_EDITOR_PREFIX_BCC = "editorBcc";
static const int NmMaxRows = 10000;
// this timeout seems to be long enough for all cases. see sendDelayedHeaderHeightChanged
static const int NmLayoutSystemWaitTimer = 500; // 0.5 sec
/*!
Constructor
*/
NmEditorHeader::NmEditorHeader(
QObject *parent, NmApplication &application, HbDocumentLoader *documentLoader) :
QObject(parent),
mApplication(application),
mDocumentLoader(documentLoader),
mHeaderHeight(0),
mIconVisible(false),
mSubjectEdit(NULL),
mRecipientFieldsEmpty(true),
mAttachmentList(NULL),
mToField(NULL),
mCcField(NULL),
mBccField(NULL),
mCcBccFieldVisible(false)
{
NM_FUNCTION;
loadWidgets();
createConnections();
}
/*!
Destructor
*/
NmEditorHeader::~NmEditorHeader()
{
NM_FUNCTION;
}
/*!
Load widgets from XML for the header.
*/
void NmEditorHeader::loadWidgets()
{
NM_FUNCTION;
// Load widgets from docml and construct handlers. Those widgets that are not shown by default
// are hidden and removed from the layout at this phase.
HbWidget *contentWidget =
qobject_cast<HbWidget *>(mDocumentLoader->findWidget(NMUI_EDITOR_CONTAINER));
if (contentWidget) {
mLayout = static_cast<QGraphicsLinearLayout *>(contentWidget->layout());
// base class QObject takes the deleting responsibility
mToField = new NmRecipientField(this, *mDocumentLoader, NMUI_EDITOR_PREFIX_TO);
mCcField = new NmRecipientField(this, *mDocumentLoader, NMUI_EDITOR_PREFIX_CC);
mBccField = new NmRecipientField(this, *mDocumentLoader, NMUI_EDITOR_PREFIX_BCC);
// Sets up editor properties like no prediction, lower case preferred etc.
HbEditorInterface toEditorInterface(mToField->editor());
HbEditorInterface ccEditorInterface(mCcField->editor());
HbEditorInterface bccEditorInterface(mBccField->editor());
toEditorInterface.setUpAsLatinAlphabetOnlyEditor();
ccEditorInterface.setUpAsLatinAlphabetOnlyEditor();
bccEditorInterface.setUpAsLatinAlphabetOnlyEditor();
mToWidget = qobject_cast<HbWidget *>(mDocumentLoader->findWidget(NMUI_EDITOR_TO_FIELD));
// Cc field is not shown by default. It needs to be both hidden and removed from the layout.
mCcWidget = qobject_cast<HbWidget *>(mDocumentLoader->findWidget(NMUI_EDITOR_CC_FIELD));
mCcWidget->hide();
mLayout->removeItem(mCcWidget);
// Bcc field is not shown by default. It needs to be both hidden and removed from the layout.
mBccWidget = qobject_cast<HbWidget *>(mDocumentLoader->findWidget(NMUI_EDITOR_BCC_FIELD));
mBccWidget->hide();
mLayout->removeItem(mBccWidget);
mSubjectWidget =
qobject_cast<HbWidget *>(mDocumentLoader->findWidget(NMUI_EDITOR_SUBJECT_FIELD));
mSubjectLayout = static_cast<QGraphicsLinearLayout *>(mSubjectWidget->layout());
// Add Subject: field
mSubjectEdit = qobject_cast<NmHtmlLineEdit *>
(mDocumentLoader->findWidget(NMUI_EDITOR_SUBJECT_EDIT));
mSubjectEdit->setMaxRows(NmMaxRows);
// Add attachment list
mAttachmentListWidget = qobject_cast<NmAttachmentListWidget *>
(mDocumentLoader->findWidget(NMUI_EDITOR_ATTACHMENT_LIST));
// Create attachment list handling object
mAttachmentList = new NmAttachmentList(*mAttachmentListWidget);
mAttachmentList->setParent(this); // ownership changes
mAttachmentListWidget->hide();
mLayout->removeItem(&mAttachmentList->listWidget());
// Add priority icon
mPriorityIcon = qobject_cast<HbLabel *>
(mDocumentLoader->findWidget(NMUI_EDITOR_PRIORITY_ICON));
mPriorityIcon->hide();
mSubjectLayout->removeItem(mPriorityIcon);
// follow-up icon is not yet supported
HbLabel *followUpIcon = qobject_cast<HbLabel *>
(mDocumentLoader->findWidget(NMUI_EDITOR_FOLLOWUP_ICON));
followUpIcon->hide();
mSubjectLayout->removeItem(followUpIcon);
}
}
/*!
Create signal - slot connections.
*/
void NmEditorHeader::createConnections()
{
NM_FUNCTION;
// Signals for checking if the recipient fields have text.
connect(mToField, SIGNAL(textChanged(const QString &)),
this, SLOT(editorContentChanged()));
connect(mCcField, SIGNAL(textChanged(const QString &)),
this, SLOT(editorContentChanged()));
connect(mBccField, SIGNAL(textChanged(const QString &)),
this, SLOT(editorContentChanged()));
// Signals for handling the recipient field expanding
connect(mToField, SIGNAL(textChanged(const QString &)),
this, SLOT(sendDelayedHeaderHeightChanged()));
connect(mCcField, SIGNAL(textChanged(const QString &)),
this, SLOT(sendDelayedHeaderHeightChanged()));
connect(mBccField, SIGNAL(textChanged(const QString &)),
this, SLOT(sendDelayedHeaderHeightChanged()));
connect(mSubjectEdit, SIGNAL(contentsChanged()), this, SLOT(sendDelayedHeaderHeightChanged()));
// Signals for handling the attachment list
connect(&mAttachmentList->listWidget(), SIGNAL(itemActivated(int)),
this, SLOT(attachmentActivated(int)));
connect(&mAttachmentList->listWidget(), SIGNAL(longPressed(int, QPointF)),
this, SLOT(attachmentLongPressed(int, QPointF)));
}
/*!
Show or hide recipient field
*/
void NmEditorHeader::setFieldVisibility(bool isVisible)
{
if ( mCcBccFieldVisible != isVisible ) {
mCcBccFieldVisible = isVisible;
if (mCcBccFieldVisible) {
mLayout->insertItem(1, mBccWidget);
mLayout->insertItem(1, mCcWidget);
mCcWidget->show();
mBccWidget->show();
}
else {
mCcWidget->hide();
mBccWidget->hide();
mLayout->removeItem(mCcWidget);
mLayout->removeItem(mBccWidget);
}
sendDelayedHeaderHeightChanged();
}
}
/*!
Return the sum of the header widget heights. This contains all the spacings a well.
*/
qreal NmEditorHeader::headerHeight() const
{
NM_FUNCTION;
// get the layout's vertical spacing
qreal spacing = 0;
HbInstance::instance()->style()->parameter("hb-param-margin-gene-middle-vertical", spacing);
// calculate the height
qreal height = 0;
height += mToField->height(); // returns widget's geometry height
height += spacing;
if (mCcBccFieldVisible) {
height += mCcField->height(); // returns widget's geometry height
height += spacing;
height += mBccField->height(); // returns widget's geometry height
height += spacing;
}
height += mSubjectWidget->geometry().height();
height += spacing;
if (mAttachmentList->listWidget().isVisible()) {
height += mAttachmentList->listWidget().geometry().height();
height += spacing;
}
return height;
}
/*!
This is called when the contents of some of the header widgets have been changed. When the
contents change the widget's actual size may also change. The header area height is needed to
calculate the size hints of the body and the scroll area widgets. We need to use a timer to let
the Orbit FW adjust the heights eg. if the subject and recipient fields are expanded by the FW.
It would be best to find a solution which doesn't depend on the header area's actual height size
information.
*/
void NmEditorHeader::sendDelayedHeaderHeightChanged()
{
NM_FUNCTION;
QTimer::singleShot(NmLayoutSystemWaitTimer, this, SLOT(sendHeaderHeightChanged()));
}
/*!
Send a signal that the header area height has been changed if necessary. This is needed for the
body and scroll area widgets. See NmEditorTextEdit::setHeaderHeight for more info.
*/
void NmEditorHeader::sendHeaderHeightChanged()
{
qreal hHeight = headerHeight();
if (mHeaderHeight != hHeight) {
mHeaderHeight = hHeight;
emit headerHeightChanged(mHeaderHeight);
}
}
/*!
Because header filds have fixed size policy. This function must be called to set
new width for every header field when orintation has been changed.
*/
void NmEditorHeader::adjustHeaderWidth()
{
NM_FUNCTION;
int newWidth = mApplication.screenSize().width();
mToWidget->setPreferredWidth(newWidth);
mCcWidget->setPreferredWidth(newWidth);
mBccWidget->setPreferredWidth(newWidth);
mSubjectWidget->setPreferredWidth(newWidth);
mAttachmentListWidget->setPreferredWidth(newWidth);
mSubjectWidget->setPreferredWidth(newWidth);
}
/*!
Return pointer to to edit
*/
NmRecipientLineEdit* NmEditorHeader::toEdit() const
{
NM_FUNCTION;
return mToField->editor();
}
/*!
Return pointer to cc edit
*/
NmRecipientLineEdit* NmEditorHeader::ccEdit() const
{
NM_FUNCTION;
return mCcField->editor();
}
/*!
Return pointer to bcc edit
*/
NmRecipientLineEdit* NmEditorHeader::bccEdit() const
{
NM_FUNCTION;
return mBccField->editor();
}
/*!
Return pointer to subject field
*/
NmHtmlLineEdit* NmEditorHeader::subjectEdit() const
{
NM_FUNCTION;
return mSubjectEdit;
}
/*!
Checks if recipient editors are empty and emits a signal if
the state is changed.
*/
void NmEditorHeader::editorContentChanged()
{
NM_FUNCTION;
bool recipientsFieldsEmpty(true);
if (mToField->text().length()) {
recipientsFieldsEmpty = false;
}
else if (mCcField->text().length()) {
recipientsFieldsEmpty = false;
}
else if (mBccField->text().length()) {
recipientsFieldsEmpty = false;
}
if (mRecipientFieldsEmpty != recipientsFieldsEmpty) {
mRecipientFieldsEmpty = recipientsFieldsEmpty;
emit recipientFieldsHaveContent(!mRecipientFieldsEmpty);
}
}
/*!
Sets the icon for priority
*/
void NmEditorHeader::setPriority(NmMessagePriority priority)
{
NM_FUNCTION;
switch (priority) {
case NmMessagePriorityHigh:
setPriority(NmActionResponseCommandPriorityHigh);
break;
case NmMessagePriorityLow:
setPriority(NmActionResponseCommandPriorityLow);
break;
default:
setPriority(NmActionResponseCommandNone);
break;
}
}
/*!
Sets the icon for priority
*/
void NmEditorHeader::setPriority(NmActionResponseCommand prio)
{
NM_FUNCTION;
switch(prio) {
case NmActionResponseCommandPriorityHigh:
if (!mIconVisible) {
mIconVisible = true;
// icon widget is just after the subject line edit (see docml)
mSubjectLayout->insertItem(2, mPriorityIcon);
mPriorityIcon->show();
}
mPriorityIcon->setIcon(
NmIcons::getIcon(NmIcons::NmIconPriorityHigh));
break;
case NmActionResponseCommandPriorityLow:
if (!mIconVisible) {
mIconVisible = true;
// icon widget is just after the subject line edit (see docml)
mSubjectLayout->insertItem(2, mPriorityIcon);
mPriorityIcon->show();
}
mPriorityIcon->setIcon(
NmIcons::getIcon(NmIcons::NmIconPriorityLow));
break;
default:
if (mIconVisible) {
mIconVisible = false;
HbIcon emptyIcon;
mPriorityIcon->setIcon(emptyIcon);
mSubjectLayout->removeItem(mPriorityIcon);
mPriorityIcon->hide();
}
break;
}
sendDelayedHeaderHeightChanged();
}
/*!
Adds an attachment to attachment list for mail.
*/
void NmEditorHeader::addAttachment(
const QString &fileName, const QString &fileSize, const NmId &nmid)
{
NM_FUNCTION;
mAttachmentList->insertAttachment(fileName, fileSize, nmid);
if (!mAttachmentList->listWidget().isVisible()) {
// attachment list is inserted just before the body widget (see docml).
mLayout->insertItem(mLayout->count() - 1, &mAttachmentList->listWidget());
mAttachmentList->listWidget().show();
}
sendHeaderHeightChanged();
}
/*!
Remove attachment from the list. This function is used when
attachment adding has failed and attachment id is not known.
*/
void NmEditorHeader::removeAttachment(const QString &fileName)
{
NM_FUNCTION;
mAttachmentList->removeAttachment(fileName);
if (mAttachmentList->count() == 0) {
mAttachmentList->listWidget().hide();
mLayout->removeItem(&mAttachmentList->listWidget());
}
sendDelayedHeaderHeightChanged();
}
/*!
Remove attachment from the list. This function is used when
attachment has been selected for remove.
*/
void NmEditorHeader::removeAttachment(const NmId &nmid)
{
NM_FUNCTION;
mAttachmentList->removeAttachment(nmid);
if (mAttachmentList->count() == 0) {
mAttachmentList->listWidget().hide();
mLayout->removeItem(&mAttachmentList->listWidget());
}
sendDelayedHeaderHeightChanged();
}
/*!
This function set messagePartId and fileSize for attachment.
*/
void NmEditorHeader::setAttachmentParameters(
const QString &fileName,
const NmId &msgPartId,
const QString &fileSize,
int result)
{
NM_FUNCTION;
if (result == NmNoError) {
// Attachment adding succesful, set message part id and size for attachment
mAttachmentList->setAttachmentPartId(fileName, msgPartId);
mAttachmentList->setAttachmentSize(msgPartId, fileSize);
}
}
/*!
Slot attachment activated from attachment list by short tap.
*/
void NmEditorHeader::attachmentActivated(int arrayIndex)
{
NM_FUNCTION;
emit attachmentShortPressed(mAttachmentList->nmIdByIndex(arrayIndex));
}
/*!
Slot attachment selected from attachment list by longtap.
*/
void NmEditorHeader::attachmentLongPressed(int arrayIndex, QPointF point)
{
NM_FUNCTION;
// Remove selected attachment
emit attachmentLongPressed(mAttachmentList->nmIdByIndex(arrayIndex), point);
}
/*!
This function is called when scroll position has been changed.
Function performs the pre calculated translation to set new positions for header fields
so that header stays visible when body is scrolled horizontally.
*/
void NmEditorHeader::repositHeader(const QTransform &transform)
{
NM_FUNCTION;
mToWidget->setTransform(transform);
mCcWidget->setTransform(transform);
mBccWidget->setTransform(transform);
mSubjectWidget->setTransform(transform);
mAttachmentListWidget->setTransform(transform);
}