diff -r 84d9eb65b26f -r e4592d119491 messagingapp/msgui/unifiededitor/src/msgunieditoraddress.cpp --- a/messagingapp/msgui/unifiededitor/src/msgunieditoraddress.cpp Mon May 03 12:29:07 2010 +0300 +++ b/messagingapp/msgui/unifiededitor/src/msgunieditoraddress.cpp Fri May 14 15:49:35 2010 +0300 @@ -16,40 +16,50 @@ */ // INCLUDES -#include "debugtraces.h" +#include #include #include #include #include +#include #include #include #include #include // KCRUidTelephonyConfiguration #include +#include +#include // Common phone number validity checker +#include // USER INCLUDES +#include "debugtraces.h" #include "msgunieditoraddress.h" #include "msgunifiededitorlineedit.h" +#include "msgmonitor.h" +#include "unieditorgenutils.h" const QString PBK_ICON("qtg_mono_contacts"); const QString SEND_ICON("qtg_mono_send"); +const QString replacementStr("; "); // 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") 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,7 +71,7 @@ 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); @@ -69,12 +79,13 @@ 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() @@ -87,17 +98,17 @@ 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; @@ -105,21 +116,20 @@ void MsgUnifiedEditorAddress::handleOk(const QVariant& value) { - CntServicesContactList contactList; - contactList = qVariantValue(value); + CntServicesContactList contactList = + qVariantValue(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()) - { - mAddressEdit->setText(contactList[i].mDisplayName); - } - else - { - mAddressEdit->setText(contactList[i].mPhoneNumber); - } + ConvergedMessageAddress* address = + new ConvergedMessageAddress(); + address->setAddress(contactList[i].mPhoneNumber); + address->setAlias(contactList[i].mDisplayName); + addrlist << address; } + setAddresses(addrlist); } void MsgUnifiedEditorAddress::handleError(int errorCode, const QString& errorMessage) @@ -128,31 +138,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::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 +190,145 @@ void MsgUnifiedEditorAddress::setAddresses(ConvergedMessageAddressList addrlist) { - int count = addrlist.count(); + // 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 + MsgMonitor::msgAddressCount(); + if(futureCount > MsgMonitor::maxMmsRecipients()) + { + mAboutToExceedMaxMmsRecipients = true; + mExceedsMaxMmsRecipientsBy = + futureCount - MsgMonitor::maxMmsRecipients(); + } + // else, check if SMS max-recipient count will exceed + else if(!mSkipMaxRecipientQuery) + { + futureCount = count + addressCount(); + if( (addressCount() <= MsgMonitor::maxSmsRecipients()) && + (futureCount > MsgMonitor::maxSmsRecipients()) ) + { + mAboutToExceedMaxSmsRecipients = true; + } + } + + for(int i = 0; i < count; i++ ) { - mAddressMap.insert(addrlist[i]->address(), addrlist[i]->alias()); + mAddressMap.insertMulti(addrlist[i]->address(), addrlist[i]->alias()); if(!addrlist[i]->alias().isEmpty()) { mAddressEdit->setText(addrlist[i]->alias()); } else { - mAddressEdit->setText(addrlist[i]->address()); + mAddressEdit->setText(addrlist[i]->address(), false); } } + + // 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 || + (MsgMonitor::msgAddressCount() >= MsgMonitor::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(MsgMonitor::msgAddressCount() > MsgMonitor::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 && + (MsgMonitor::messageType() == ConvergedMessage::Sms) && + (mAddressEdit->addresses().count() > MsgMonitor::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); + + 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&))); + emit contentChanged(); } void MsgUnifiedEditorAddress::syncDeletionsToMap() @@ -243,19 +354,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 +378,7 @@ { for(int i =j+1;isetFocus(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(replacementStr, + QString::SkipEmptyParts); + int count = list.count(); + QStringList valList = mAddressMap.values(); + for(int i=0; isetText(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 (sender()); + if (action == dlg->actions().at(0)) { + // accept new content, update prev-buffer + 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 allValid = true; + foreach(QString addr, fieldAddresses) + { + // run address validation only if address is unmapped + // (i.e. user-inserted) + if(mAddressMap.contains(addr)) + { + // 1. perform number validation + allValid = CommonPhoneParser::IsValidPhoneNumber( + *XQConversions::qStringToS60Desc(addr), + CommonPhoneParser::ESMSNumber ); + + // 2. if number validity fails, then perform email addr validation + if( !allValid && + (MsgMonitor::messageType() == ConvergedMessage::Mms) ) + { // additional check for MMS only + allValid = genUtils->IsValidEmailAddress( + *XQConversions::qStringToS60Desc(addr) ); + } + + if(!allValid) + { + 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; + } + } + } + delete genUtils; + return allValid; +} + +void MsgUnifiedEditorAddress::handleInvalidContactDialog( + HbAction* act) +{ + Q_UNUSED(act); + QTimer::singleShot(250, this, SLOT(setFocus())); +} + Q_IMPLEMENT_USER_METATYPE(CntServicesContact) Q_IMPLEMENT_USER_METATYPE_NO_OPERATORS(CntServicesContactList)