messagingapp/msgui/unifiededitor/src/msgunieditoraddress.cpp
changeset 31 ebfee66fde93
child 34 84197e66a4bd
equal deleted inserted replaced
30:6a20128ce557 31:ebfee66fde93
       
     1 /*
       
     2  * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3  * All rights reserved.
       
     4  * This component and the accompanying materials are made available
       
     5  * under the terms of "Eclipse Public License v1.0"
       
     6  * which accompanies this distribution, and is available
       
     7  * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8  *
       
     9  * Initial Contributors:
       
    10  * Nokia Corporation - initial contribution.
       
    11  *
       
    12  * Contributors:
       
    13  *
       
    14  * Description:
       
    15  *
       
    16  */
       
    17 
       
    18 // INCLUDES
       
    19 #include <QTimer>
       
    20 #include <HbTextItem>
       
    21 #include <HbPushButton>
       
    22 #include <HbAction>
       
    23 #include <hbinputeditorinterface.h>
       
    24 #include <hbmessagebox.h>
       
    25 #include <cntservicescontact.h>
       
    26 #include <xqaiwrequest.h>
       
    27 #include <xqappmgr.h>
       
    28 #include <telconfigcrkeys.h>        // KCRUidTelephonyConfiguration
       
    29 #include <centralrepository.h>
       
    30 #include <HbNotificationDialog>
       
    31 #include <commonphoneparser.h>      // Common phone number validity checker
       
    32 #include <xqconversions.h>
       
    33 
       
    34 // USER INCLUDES
       
    35 #include "debugtraces.h"
       
    36 #include "msgunieditoraddress.h"
       
    37 #include "msgunifiededitorlineedit.h"
       
    38 #include "msgmonitor.h"
       
    39 #include "unieditorgenutils.h"
       
    40 
       
    41 const QString PBK_ICON("qtg_mono_contacts");
       
    42 const QString SEND_ICON("qtg_mono_send");
       
    43 const QString replacementStr("; ");
       
    44 
       
    45 // Constants
       
    46 const int KDefaultGsmNumberMatchLength = 7;  //matching unique ph numbers
       
    47 #define LOC_SMS_RECIPIENT_LIMIT_REACHED hbTrId("txt_messaging_dialog_number_of_recipients_exceeded")
       
    48 #define LOC_MMS_RECIPIENT_LIMIT_REACHED hbTrId("txt_messaging_dpopinfo_unable_to_add_more_recipien")
       
    49 #define LOC_DIALOG_OK hbTrId("txt_common_button_ok")
       
    50 #define LOC_BUTTON_CANCEL hbTrId("txt_common_button_cancel")
       
    51 #define LOC_INVALID_RECIPIENT hbTrId("txt_messaging_dialog_invalid_recipient_found")
       
    52 
       
    53 MsgUnifiedEditorAddress::MsgUnifiedEditorAddress( const QString& label,
       
    54                                                   QGraphicsItem *parent ) :
       
    55 MsgUnifiedEditorBaseWidget(parent),
       
    56 mSkipMaxRecipientQuery(false),
       
    57 mAboutToExceedMaxSmsRecipients(false),
       
    58 mAboutToExceedMaxMmsRecipients(false),
       
    59 mExceedsMaxMmsRecipientsBy(0)
       
    60 {
       
    61     this->setContentsMargins(0,0,0,0);
       
    62 
       
    63     mLaunchBtn = new HbPushButton(this);
       
    64     HbStyle::setItemName(mLaunchBtn,"launchBtn");
       
    65     connect(mLaunchBtn,SIGNAL(clicked()),this,SLOT(fetchContacts()));
       
    66 
       
    67     mLaunchBtn->setIcon(HbIcon(PBK_ICON));
       
    68 
       
    69     mAddressEdit = new MsgUnifiedEditorLineEdit(label,this);
       
    70     HbStyle::setItemName(mAddressEdit,"addressField");
       
    71 
       
    72     mAddressEdit->setMaxRows(40);
       
    73     connect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
       
    74             this, SLOT(onContentsChanged(const QString&)));
       
    75 
       
    76     // add "Send" action in VKB
       
    77     HbEditorInterface editorInterface(mAddressEdit);
       
    78     mAddressEdit->setInputMethodHints(Qt::ImhPreferNumbers);
       
    79     HbAction *sendAction = new HbAction(HbIcon(SEND_ICON), QString(),this);
       
    80     connect(sendAction, SIGNAL(triggered()),this, SIGNAL(sendMessage()));
       
    81     editorInterface.addAction(sendAction);
       
    82     }
       
    83 
       
    84 MsgUnifiedEditorAddress::~MsgUnifiedEditorAddress()
       
    85 {
       
    86 	//TODO: Should remove this code depending on orbit's reply whether it is needed
       
    87 	//to unregister the same plugin registered on two different widgets twice.
       
    88     //style()->unregisterPlugin(mPluginPath);
       
    89 }
       
    90 
       
    91 void MsgUnifiedEditorAddress::fetchContacts()
       
    92 {
       
    93     QList<QVariant> args;
       
    94     QString serviceName("com.nokia.services.phonebookservices");
       
    95     QString operation("fetch(QString,QString,QString)");
       
    96     XQAiwRequest* request;
       
    97     XQApplicationManager appManager;
       
    98     request = appManager.create(serviceName, "Fetch", operation, true); // embedded
       
    99     if ( request == NULL )
       
   100         {
       
   101         return;
       
   102         }
       
   103 
       
   104     // Result handlers
       
   105     connect (request, SIGNAL(requestOk(const QVariant&)), this, SLOT(handleOk(const QVariant&)));
       
   106     connect (request, SIGNAL(requestError(int,const QString&)), this, SLOT(handleError(int,const QString&)));
       
   107 
       
   108     args << QString(tr("Phonebook"));
       
   109     args << KCntActionAll;
       
   110     args << KCntFilterDisplayAll;
       
   111 
       
   112     request->setArguments(args);
       
   113     request->send();
       
   114     delete request;
       
   115 }
       
   116 
       
   117 void MsgUnifiedEditorAddress::handleOk(const QVariant& value)
       
   118 {
       
   119    CntServicesContactList contactList =
       
   120            qVariantValue<CntServicesContactList>(value);
       
   121     int count = contactList.count();
       
   122 
       
   123     ConvergedMessageAddressList addrlist;
       
   124     for(int i = 0; i < count; i++ )
       
   125     {
       
   126         ConvergedMessageAddress* address =
       
   127                 new ConvergedMessageAddress();
       
   128         address->setAddress(contactList[i].mPhoneNumber);
       
   129         address->setAlias(contactList[i].mDisplayName);
       
   130         addrlist << address;
       
   131     }
       
   132     setAddresses(addrlist);
       
   133 }
       
   134 
       
   135 void MsgUnifiedEditorAddress::handleError(int errorCode, const QString& errorMessage)
       
   136 {
       
   137     Q_UNUSED(errorMessage)
       
   138     Q_UNUSED(errorCode)
       
   139 }
       
   140 
       
   141 // ----------------------------------------------------------------------------
       
   142 // MsgUnifiedEditorAddress::addresses
       
   143 // @see header
       
   144 // ----------------------------------------------------------------------------
       
   145 ConvergedMessageAddressList MsgUnifiedEditorAddress::addresses(
       
   146         bool removeDuplicates)
       
   147 {
       
   148 #ifdef _DEBUG_TRACES_
       
   149     qCritical() << "MsgUnifiedEditorAddress::addresses start";
       
   150 #endif
       
   151     // sync-up map to account for user-actions on edit-field
       
   152     syncDeletionsToMap();
       
   153     syncAdditionsToMap();
       
   154 
       
   155     ConvergedMessageAddressList addresses;
       
   156     if(removeDuplicates)
       
   157     {
       
   158         QStringList uniqueAddr;
       
   159         uniqueAddr = uniqueAddressList();
       
   160         foreach(QString addr, uniqueAddr)
       
   161         {
       
   162             ConvergedMessageAddress* address = new ConvergedMessageAddress;
       
   163             address->setAddress(addr);
       
   164             address->setAlias(mAddressMap.value(addr));
       
   165             addresses.append(address);
       
   166         }
       
   167     }
       
   168     else
       
   169     {
       
   170         QMap<QString, QString>::iterator i = mAddressMap.begin();
       
   171         while (i != mAddressMap.end())
       
   172         {
       
   173             ConvergedMessageAddress* address = new ConvergedMessageAddress;
       
   174             address->setAddress(i.key());
       
   175             address->setAlias(i.value());
       
   176             addresses.append(address);
       
   177             i++;
       
   178         }
       
   179     }
       
   180 #ifdef _DEBUG_TRACES_
       
   181     qCritical() << "MsgUnifiedEditorAddress::addresses end";
       
   182 #endif
       
   183     return addresses;
       
   184 }
       
   185 
       
   186 int MsgUnifiedEditorAddress::addressCount()
       
   187 {
       
   188     return mAddressEdit->addresses().count();
       
   189 }
       
   190 
       
   191 void MsgUnifiedEditorAddress::setAddresses(ConvergedMessageAddressList addrlist)
       
   192 {
       
   193     // ensure flags are reset before starting the addr addition
       
   194     mAboutToExceedMaxSmsRecipients = false;
       
   195     mAboutToExceedMaxMmsRecipients = false;
       
   196     mExceedsMaxMmsRecipientsBy = 0;
       
   197 
       
   198     // first, we check if MMS max-recipient count will exceed
       
   199     int count = addrlist.count();
       
   200 	int futureCount = count + MsgMonitor::msgAddressCount();
       
   201 	if(futureCount > MsgMonitor::maxMmsRecipients())
       
   202 	{
       
   203 	    mAboutToExceedMaxMmsRecipients = true;
       
   204 	    mExceedsMaxMmsRecipientsBy =
       
   205 	            futureCount - MsgMonitor::maxMmsRecipients();
       
   206 	}
       
   207 	// else, check if SMS max-recipient count will exceed
       
   208 	else if(!mSkipMaxRecipientQuery)
       
   209 	{
       
   210 	    futureCount = count + addressCount();
       
   211 	    if( (addressCount() <= MsgMonitor::maxSmsRecipients()) &&
       
   212 	        (futureCount > MsgMonitor::maxSmsRecipients()) )
       
   213 	    {
       
   214 	        mAboutToExceedMaxSmsRecipients = true;
       
   215 	    }
       
   216 	}
       
   217 
       
   218 
       
   219     for(int i = 0; i < count; i++ )
       
   220     {
       
   221         mAddressMap.insertMulti(addrlist[i]->address(), addrlist[i]->alias());
       
   222         if(!addrlist[i]->alias().isEmpty())
       
   223         {
       
   224             mAddressEdit->setText(addrlist[i]->alias());
       
   225         }
       
   226         else
       
   227         {
       
   228             mAddressEdit->setText(addrlist[i]->address(), false);
       
   229         }
       
   230     }
       
   231 
       
   232     // addition operation complete, reset flags
       
   233     mAboutToExceedMaxSmsRecipients = false;
       
   234     mAboutToExceedMaxMmsRecipients = false;
       
   235     mExceedsMaxMmsRecipientsBy = 0;
       
   236 }
       
   237 
       
   238 int MsgUnifiedEditorAddress::contactMatchDigits()
       
   239 {
       
   240     // Read the amount of digits to be used in contact matching
       
   241     // The key is owned by PhoneApp
       
   242     int matchDigitCount = 0;
       
   243     TRAP_IGNORE(
       
   244         CRepository* repository = CRepository::NewLC(KCRUidTelConfiguration);
       
   245         if ( repository->Get(KTelMatchDigits, matchDigitCount) == KErrNone )
       
   246         {
       
   247             // Min is 7
       
   248             matchDigitCount = Max(matchDigitCount, KDefaultGsmNumberMatchLength);
       
   249         }
       
   250         CleanupStack::PopAndDestroy(); // repository
       
   251     );
       
   252     return matchDigitCount;
       
   253 }
       
   254 
       
   255 void MsgUnifiedEditorAddress::onContentsChanged(const QString& text)
       
   256 {
       
   257     // Max MMS recipient count check
       
   258     if( mAboutToExceedMaxMmsRecipients ||
       
   259         (MsgMonitor::msgAddressCount() >= MsgMonitor::maxMmsRecipients()) )
       
   260     {
       
   261         if(mAboutToExceedMaxMmsRecipients)
       
   262         {// show discreet note only once
       
   263             --mExceedsMaxMmsRecipientsBy;
       
   264             if(!mExceedsMaxMmsRecipientsBy)
       
   265             {
       
   266                 HbNotificationDialog::launchDialog(
       
   267                         LOC_MMS_RECIPIENT_LIMIT_REACHED);
       
   268             }
       
   269             resetToPrevious();
       
   270         }
       
   271         else
       
   272         {
       
   273             // update monitor data
       
   274             emit contentChanged();
       
   275             if(MsgMonitor::msgAddressCount() > MsgMonitor::maxMmsRecipients())
       
   276             {
       
   277                 HbNotificationDialog::launchDialog(
       
   278                         LOC_MMS_RECIPIENT_LIMIT_REACHED);
       
   279                 resetToPrevious();
       
   280                 // reset monitor data
       
   281                 emit contentChanged();
       
   282             }
       
   283             else
       
   284             {
       
   285                 mPrevBuffer = text;
       
   286             }
       
   287         }
       
   288         return;
       
   289     }
       
   290 
       
   291     // Max SMS recipient count check
       
   292     if( !mSkipMaxRecipientQuery &&
       
   293         (MsgMonitor::messageType() == ConvergedMessage::Sms) &&
       
   294         (mAddressEdit->addresses().count() > MsgMonitor::maxSmsRecipients()) )
       
   295     {
       
   296         // when we show this dialog, we don't want the intermediate states
       
   297         // to be signalled to us
       
   298         disconnect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
       
   299                 this, SLOT(onContentsChanged(const QString&)));
       
   300         QTimer::singleShot(50, this, SLOT(handleRecipientLimitReached()));
       
   301     }
       
   302     else
       
   303     {
       
   304         if(!mAboutToExceedMaxSmsRecipients)
       
   305         {// remember addresses before the block insertion started
       
   306             mPrevBuffer = text;
       
   307         }
       
   308         emit contentChanged();
       
   309     }
       
   310 }
       
   311 
       
   312 void MsgUnifiedEditorAddress::handleRecipientLimitReached()
       
   313 {
       
   314     HbMessageBox* dlg = new HbMessageBox(HbMessageBox::MessageTypeQuestion);
       
   315     dlg->setAttribute(Qt::WA_DeleteOnClose);
       
   316     dlg->setFocusPolicy(Qt::NoFocus);
       
   317     dlg->setTimeout(HbPopup::NoTimeout);
       
   318 
       
   319     dlg->setText(LOC_SMS_RECIPIENT_LIMIT_REACHED);
       
   320 
       
   321     HbAction* okAction = new HbAction(LOC_DIALOG_OK,dlg);
       
   322     dlg->addAction(okAction);
       
   323 
       
   324     HbAction* cancelAction = new HbAction(LOC_BUTTON_CANCEL,dlg);
       
   325     dlg->addAction(cancelAction);
       
   326 
       
   327     dlg->open(this,SLOT(onMaxRecipientsReached(HbAction*)));
       
   328     // reconnect to get back updates
       
   329     connect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
       
   330             this, SLOT(onContentsChanged(const QString&)));
       
   331     emit contentChanged();
       
   332 }
       
   333 
       
   334 void MsgUnifiedEditorAddress::syncDeletionsToMap()
       
   335 {
       
   336     // get address list from edit-field
       
   337     QStringList addrList = mAddressEdit->addresses();
       
   338 
       
   339     QMap<QString, QString>::iterator i = mAddressMap.begin();
       
   340     while (i != mAddressMap.end())
       
   341     {
       
   342         // check if either key or value is present in the list
       
   343         if( !(addrList.contains(i.value(), Qt::CaseSensitive) ||
       
   344               addrList.contains(i.key(), Qt::CaseSensitive)) )
       
   345         {// if none are present, then delete entry from map
       
   346             i = mAddressMap.erase(i);
       
   347         }
       
   348         else
       
   349         {
       
   350             ++i;
       
   351         }
       
   352     }
       
   353 }
       
   354 
       
   355 void MsgUnifiedEditorAddress::syncAdditionsToMap()
       
   356 {
       
   357     // remove already mapped addresses from edit-field
       
   358     QStringList userInputAddrList(mAddressEdit->addresses());
       
   359     QStringList mapAddrList = mAddressMap.values();
       
   360     mapAddrList << mAddressMap.keys();
       
   361     foreach(QString addr, mapAddrList)
       
   362     {
       
   363         userInputAddrList.removeOne(addr);
       
   364     }
       
   365 
       
   366     // add the unmapped addresses to address-map
       
   367     foreach(QString addr, userInputAddrList)
       
   368     {
       
   369         mAddressMap.insertMulti(addr, QString());
       
   370     }
       
   371 }
       
   372 
       
   373 QStringList MsgUnifiedEditorAddress::uniqueAddressList()
       
   374 {
       
   375     int matchDigitCount = MsgUnifiedEditorAddress::contactMatchDigits();
       
   376     QStringList mapAddrList = mAddressMap.keys();
       
   377     for(int j = 0;j<mapAddrList.count()-1;j++)
       
   378     {
       
   379         for(int i =j+1;i<mapAddrList.count();i++)
       
   380         {
       
   381             if(0 == mapAddrList[j].right(matchDigitCount).compare(mapAddrList[i].right(matchDigitCount)))
       
   382             {
       
   383                mapAddrList.removeAt(i);
       
   384                i--;
       
   385             }
       
   386         }
       
   387     }
       
   388     return mapAddrList;
       
   389 }
       
   390 
       
   391 // ----------------------------------------------------------------------------
       
   392 // MsgUnifiedEditorAddress::skipMaxRecipientQuery
       
   393 // @see header
       
   394 // ----------------------------------------------------------------------------
       
   395 void MsgUnifiedEditorAddress::skipMaxRecipientQuery(bool skip)
       
   396 {
       
   397     mSkipMaxRecipientQuery = skip;
       
   398 }
       
   399 
       
   400 void MsgUnifiedEditorAddress::setFocus()
       
   401 {
       
   402     mAddressEdit->setFocus(Qt::MouseFocusReason);
       
   403 }
       
   404 
       
   405 // ----------------------------------------------------------------------------
       
   406 // MsgUnifiedEditorAddress::resetToPrevious
       
   407 // @see header
       
   408 // ----------------------------------------------------------------------------
       
   409 void MsgUnifiedEditorAddress::resetToPrevious()
       
   410 {
       
   411     // when we do this reset operation, we don't want the intermediate states
       
   412     // to be signalled to us
       
   413     disconnect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
       
   414             this, SLOT(onContentsChanged(const QString&)));
       
   415 
       
   416     mAddressEdit->clearContent();
       
   417     QStringList list = mPrevBuffer.split(replacementStr,
       
   418             QString::SkipEmptyParts);
       
   419     int count = list.count();
       
   420     QStringList valList = mAddressMap.values();
       
   421     for(int i=0; i<count; i++)
       
   422     {
       
   423         QString addr = list.at(i);
       
   424         if(valList.contains(addr))
       
   425         {
       
   426             mAddressEdit->setText(addr);
       
   427         }
       
   428         else
       
   429         {
       
   430             mAddressEdit->setText(addr, false);
       
   431         }
       
   432     }
       
   433     syncDeletionsToMap();
       
   434     connect(mAddressEdit, SIGNAL(contentsChanged(const QString&)),
       
   435             this, SLOT(onContentsChanged(const QString&)));
       
   436 }
       
   437 
       
   438 // ----------------------------------------------------------------------------
       
   439 // MsgUnifiedEditorAddress::onMaxRecipientsReached
       
   440 // @see header
       
   441 // ----------------------------------------------------------------------------
       
   442 void MsgUnifiedEditorAddress::onMaxRecipientsReached(HbAction* action)
       
   443 {
       
   444     HbMessageBox *dlg = qobject_cast<HbMessageBox*> (sender());
       
   445     if (action == dlg->actions().at(0)) {
       
   446         // accept new content, update prev-buffer
       
   447         mPrevBuffer = mAddressEdit->content();
       
   448     }
       
   449     else {
       
   450         // reject the new content, keep the old
       
   451         resetToPrevious();
       
   452     }
       
   453 }
       
   454 
       
   455 // ----------------------------------------------------------------------------
       
   456 // MsgUnifiedEditorAddress::validateContacts
       
   457 // @see header
       
   458 // ----------------------------------------------------------------------------
       
   459 bool MsgUnifiedEditorAddress::validateContacts()
       
   460 {
       
   461     UniEditorGenUtils* genUtils = new UniEditorGenUtils;
       
   462 
       
   463     // sync-up map to account for user-actions on address-field
       
   464     syncDeletionsToMap();
       
   465     syncAdditionsToMap();
       
   466 
       
   467     // get the list of contacts in address-field
       
   468     QStringList fieldAddresses(mAddressEdit->addresses());
       
   469 
       
   470     bool allValid = true;
       
   471     foreach(QString addr, fieldAddresses)
       
   472     {
       
   473         // run address validation only if address is unmapped
       
   474         // (i.e. user-inserted)
       
   475         if(mAddressMap.contains(addr))
       
   476         {
       
   477             // 1. perform number validation
       
   478             allValid = CommonPhoneParser::IsValidPhoneNumber(
       
   479                     *XQConversions::qStringToS60Desc(addr),
       
   480                     CommonPhoneParser::ESMSNumber );
       
   481 
       
   482             // 2. if number validity fails, then perform email addr validation
       
   483             if( !allValid &&
       
   484                 (MsgMonitor::messageType() == ConvergedMessage::Mms) )
       
   485             { // additional check for MMS only
       
   486                 allValid = genUtils->IsValidEmailAddress(
       
   487                         *XQConversions::qStringToS60Desc(addr) );
       
   488             }
       
   489 
       
   490             if(!allValid)
       
   491             {
       
   492                 mAddressEdit->highlightInvalidString(addr);
       
   493                 QString invalidAddrStr =
       
   494                         QString(LOC_INVALID_RECIPIENT).arg(addr);
       
   495                 HbMessageBox* dlg = new HbMessageBox(invalidAddrStr,
       
   496                         HbMessageBox::MessageTypeInformation);
       
   497                 dlg->setDismissPolicy(HbPopup::TapInside);
       
   498                 dlg->setTimeout(HbPopup::NoTimeout);
       
   499                 dlg->setAttribute(Qt::WA_DeleteOnClose, true);
       
   500                 dlg->open(this, SLOT(handleInvalidContactDialog(HbAction*)));
       
   501                 break;
       
   502             }
       
   503         }
       
   504     }
       
   505     delete genUtils;
       
   506     return allValid;
       
   507 }
       
   508 
       
   509 void MsgUnifiedEditorAddress::handleInvalidContactDialog(
       
   510         HbAction* act)
       
   511 {
       
   512     Q_UNUSED(act);
       
   513     QTimer::singleShot(250, this, SLOT(setFocus()));
       
   514 }
       
   515 
       
   516 Q_IMPLEMENT_USER_METATYPE(CntServicesContact)
       
   517 Q_IMPLEMENT_USER_METATYPE_NO_OPERATORS(CntServicesContactList)
       
   518 
       
   519 //EOF