--- a/messagingapp/msgui/unifiededitor/src/msgunieditoraddress.cpp Mon May 03 12:29:07 2010 +0300
+++ b/messagingapp/msgui/unifiededitor/src/msgunieditoraddress.cpp Fri Jun 25 15:47:40 2010 +0530
@@ -16,40 +16,55 @@
*/
// INCLUDES
-#include "debugtraces.h"
+#include <QTimer>
#include <HbTextItem>
#include <HbPushButton>
#include <HbAction>
-#include <hbinputeditorinterface.h>
+#include <hbmessagebox.h>
#include <cntservicescontact.h>
#include <xqaiwrequest.h>
#include <xqappmgr.h>
#include <telconfigcrkeys.h> // KCRUidTelephonyConfiguration
#include <centralrepository.h>
+#include <HbNotificationDialog>
+#include <commonphoneparser.h> // Common phone number validity checker
+#include <xqconversions.h>
// USER INCLUDES
+#include "debugtraces.h"
#include "msgunieditoraddress.h"
-#include "msgunifiededitorlineedit.h"
+#include "msgunieditorlineedit.h"
+#include "msgunieditormonitor.h"
+#include "UniEditorGenUtils.h"
const QString PBK_ICON("qtg_mono_contacts");
-const QString SEND_ICON("qtg_mono_send");
+const QString REPLACEMENT_STR("; ");
+const QString COMMA_SEPERATOR(",");
// Constants
const int KDefaultGsmNumberMatchLength = 7; //matching unique ph numbers
+#define LOC_SMS_RECIPIENT_LIMIT_REACHED hbTrId("txt_messaging_dialog_number_of_recipients_exceeded")
+#define LOC_MMS_RECIPIENT_LIMIT_REACHED hbTrId("txt_messaging_dpopinfo_unable_to_add_more_recipien")
+#define LOC_DIALOG_OK hbTrId("txt_common_button_ok")
+#define LOC_BUTTON_CANCEL hbTrId("txt_common_button_cancel")
+#define LOC_INVALID_RECIPIENT hbTrId("txt_messaging_dialog_invalid_recipient_found")
+#define LOC_INVALID_RECIPIENT_NOT_ADDED hbTrId("txt_messaging_dialog_invalid_recipient_not_added")
+#define LOC_INVALID_RECIPIENTS_NOT_ADDED hbTrId("txt_messaging_dialog_invalid_recipients_not_added")
+
+
+
+
MsgUnifiedEditorAddress::MsgUnifiedEditorAddress( const QString& label,
- const QString& pluginPath,
QGraphicsItem *parent ) :
-HbWidget(parent),
-mPluginPath(pluginPath)
+MsgUnifiedEditorBaseWidget(parent),
+mSkipMaxRecipientQuery(false),
+mAboutToExceedMaxSmsRecipients(false),
+mAboutToExceedMaxMmsRecipients(false),
+mExceedsMaxMmsRecipientsBy(0)
{
- #ifdef _DEBUG_TRACES_
- qDebug() << "MsgUnifiedEditorAddress calling HbStyle::registerPlugin";
- #endif
+ this->setContentsMargins(0,0,0,0);
- this->setContentsMargins(0,0,0,0);
- setPluginBaseId(style()->registerPlugin(mPluginPath));
-
mLaunchBtn = new HbPushButton(this);
HbStyle::setItemName(mLaunchBtn,"launchBtn");
connect(mLaunchBtn,SIGNAL(clicked()),this,SLOT(fetchContacts()));
@@ -61,24 +76,22 @@
mAddressEdit->setMaxRows(40);
connect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
- this, SLOT(onContentsAdded(const QString&)));
+ this, SLOT(onContentsChanged(const QString&)));
- // add "Send" action in VKB
- HbEditorInterface editorInterface(mAddressEdit);
mAddressEdit->setInputMethodHints(Qt::ImhPreferNumbers);
- HbAction *sendAction = new HbAction(HbIcon(SEND_ICON), QString(),this);
- connect(sendAction, SIGNAL(triggered()),this, SIGNAL(sendMessage()));
- editorInterface.addAction(sendAction);
-
- }
+}
MsgUnifiedEditorAddress::~MsgUnifiedEditorAddress()
{
- style()->unregisterPlugin(mPluginPath);
+ //TODO: Should remove this code depending on orbit's reply whether it is needed
+ //to unregister the same plugin registered on two different widgets twice.
+ //style()->unregisterPlugin(mPluginPath);
}
void MsgUnifiedEditorAddress::fetchContacts()
{
+ mLaunchBtn->blockSignals(true);
+
QList<QVariant> args;
QString serviceName("com.nokia.services.phonebookservices");
QString operation("fetch(QString,QString,QString)");
@@ -87,39 +100,48 @@
request = appManager.create(serviceName, "Fetch", operation, true); // embedded
if ( request == NULL )
{
- return;
+ return;
}
// Result handlers
connect (request, SIGNAL(requestOk(const QVariant&)), this, SLOT(handleOk(const QVariant&)));
connect (request, SIGNAL(requestError(int,const QString&)), this, SLOT(handleError(int,const QString&)));
-
- args << QString(tr("Phonebook"));
+
+ args << QString(tr("Phonebook"));
args << KCntActionAll;
args << KCntFilterDisplayAll;
-
+
request->setArguments(args);
request->send();
delete request;
+
+ //unblock click signal after some delay.
+ QTimer::singleShot(250,this,SLOT(unblockSignals()));
}
void MsgUnifiedEditorAddress::handleOk(const QVariant& value)
{
- CntServicesContactList contactList;
- contactList = qVariantValue<CntServicesContactList>(value);
+ CntServicesContactList contactList =
+ qVariantValue<CntServicesContactList>(value);
+ int count = contactList.count();
- for(int i = 0; i < contactList.count(); i++ )
+ ConvergedMessageAddressList addrlist;
+ for(int i = 0; i < count; i++ )
{
- mAddressMap.insert(contactList[i].mPhoneNumber, contactList[i].mDisplayName);
- if(!contactList[i].mDisplayName.isEmpty())
+ ConvergedMessageAddress* address =
+ new ConvergedMessageAddress();
+ if(!contactList[i].mPhoneNumber.isEmpty())
{
- mAddressEdit->setText(contactList[i].mDisplayName);
+ address->setAddress(contactList[i].mPhoneNumber);
}
else
{
- mAddressEdit->setText(contactList[i].mPhoneNumber);
+ address->setAddress(contactList[i].mEmailAddress);
}
+ address->setAlias(contactList[i].mDisplayName);
+ addrlist << address;
}
+ setAddresses(addrlist);
}
void MsgUnifiedEditorAddress::handleError(int errorCode, const QString& errorMessage)
@@ -128,31 +150,47 @@
Q_UNUSED(errorCode)
}
-ConvergedMessageAddressList MsgUnifiedEditorAddress::addresses()
+// ----------------------------------------------------------------------------
+// MsgUnifiedEditorAddress::addresses
+// @see header
+// ----------------------------------------------------------------------------
+ConvergedMessageAddressList MsgUnifiedEditorAddress::addresses(
+ bool removeDuplicates)
{
- #ifdef _DEBUG_TRACES_
- qCritical() << "MsgUnifiedEditorAddress::address start";
+#ifdef _DEBUG_TRACES_
+ qCritical() << "MsgUnifiedEditorAddress::addresses start";
#endif
// sync-up map to account for user-actions on edit-field
syncDeletionsToMap();
syncAdditionsToMap();
- QStringList uniqueAddr;
- uniqueAddr = uniqueAddressList();
-
ConvergedMessageAddressList addresses;
- foreach(QString addr, uniqueAddr)
+ if(removeDuplicates)
{
- ConvergedMessageAddress* address = new ConvergedMessageAddress;
- address->setAddress(addr);
- if(!mAddressMap.value(addr).isEmpty())
+ QStringList uniqueAddr;
+ uniqueAddr = uniqueAddressList();
+ foreach(QString addr, uniqueAddr)
{
+ ConvergedMessageAddress* address = new ConvergedMessageAddress;
+ address->setAddress(addr);
address->setAlias(mAddressMap.value(addr));
- }
- addresses.append(address);
+ addresses.append(address);
+ }
}
- #ifdef _DEBUG_TRACES_
- qCritical() << "MsgUnifiedEditorAddress::address end";
+ else
+ {
+ QMap<QString, QString>::iterator i = mAddressMap.begin();
+ while (i != mAddressMap.end())
+ {
+ ConvergedMessageAddress* address = new ConvergedMessageAddress;
+ address->setAddress(i.key());
+ address->setAlias(i.value());
+ addresses.append(address);
+ i++;
+ }
+ }
+#ifdef _DEBUG_TRACES_
+ qCritical() << "MsgUnifiedEditorAddress::addresses end";
#endif
return addresses;
}
@@ -164,60 +202,177 @@
void MsgUnifiedEditorAddress::setAddresses(ConvergedMessageAddressList addrlist)
{
- int count = addrlist.count();
- for(int i = 0; i < count; i++ )
+ // avoid processing if no info available
+ if(addrlist.count() == 0)
{
- mAddressMap.insert(addrlist[i]->address(), addrlist[i]->alias());
- if(!addrlist[i]->alias().isEmpty())
+ return;
+ }
+
+ // ensure flags are reset before starting the addr addition
+ mAboutToExceedMaxSmsRecipients = false;
+ mAboutToExceedMaxMmsRecipients = false;
+ mExceedsMaxMmsRecipientsBy = 0;
+
+ // first, we check if MMS max-recipient count will exceed
+ int count = addrlist.count();
+ int futureCount = count + MsgUnifiedEditorMonitor::msgAddressCount();
+ if(futureCount > MsgUnifiedEditorMonitor::maxMmsRecipients())
+ {
+ mAboutToExceedMaxMmsRecipients = true;
+ mExceedsMaxMmsRecipientsBy =
+ futureCount - MsgUnifiedEditorMonitor::maxMmsRecipients();
+ }
+ // else, check if SMS max-recipient count will exceed
+ else if(!mSkipMaxRecipientQuery)
+ {
+ futureCount = count + addressCount();
+ if( (addressCount() <= MsgUnifiedEditorMonitor::maxSmsRecipients()) &&
+ (futureCount > MsgUnifiedEditorMonitor::maxSmsRecipients()) )
+ {
+ mAboutToExceedMaxSmsRecipients = true;
+ }
+ }
+
+ int invalidCount= 0;
+ QString invalidContacts;
+ for(int i = 0; i < count; i++ )
{
- mAddressEdit->setText(addrlist[i]->alias());
- }
- else
+ bool isValid = false;
+ isValid = checkValidAddress(addrlist.at(i)->address());
+ if(!isValid)
+ {
+ invalidCount ++;
+ // append the comma till last but one contact.
+ // add the invalid ocntacts to the " , " seperated string.
+ if(invalidCount > 1)
+ {
+ invalidContacts.append(COMMA_SEPERATOR);
+ }
+ invalidContacts.append(addrlist.at(i)->alias());
+ }
+ else
+ {
+ mAddressMap.insertMulti(addrlist[i]->address(), addrlist[i]->alias());
+ if(!addrlist[i]->alias().isEmpty())
+ {
+ mAddressEdit->setText(addrlist[i]->alias());
+ }
+ else
+ {
+ mAddressEdit->setText(addrlist[i]->address(), false);
+ }
+ }
+ }
+ if(invalidCount)
{
- mAddressEdit->setText(addrlist[i]->address());
+ QString invalidStr;
+ (invalidCount == 1)?(invalidStr = QString(LOC_INVALID_RECIPIENT_NOT_ADDED)) :(invalidStr = QString(LOC_INVALID_RECIPIENTS_NOT_ADDED));
+ // append line seperator
+ invalidStr.append("<br>");
+ invalidStr.append(invalidContacts);
+ HbMessageBox::information(invalidStr);
}
- }
+
+ // addition operation complete, reset flags
+ mAboutToExceedMaxSmsRecipients = false;
+ mAboutToExceedMaxMmsRecipients = false;
+ mExceedsMaxMmsRecipientsBy = 0;
}
int MsgUnifiedEditorAddress::contactMatchDigits()
- {
+{
// Read the amount of digits to be used in contact matching
- // The key is owned by PhoneApp
- CRepository* repository = CRepository::NewLC(KCRUidTelConfiguration);
+ // The key is owned by PhoneApp
int matchDigitCount = 0;
- if ( repository->Get(KTelMatchDigits, matchDigitCount) == KErrNone )
+ TRAP_IGNORE(
+ CRepository* repository = CRepository::NewLC(KCRUidTelConfiguration);
+ if ( repository->Get(KTelMatchDigits, matchDigitCount) == KErrNone )
{
- // Min is 7
- matchDigitCount = Max(matchDigitCount, KDefaultGsmNumberMatchLength);
+ // Min is 7
+ matchDigitCount = Max(matchDigitCount, KDefaultGsmNumberMatchLength);
}
- CleanupStack::PopAndDestroy(); // repository
-
+ CleanupStack::PopAndDestroy(); // repository
+ );
return matchDigitCount;
+}
- }
-
-void MsgUnifiedEditorAddress::onContentsAdded(const QString& text)
+void MsgUnifiedEditorAddress::onContentsChanged(const QString& text)
{
- if(!text.isEmpty())
+ // Max MMS recipient count check
+ if( mAboutToExceedMaxMmsRecipients ||
+ (MsgUnifiedEditorMonitor::msgAddressCount() >= MsgUnifiedEditorMonitor::maxMmsRecipients()) )
{
+ if(mAboutToExceedMaxMmsRecipients)
+ {// show discreet note only once
+ --mExceedsMaxMmsRecipientsBy;
+ if(!mExceedsMaxMmsRecipientsBy)
+ {
+ HbNotificationDialog::launchDialog(
+ LOC_MMS_RECIPIENT_LIMIT_REACHED);
+ }
+ resetToPrevious();
+ }
+ else
+ {
+ // update monitor data
+ emit contentChanged();
+ if(MsgUnifiedEditorMonitor::msgAddressCount() > MsgUnifiedEditorMonitor::maxMmsRecipients())
+ {
+ HbNotificationDialog::launchDialog(
+ LOC_MMS_RECIPIENT_LIMIT_REACHED);
+ resetToPrevious();
+ // reset monitor data
+ emit contentChanged();
+ }
+ else
+ {
+ mPrevBuffer = text;
+ }
+ }
+ return;
+ }
+
+ // Max SMS recipient count check
+ if( !mSkipMaxRecipientQuery &&
+ (MsgUnifiedEditorMonitor::messageType() == ConvergedMessage::Sms) &&
+ (mAddressEdit->addresses().count() > MsgUnifiedEditorMonitor::maxSmsRecipients()) )
+ {
+ // when we show this dialog, we don't want the intermediate states
+ // to be signalled to us
disconnect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
- this, SLOT(onContentsAdded(const QString&)));
+ this, SLOT(onContentsChanged(const QString&)));
+ QTimer::singleShot(50, this, SLOT(handleRecipientLimitReached()));
+ }
+ else
+ {
+ if(!mAboutToExceedMaxSmsRecipients)
+ {// remember addresses before the block insertion started
+ mPrevBuffer = text;
+ }
emit contentChanged();
- connect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
- this, SLOT(onContentsRemoved(const QString&)));
}
}
-void MsgUnifiedEditorAddress::onContentsRemoved(const QString& text)
+void MsgUnifiedEditorAddress::handleRecipientLimitReached()
{
- if(text.isEmpty())
- {
- disconnect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
- this, SLOT(onContentsRemoved(const QString&)));
- emit contentChanged();
- connect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
- this, SLOT(onContentsAdded(const QString&)));
- }
+ HbMessageBox* dlg = new HbMessageBox(HbMessageBox::MessageTypeQuestion);
+ dlg->setAttribute(Qt::WA_DeleteOnClose);
+ dlg->setFocusPolicy(Qt::NoFocus);
+ dlg->setTimeout(HbPopup::NoTimeout);
+
+ dlg->setText(LOC_SMS_RECIPIENT_LIMIT_REACHED);
+
+ dlg->clearActions();
+ HbAction* okAction = new HbAction(LOC_DIALOG_OK,dlg);
+ dlg->addAction(okAction);
+
+ HbAction* cancelAction = new HbAction(LOC_BUTTON_CANCEL,dlg);
+ dlg->addAction(cancelAction);
+
+ dlg->open(this,SLOT(onMaxRecipientsReached(HbAction*)));
+ // reconnect to get back updates
+ connect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
+ this, SLOT(onContentsChanged(const QString&)));
}
void MsgUnifiedEditorAddress::syncDeletionsToMap()
@@ -236,6 +391,18 @@
}
else
{
+ // ensure that the matched contact is removed from the
+ // address's list
+ int matchedIndex = addrList.indexOf(i.value());
+ if(matchedIndex == -1)
+ {
+ matchedIndex = addrList.indexOf(i.key());
+ }
+ if(matchedIndex != -1)
+ {
+ addrList.removeAt(matchedIndex);
+ }
+ // now go to next index in map
++i;
}
}
@@ -243,19 +410,19 @@
void MsgUnifiedEditorAddress::syncAdditionsToMap()
{
- QStringList mapAddrList = mAddressMap.values();
-
// remove already mapped addresses from edit-field
QStringList userInputAddrList(mAddressEdit->addresses());
+ QStringList mapAddrList = mAddressMap.values();
+ mapAddrList << mAddressMap.keys();
foreach(QString addr, mapAddrList)
{
- userInputAddrList.removeAll(addr);
+ userInputAddrList.removeOne(addr);
}
// add the unmapped addresses to address-map
foreach(QString addr, userInputAddrList)
{
- mAddressMap.insertMulti(addr, addr);
+ mAddressMap.insertMulti(addr, QString());
}
}
@@ -267,7 +434,7 @@
{
for(int i =j+1;i<mapAddrList.count();i++)
{
- if(0 == mapAddrList[j].right(matchDigitCount).compare(mapAddrList[i].right(matchDigitCount)))
+ if(0 == mapAddrList[j].right(matchDigitCount).compare(mapAddrList[i].right(matchDigitCount)))
{
mapAddrList.removeAt(i);
i--;
@@ -276,6 +443,148 @@
}
return mapAddrList;
}
+
+// ----------------------------------------------------------------------------
+// MsgUnifiedEditorAddress::skipMaxRecipientQuery
+// @see header
+// ----------------------------------------------------------------------------
+void MsgUnifiedEditorAddress::skipMaxRecipientQuery(bool skip)
+{
+ mSkipMaxRecipientQuery = skip;
+}
+
+void MsgUnifiedEditorAddress::setFocus()
+{
+ mAddressEdit->setFocus(Qt::MouseFocusReason);
+}
+
+// ----------------------------------------------------------------------------
+// MsgUnifiedEditorAddress::resetToPrevious
+// @see header
+// ----------------------------------------------------------------------------
+void MsgUnifiedEditorAddress::resetToPrevious()
+{
+ // when we do this reset operation, we don't want the intermediate states
+ // to be signalled to us
+ disconnect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
+ this, SLOT(onContentsChanged(const QString&)));
+
+ mAddressEdit->clearContent();
+ QStringList list = mPrevBuffer.split(REPLACEMENT_STR,
+ QString::SkipEmptyParts);
+ int count = list.count();
+ QStringList valList = mAddressMap.values();
+ for(int i=0; i<count; i++)
+ {
+ QString addr = list.at(i);
+ if(valList.contains(addr))
+ {
+ mAddressEdit->setText(addr);
+ }
+ else
+ {
+ mAddressEdit->setText(addr, false);
+ }
+ }
+ syncDeletionsToMap();
+ connect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
+ this, SLOT(onContentsChanged(const QString&)));
+}
+
+// ----------------------------------------------------------------------------
+// MsgUnifiedEditorAddress::onMaxRecipientsReached
+// @see header
+// ----------------------------------------------------------------------------
+void MsgUnifiedEditorAddress::onMaxRecipientsReached(HbAction* action)
+{
+ HbMessageBox *dlg = qobject_cast<HbMessageBox*> (sender());
+ if (action == dlg->actions().at(0)) {
+ // accept new content, update prev-buffer
+ emit contentChanged();
+ mPrevBuffer = mAddressEdit->content();
+ }
+ else {
+ // reject the new content, keep the old
+ resetToPrevious();
+ }
+}
+
+// ----------------------------------------------------------------------------
+// MsgUnifiedEditorAddress::validateContacts
+// @see header
+// ----------------------------------------------------------------------------
+bool MsgUnifiedEditorAddress::validateContacts()
+{
+ UniEditorGenUtils* genUtils = new UniEditorGenUtils;
+
+ // sync-up map to account for user-actions on address-field
+ syncDeletionsToMap();
+ syncAdditionsToMap();
+
+ // get the list of contacts in address-field
+ QStringList fieldAddresses(mAddressEdit->addresses());
+
+ bool isValid = true;
+ foreach(QString addr, fieldAddresses)
+ {
+ // run address validation only if address is unmapped
+ // (i.e. user-inserted)
+ if(mAddressMap.contains(addr))
+ {
+ isValid = checkValidAddress(addr);
+ if(!isValid)
+ {
+ mAddressEdit->highlightInvalidString(addr);
+ QString invalidAddrStr =
+ QString(LOC_INVALID_RECIPIENT).arg(addr);
+ HbMessageBox* dlg = new HbMessageBox(invalidAddrStr,
+ HbMessageBox::MessageTypeInformation);
+ dlg->setDismissPolicy(HbPopup::TapInside);
+ dlg->setTimeout(HbPopup::NoTimeout);
+ dlg->setAttribute(Qt::WA_DeleteOnClose, true);
+ dlg->open(this, SLOT(handleInvalidContactDialog(HbAction*)));
+ break;
+ }
+ }
+ }
+
+ return isValid;
+}
+// ----------------------------------------------------------------------------
+// MsgUnifiedEditorAddress::checkValidAddress
+// @see header
+// ----------------------------------------------------------------------------
+bool MsgUnifiedEditorAddress::checkValidAddress(const QString& addr)
+ {
+ bool isValid = false;
+ // 1. perform number validation
+ isValid = CommonPhoneParser::IsValidPhoneNumber(
+ *XQConversions::qStringToS60Desc(addr),
+ CommonPhoneParser::ESMSNumber );
+
+ // 2. if number validity fails, then perform email addr validation
+ UniEditorGenUtils* genUtils = new UniEditorGenUtils;
+ if(!isValid)
+ { // additional check for MMS only
+ isValid = genUtils->IsValidEmailAddress(
+ *XQConversions::qStringToS60Desc(addr) );
+ }
+ delete genUtils;
+ return isValid;
+ }
+
+void MsgUnifiedEditorAddress::handleInvalidContactDialog(
+ HbAction* act)
+{
+ Q_UNUSED(act);
+ QTimer::singleShot(250, this, SLOT(setFocus()));
+}
+
+void MsgUnifiedEditorAddress::unblockSignals()
+{
+ mLaunchBtn->blockSignals(false);
+}
+
Q_IMPLEMENT_USER_METATYPE(CntServicesContact)
Q_IMPLEMENT_USER_METATYPE_NO_OPERATORS(CntServicesContactList)