plugins/contacts/symbian/plugin/src/cntsymbiandatabase.cpp
changeset 0 876b1a06bc25
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtCore module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 //system includes
       
    42 #include <e32base.h>
       
    43 #include <s32mem.h>
       
    44 #include <cntitem.h>
       
    45 
       
    46 //user includes
       
    47 #include "cntsymbiandatabase.h"
       
    48 #include "cntsymbiantransformerror.h"
       
    49 #include "qcontactchangeset.h"
       
    50 #include "qcontactmanagerengine.h"
       
    51 
       
    52 // Constant
       
    53 typedef QPair<QContactLocalId, QContactLocalId> QOwnCardPair;
       
    54 
       
    55 CntSymbianDatabase::CntSymbianDatabase(QContactManagerEngine *engine, QContactManager::Error* error) :
       
    56     m_engine(engine),
       
    57     m_contactDatabase(0),
       
    58     m_currentOwnCardId(0)
       
    59 {
       
    60     TRAPD(err, initializeL());
       
    61     CntSymbianTransformError::transformError(err, error);
       
    62 }
       
    63 
       
    64 void CntSymbianDatabase::initializeL()
       
    65 {
       
    66     User::LeaveIfNull(m_engine);
       
    67 
       
    68 #ifdef SYMBIAN_BACKEND_USE_SQLITE
       
    69 	// 10.x platforms do not need some of CContactDatabase's concepts, so
       
    70 	// they use the optimized OpenV2 and CreateV2.
       
    71     TRAPD(err, m_contactDatabase = CContactDatabase::OpenV2L());
       
    72     // Database not found, create it
       
    73     if (err == KErrNotFound) {
       
    74         m_contactDatabase = CContactDatabase::CreateV2L();
       
    75     }
       
    76 #else		
       
    77     TRAPD(err, m_contactDatabase = CContactDatabase::OpenL());
       
    78 
       
    79     // Database not found, create it
       
    80     if (err == KErrNotFound) {
       
    81         m_contactDatabase = CContactDatabase::CreateL();
       
    82     }
       
    83 #endif
       
    84 
       
    85 #ifndef SYMBIAN_BACKEND_USE_SQLITE
       
    86     // In pre 10.1 platforms the AddObserverL & RemoveObserver functions are not
       
    87     // exported so we need to use CContactChangeNotifier.
       
    88     TRAP(err, m_contactChangeNotifier = CContactChangeNotifier::NewL(*m_contactDatabase, this));
       
    89 #else
       
    90     TRAP(err, m_contactDatabase->AddObserverL(*this));
       
    91     TRAP(err, m_contactDatabase->AddObserverV2L(*this));
       
    92 #endif
       
    93 
       
    94     // Read current own card id (self contact id)
       
    95     TContactItemId myCard = m_contactDatabase->OwnCardId();
       
    96     if (myCard > 0)
       
    97         m_currentOwnCardId = QContactLocalId(myCard);
       
    98 
       
    99     // Currently the group membership check is only used in pre-10.1
       
   100     // platforms. In 10.1 we need to check the performance penalty
       
   101     // caused in the instantiation of QContactManager. If the
       
   102     // performance is too bad, then the MContactDbObserver API needs to
       
   103     // be changed in 10.1 so that we don't need the group membership
       
   104     // buffer in the engine level. In other words events like
       
   105     // EContactDbObserverEventGroupMembersAdded and 
       
   106     // EContactDbObserverEventGroupMembersRemoved need to be added to
       
   107     // MContactDbObserver.
       
   108 #ifndef SYMBIAN_BACKEND_USE_SQLITE
       
   109     updateGroupMembershipsL();
       
   110 #endif
       
   111 }
       
   112 
       
   113 CntSymbianDatabase::~CntSymbianDatabase()
       
   114 {
       
   115     m_engine = NULL;
       
   116 #ifndef SYMBIAN_BACKEND_USE_SQLITE
       
   117     delete m_contactChangeNotifier;
       
   118 #else
       
   119     if (m_contactDatabase != 0) {
       
   120         m_contactDatabase->RemoveObserver(*this);
       
   121         m_contactDatabase->RemoveObserverV2(*this);
       
   122     }
       
   123 #endif
       
   124     delete m_contactDatabase;
       
   125 }
       
   126 
       
   127 CContactDatabase* CntSymbianDatabase::contactDatabase()
       
   128 {
       
   129     return m_contactDatabase;
       
   130 }
       
   131 
       
   132 void CntSymbianDatabase::appendContactsEmitted(const QList<QContactLocalId> &contactList)
       
   133 {
       
   134     m_contactsEmitted += contactList;
       
   135 }
       
   136 
       
   137 void CntSymbianDatabase::appendContactEmitted(QContactLocalId id)
       
   138 {
       
   139     m_contactsEmitted.append(id);
       
   140 }
       
   141 
       
   142 /*!
       
   143  * Respond to a contacts database event, delegating this event to
       
   144  * an appropriate signal as required.
       
   145  *
       
   146  * \param aEvent Contacts database event describing the change to the
       
   147  *  database.
       
   148  */
       
   149 void CntSymbianDatabase::HandleDatabaseEventL(TContactDbObserverEvent aEvent)
       
   150 {
       
   151     QContactChangeSet changeSet;
       
   152     TContactItemId id = aEvent.iContactId;
       
   153 
       
   154 #ifdef SYMBIAN_BACKEND_SIGNAL_EMISSION_TWEAK
       
   155     switch (aEvent.iType)
       
   156     {
       
   157     case EContactDbObserverEventContactAdded:
       
   158         if(m_contactsEmitted.contains(id))
       
   159             m_contactsEmitted.removeOne(id);
       
   160         else
       
   161             changeSet.insertAddedContact(id);
       
   162         break;
       
   163     case EContactDbObserverEventOwnCardDeleted:
       
   164         if (m_contactsEmitted.contains(id)) {
       
   165             m_contactsEmitted.removeOne(id);
       
   166         } else {
       
   167             // signal selfContactIdChanged (from id to zero)
       
   168             QOwnCardPair ownCard(m_currentOwnCardId, QContactLocalId(0));
       
   169             changeSet.setOldAndNewSelfContactId(ownCard);
       
   170             // signal contactsRemoved (the self contact was deleted)
       
   171             changeSet.insertRemovedContact(id);
       
   172         }
       
   173         // reset own card id
       
   174         m_currentOwnCardId = QContactLocalId(0);
       
   175         break;
       
   176     case EContactDbObserverEventContactDeleted:
       
   177         if(m_contactsEmitted.contains(id))
       
   178             m_contactsEmitted.removeOne(id);
       
   179         else
       
   180             changeSet.insertRemovedContact(id);
       
   181         break;
       
   182     case EContactDbObserverEventContactChanged:
       
   183         if(m_contactsEmitted.contains(id))
       
   184             m_contactsEmitted.removeOne(id);
       
   185         else
       
   186             changeSet.insertChangedContact(id);
       
   187         break;
       
   188     case EContactDbObserverEventGroupAdded:
       
   189         if(m_contactsEmitted.contains(id)) {
       
   190             // adding a group triggers also a "changed" event. The work-around
       
   191             // is to leave the id to m_contactsEmitted
       
   192         } else {
       
   193             changeSet.insertAddedContact(id);
       
   194             m_contactsEmitted.append(id);
       
   195         }
       
   196         break;
       
   197     case EContactDbObserverEventGroupDeleted:
       
   198         if(m_contactsEmitted.contains(id))
       
   199             m_contactsEmitted.removeOne(id);
       
   200         else
       
   201             changeSet.insertRemovedContact(id);
       
   202         break;
       
   203     case EContactDbObserverEventGroupChanged:
       
   204 				//handled in HandleDatabaseEventV2L
       
   205         break;
       
   206     case EContactDbObserverEventOwnCardChanged:
       
   207         if (m_contactsEmitted.contains(id)) {
       
   208             m_contactsEmitted.removeOne(id);
       
   209         }
       
   210         else {
       
   211             if (m_currentOwnCardId == QContactLocalId(id)) {
       
   212                 //own card content was changed
       
   213                 changeSet.insertChangedContact(m_currentOwnCardId);
       
   214             }
       
   215         
       
   216             QOwnCardPair ownCard(m_currentOwnCardId, QContactLocalId(id));
       
   217             changeSet.setOldAndNewSelfContactId(ownCard);
       
   218             m_currentOwnCardId = QContactLocalId(id);
       
   219         }
       
   220         break;
       
   221     default:
       
   222         break; // ignore other events
       
   223     }
       
   224 #else // SYMBIAN_BACKEND_SIGNAL_EMISSION_TWEAK
       
   225     switch (aEvent.iType)
       
   226     {
       
   227     case EContactDbObserverEventContactAdded:
       
   228         changeSet.insertAddedContact(id);
       
   229         break;
       
   230     case EContactDbObserverEventOwnCardDeleted:
       
   231         {
       
   232             // signal selfContactIdChanged (from id to zero)
       
   233             QOwnCardPair ownCard(m_currentOwnCardId, QContactLocalId(0));
       
   234             changeSet.setOldAndNewSelfContactId(ownCard);
       
   235             // signal contactsRemoved (the self contact was deleted)
       
   236             changeSet.insertRemovedContact(id);
       
   237             // reset own card id
       
   238             m_currentOwnCardId = QContactLocalId(0);
       
   239         }
       
   240         break;
       
   241     case EContactDbObserverEventContactDeleted:
       
   242         {
       
   243             changeSet.insertRemovedContact(id);
       
   244 
       
   245             // Check if contact was part of some group. 
       
   246             // This check is needed because CContactDatabase will NOT
       
   247             // provide EContactDbObserverEventGroupChanged event in this case!!!
       
   248             QMap<QContactLocalId, QSet<QContactLocalId> >::iterator i;
       
   249             for (i=m_groupContents.begin(); i!=m_groupContents.end(); i++ ) {
       
   250                 if (i->contains(id)) {
       
   251                     changeSet.insertRemovedRelationshipsContact(i.key());
       
   252                     changeSet.insertRemovedRelationshipsContacts(i->toList());
       
   253                     i->remove(id);
       
   254                 }
       
   255             }
       
   256         }
       
   257         break;
       
   258     case EContactDbObserverEventContactChanged:
       
   259         changeSet.insertChangedContact(id);
       
   260         break;
       
   261     case EContactDbObserverEventGroupAdded:
       
   262         // Creating a group will cause two events.
       
   263         // Emitting addedContact from EContactDbObserverEventGroupChanged.
       
   264         changeSet.insertAddedContact(id);
       
   265         break;
       
   266     case EContactDbObserverEventGroupDeleted:
       
   267         {
       
   268             changeSet.insertRemovedContact(id);
       
   269             
       
   270             // Check if there was any contacts in the group
       
   271             if (m_groupContents.value(id).count()) {
       
   272                 changeSet.insertRemovedRelationshipsContact(id);
       
   273                 changeSet.insertRemovedRelationshipsContacts(m_groupContents.value(id).toList());
       
   274             }
       
   275             m_groupContents.remove(id);
       
   276         }
       
   277         break;
       
   278     case EContactDbObserverEventGroupChanged:
       
   279         {
       
   280             bool isOldGroup = m_groupContents.contains(id);
       
   281 
       
   282             // Contact DB observer API does not give information of contacts
       
   283             // possibly added to or removed from the group
       
   284             QSet<QContactLocalId> added;
       
   285             QSet<QContactLocalId> removed;
       
   286             TRAPD(err, updateGroupMembershipsL(id, added, removed));        
       
   287             if(err != KErrNone)
       
   288                 changeSet.setDataChanged(true);
       
   289 
       
   290             if (removed.count()) {
       
   291                 // The group changed event was caused by removing contacts
       
   292                 // from the group
       
   293                 changeSet.insertRemovedRelationshipsContact(id);
       
   294                 changeSet.insertRemovedRelationshipsContacts(removed.toList());
       
   295             }
       
   296             if (added.count()) {
       
   297                 // The group changed event was caused by adding contacts
       
   298                 // to the group
       
   299                 changeSet.insertAddedRelationshipsContact(id);
       
   300                 changeSet.insertAddedRelationshipsContacts(added.toList());
       
   301             }
       
   302             if (added.count() == 0 && removed.count() == 0) {
       
   303                 // The group changed event was caused by modifying the group
       
   304                 // NOTE: Do not emit this for a new group. Creating a group
       
   305                 // through the backend causes two events GroupAdded and 
       
   306                 // GroupChanged.
       
   307                 if (isOldGroup)
       
   308                     changeSet.insertChangedContact(id);
       
   309             }
       
   310         }
       
   311         break;
       
   312     case EContactDbObserverEventOwnCardChanged:
       
   313         if (m_currentOwnCardId == QContactLocalId(id))
       
   314             changeSet.insertChangedContact(m_currentOwnCardId);
       
   315         else
       
   316             changeSet.setOldAndNewSelfContactId(QOwnCardPair(m_currentOwnCardId, QContactLocalId(id)));
       
   317         m_currentOwnCardId = QContactLocalId(id);
       
   318         break;
       
   319     default:
       
   320         break; // ignore other events
       
   321     }
       
   322 #endif // SYMBIAN_BACKEND_SIGNAL_EMISSION_TWEAK
       
   323     
       
   324     changeSet.emitSignals(m_engine);
       
   325 }
       
   326 
       
   327 #ifdef SYMBIAN_BACKEND_USE_SQLITE  
       
   328 /*!
       
   329  * Respond to a contacts database extended event, delegating this event to
       
   330  * an appropriate signal as required.
       
   331  *
       
   332  * \param aEvent Contacts database extended event describing the change to the
       
   333  *  database.
       
   334  */
       
   335 void CntSymbianDatabase::HandleDatabaseEventV2L(TContactDbObserverEventV2 aEvent)
       
   336 {
       
   337     QContactChangeSet changeSet;
       
   338     switch (aEvent.iTypeV2)
       
   339     {
       
   340     case EContactDbObserverEventV2ContactAddedToGroup:
       
   341         if (m_contactsEmitted.contains(aEvent.iContactId) && 
       
   342             m_contactsEmitted.contains(aEvent.iAdditionalContactId)) {
       
   343             m_contactsEmitted.removeOne(aEvent.iContactId);
       
   344             m_contactsEmitted.removeOne(aEvent.iAdditionalContactId);
       
   345             }
       
   346         else {
       
   347             QList<QContactLocalId> affectedContactIds;
       
   348             affectedContactIds.append(aEvent.iContactId);
       
   349             affectedContactIds.append(aEvent.iAdditionalContactId);
       
   350             changeSet.insertAddedRelationshipsContacts(affectedContactIds);
       
   351         }
       
   352         break;
       
   353     case EContactDbObserverEventV2ContactRemovedFromGroup:
       
   354         if (m_contactsEmitted.contains(aEvent.iContactId) && 
       
   355             m_contactsEmitted.contains(aEvent.iAdditionalContactId)) {
       
   356             m_contactsEmitted.removeOne(aEvent.iContactId);
       
   357             m_contactsEmitted.removeOne(aEvent.iAdditionalContactId);
       
   358             }
       
   359         else {
       
   360             QList<QContactLocalId> affectedContactIds;
       
   361             affectedContactIds.append(aEvent.iContactId);
       
   362             affectedContactIds.append(aEvent.iAdditionalContactId);
       
   363             changeSet.insertRemovedRelationshipsContacts(affectedContactIds);
       
   364         }
       
   365         break;
       
   366     case EContactDbObserverEventV2GroupChanged:
       
   367         if(m_contactsEmitted.contains(aEvent.iContactId)) {
       
   368             m_contactsEmitted.removeOne(aEvent.iContactId);
       
   369         }
       
   370         else {
       
   371             changeSet.insertChangedContact(aEvent.iContactId);
       
   372         }
       
   373         break;
       
   374     default:
       
   375         break; // ignore other events   
       
   376     }
       
   377     changeSet.emitSignals(m_engine);
       
   378 }
       
   379 #endif
       
   380 
       
   381 /*
       
   382  * Private implementation for updating the buffer containing the members of all
       
   383  * groups.
       
   384  */
       
   385 void CntSymbianDatabase::updateGroupMembershipsL()
       
   386 {
       
   387     CContactIdArray *groupIds = m_contactDatabase->GetGroupIdListL();
       
   388     for (TInt i(0); i < groupIds->Count(); ++i) {
       
   389         QContactLocalId id = (*groupIds)[i];
       
   390         QSet<QContactLocalId> dummySet;
       
   391         updateGroupMembershipsL(id, dummySet, dummySet);
       
   392     }
       
   393     delete groupIds;
       
   394 }
       
   395 
       
   396 /*
       
   397  * Private implementation for updating the buffer containing the members of a
       
   398  * group.
       
   399  */
       
   400 void CntSymbianDatabase::updateGroupMembershipsL(
       
   401     QContactLocalId groupId,
       
   402     QSet<QContactLocalId> &added,
       
   403     QSet<QContactLocalId> &removed)
       
   404 {
       
   405     QSet<QContactLocalId> groupMembersNew = groupMembersL(groupId);
       
   406     QSet<QContactLocalId> groupMembersOld = m_groupContents.value(groupId);
       
   407 
       
   408     if(groupMembersOld.count() < groupMembersNew.count())
       
   409         added = groupMembersNew - groupMembersOld;
       
   410     else if(groupMembersOld.count() > groupMembersNew.count())
       
   411         removed = groupMembersOld - groupMembersNew;
       
   412 
       
   413     m_groupContents.insert(groupId, groupMembersNew);
       
   414 }
       
   415 
       
   416 /*
       
   417  * Private implementation for fetching the members of a group.
       
   418  */
       
   419 QSet<QContactLocalId> CntSymbianDatabase::groupMembersL(QContactLocalId groupId)
       
   420 {
       
   421     QSet<QContactLocalId> groupMembers;
       
   422 
       
   423     CContactItem *contactItem = m_contactDatabase->ReadContactLC(TContactItemId(groupId));
       
   424     Q_ASSERT(contactItem && contactItem->Type() == KUidContactGroup);
       
   425     CContactGroup *group = static_cast<CContactGroup*>(contactItem);
       
   426     
       
   427     const CContactIdArray *idArray = group->ItemsContained();
       
   428     
       
   429     //loop through all the contacts and add them to the list
       
   430     for (int i(0); i < idArray->Count(); i++) {
       
   431         groupMembers.insert((*idArray)[i]);
       
   432     }
       
   433     CleanupStack::PopAndDestroy(contactItem);
       
   434 
       
   435     return groupMembers;
       
   436 }