javaextensions/pim/framework/src.s60/cpimlist.cpp
branchRCL_3
changeset 19 04becd199f91
child 23 98ccebc37403
equal deleted inserted replaced
16:f5050f1da672 19:04becd199f91
       
     1 /*
       
     2 * Copyright (c) 2008 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:  Abstract PIMList base class.
       
    15  *
       
    16 */
       
    17 
       
    18 
       
    19 // INCLUDE FILES
       
    20 #include  "cpimlist.h"
       
    21 #include  "mpimadaptermanager.h"
       
    22 #include  "mpimlistadapter.h"
       
    23 #include  "mpimlocalizationdata.h"
       
    24 #include  "cpimvalidator.h"
       
    25 #include  "cpimitem.h"
       
    26 #include  "cpimitemmatcher.h"
       
    27 #include  "cpimstringmatcher.h"
       
    28 #include  "cleanupresetanddestroy.h"
       
    29 #include  "pimexternalchanges.h"
       
    30 #include  "pimpanics.h"
       
    31 #include  "pimjnitools.h"
       
    32 #include  "pimutils.h"
       
    33 #include  "s60commonutils.h"
       
    34 #include  "jstringutils.h"
       
    35 #include "logger.h"
       
    36 
       
    37 // CONSTANTS
       
    38 /** Item array granularity. */
       
    39 const TInt KItemArrayGranularity = 8;
       
    40 
       
    41 CPIMList::CPIMList(const CPIMValidator& aValidator) :
       
    42         iItems(KItemArrayGranularity), iValidator(aValidator) // not owned
       
    43 {
       
    44     JELOG2(EPim);
       
    45 }
       
    46 
       
    47 void CPIMList::ConstructL(MPIMLocalizationData* aLocalizationData,
       
    48                           MPIMAdapterManager* aAdapterManager, MPIMListAdapter* aListAdapter)
       
    49 {
       
    50     JELOG2(EPim);
       
    51     iLocalizationData = aLocalizationData; // not owned
       
    52     iAdapterManager = aAdapterManager; // not owned
       
    53     iListAdapter = aListAdapter; // not owned
       
    54 }
       
    55 
       
    56 CPIMList::~CPIMList()
       
    57 {
       
    58     JELOG2(EPim);
       
    59     iItems.Close();
       
    60 }
       
    61 
       
    62 pimbaseitem* CPIMList::createItem()
       
    63 {
       
    64     JELOG2(EPim);
       
    65     TInt error = KErrNone;
       
    66     CPIMItem* item = NULL;
       
    67     TRAP(error, item = DoCreateItemL(KPIMNullItemID(), NULL));
       
    68     if (error != KErrNone)
       
    69         throw error;
       
    70     item->SetModified(ETrue);
       
    71     return item;
       
    72 }
       
    73 
       
    74 void CPIMList::removeItem(pimbaseitem* aItem)
       
    75 {
       
    76     JELOG2(EPim);
       
    77     TInt error = KErrNone;
       
    78     TRAP(error,
       
    79     {
       
    80         if (!iListAdapter)
       
    81         {
       
    82             User::Leave(KErrSessionClosed);
       
    83         }
       
    84         CPIMItem* item = static_cast<CPIMItem*>(aItem);
       
    85         // Find the item in the list
       
    86         TInt itemIndex = iItems.Find(item);
       
    87 
       
    88         if (itemIndex == KErrNotFound)
       
    89         {
       
    90             // The item is not in the list
       
    91             User::Leave(KErrArgument);
       
    92         }
       
    93 
       
    94         // Remove item from native database.
       
    95         // If the item does not exist any more in the database, we will
       
    96         // not touch but let the update mechanism clean it away at
       
    97         // some other time.
       
    98         DoDeleteItemL(*item);
       
    99 
       
   100         // Remove item from the list
       
   101         item->RemoveAdapterAssociation();
       
   102         iItems.Remove(itemIndex);
       
   103 
       
   104         // The item is owned by its Java side peer, so we won't
       
   105         // delete it here.
       
   106     }
       
   107         );
       
   108     if (error != KErrNone)
       
   109         throw error;
       
   110 }
       
   111 
       
   112 void CPIMList::addCommittedItem(pimbaseitem* aItem)
       
   113 {
       
   114     JELOG2(EPim);
       
   115     CPIMItem* item = static_cast<CPIMItem*>(aItem);
       
   116     TInt error = KErrNone;
       
   117     TRAP(error,
       
   118     {
       
   119         __ASSERT_DEBUG(
       
   120             iItems.Find(item)== KErrNotFound,
       
   121             User::Panic(KPIMPanicCategory, EPIMPanicCommittedExists));
       
   122 
       
   123         User::LeaveIfError(iItems.Append(item));
       
   124     }
       
   125         );
       
   126     if (error != KErrNone)
       
   127         throw error;
       
   128 }
       
   129 
       
   130 jstring CPIMList::getName(JNIEnv* aJniEnv)
       
   131 {
       
   132     JELOG2(EPim);
       
   133     HBufC* name = NULL;
       
   134     TInt error = KErrNone;
       
   135     TRAP(error, name = iAdapterManager->ListNameL().AllocL());
       
   136     if (error != KErrNone || !name)
       
   137     {
       
   138         // If a leave occurred the name was never created
       
   139         return NULL;
       
   140     }
       
   141     jstring javaName = java::util::S60CommonUtils::NativeToJavaString(
       
   142                            *aJniEnv, *name);
       
   143     delete name;
       
   144     return javaName; // if NULL, it indicates error
       
   145 }
       
   146 
       
   147 void CPIMList::close()
       
   148 {
       
   149     JELOG2(EPim);
       
   150     if (!iListAdapter)
       
   151     {
       
   152         throw KErrSessionClosed;
       
   153     }
       
   154 
       
   155     // Close the list adapter
       
   156     iListAdapter->Close();
       
   157 
       
   158     // Notify items about closing list
       
   159     const TInt n = iItems.Count();
       
   160     for (TInt i = 0; i < n; i++)
       
   161     {
       
   162         iItems[i]->ListClosed();
       
   163     }
       
   164 
       
   165     // Setting the list adapter NULL denotes closed list
       
   166     iListAdapter = NULL;
       
   167 
       
   168 }
       
   169 
       
   170 jintArray CPIMList::callItemsByEnumerationType(JNIEnv* aJniEnv,
       
   171         int aEnumerationType, int aMatchingItemHandle, jstring aStringArg,
       
   172         jintArray aError)
       
   173 {
       
   174     JELOG2(EPim);
       
   175     const JStringUtils stringArg(*aJniEnv, aStringArg);
       
   176     const TDesC* nativeStringArg = (aStringArg ? &stringArg : NULL);
       
   177     TInt error = KErrNone;
       
   178     jintArray itemHandles = NULL;
       
   179     TRAP(error, itemHandles = CallItemsByEnumerationTypeL(aJniEnv,
       
   180                               aEnumerationType, aMatchingItemHandle, nativeStringArg));
       
   181     SetJavaErrorCode(aJniEnv, aError, error);
       
   182     return itemHandles;
       
   183 }
       
   184 
       
   185 jintArray CPIMList::CallItemsByEnumerationTypeL(JNIEnv* aJniEnv,
       
   186         int aEnumerationType, int aMatchingItemHandle,
       
   187         const TDesC* aStringArg)
       
   188 {
       
   189     JELOG2(EPim);
       
   190     RPointerArray<CPIMItem>* items = NULL;
       
   191 
       
   192     if (aEnumerationType == EPIMItemAll)
       
   193     {
       
   194         items = ItemsL();
       
   195     }
       
   196     else if (aEnumerationType == EPIMItemMatchingItem)
       
   197     {
       
   198         pimbaseitem * baseMatchingItem =
       
   199             reinterpret_cast<pimbaseitem *>(aMatchingItemHandle);
       
   200         CPIMItem* matchingItem =
       
   201             static_cast<CPIMItem *>(baseMatchingItem);
       
   202         items = ItemsL(*matchingItem);
       
   203     }
       
   204     else if (aEnumerationType == EPIMItemMatchingString)
       
   205     {
       
   206         __ASSERT_DEBUG(aStringArg, User::Panic(KPIMPanicCategory,
       
   207                                                EPIMPanicNullArgument));
       
   208 
       
   209         items = ItemsL(*aStringArg);
       
   210     }
       
   211     else if (aEnumerationType == EPIMItemMatchingCategory)
       
   212     {
       
   213         // Category argument may be NULL, indicating "uncategorized"
       
   214         items = ItemsByCategoryL(aStringArg);
       
   215     }
       
   216     else
       
   217     {
       
   218         User::Leave(KErrCorrupt); // Error
       
   219     }
       
   220 
       
   221     // We now own the items array
       
   222 
       
   223     jintArray itemHandles = GetJavaItemHandles(*aJniEnv, *items);
       
   224     items->Close();
       
   225     delete items;
       
   226     items = NULL;
       
   227 
       
   228     if (!itemHandles)
       
   229     {
       
   230         User::Leave(KErrNoMemory);
       
   231     }
       
   232 
       
   233     return itemHandles;
       
   234 }
       
   235 
       
   236 RPointerArray<CPIMItem>* CPIMList::ItemsL()
       
   237 {
       
   238     JELOG2(EPim);
       
   239     if (!iListAdapter)
       
   240     {
       
   241         User::Leave(KErrSessionClosed);
       
   242     }
       
   243 
       
   244     // Put all items in an array as MPIMItemData objects
       
   245     RPointerArray<MPIMItem> tempArr(KItemArrayGranularity);
       
   246     CleanupClosePushL(tempArr);
       
   247 
       
   248     const TInt n = iItems.Count();
       
   249     for (TInt i = 0; i < n; i++)
       
   250     {
       
   251         CPIMItem* item = iItems[i];
       
   252         User::LeaveIfError(tempArr.Append(item));
       
   253     }
       
   254 
       
   255     TLinearOrder<MPIMItem> order(iAdapterManager->ItemOrder());
       
   256 
       
   257     RPointerArray<CPIMItem>* retArr = SortAndConvertToCPIMItemsL(order,
       
   258                                       tempArr);
       
   259 
       
   260     CleanupStack::PopAndDestroy(); // tempArr cleanup close
       
   261     return retArr;
       
   262 }
       
   263 
       
   264 RPointerArray<CPIMItem>* CPIMList::ItemsL(const CPIMItem& aMatchingItem)
       
   265 {
       
   266     JELOG2(EPim);
       
   267     if (!iListAdapter)
       
   268     {
       
   269         User::Leave(KErrSessionClosed);
       
   270     }
       
   271 
       
   272     // Matching items are inserted temporarily into this array for sorting
       
   273     RPointerArray<MPIMItem> tempArr(KItemArrayGranularity);
       
   274     CleanupClosePushL(tempArr);
       
   275 
       
   276     CPIMItemMatcher* itemMatcher = CPIMItemMatcher::NewLC(iValidator,
       
   277                                    *iAdapterManager, aMatchingItem);
       
   278 
       
   279     const TInt numItems = iItems.Count();
       
   280     for (TInt itemIndex = 0; itemIndex < numItems; itemIndex++)
       
   281     {
       
   282         CPIMItem* listItem = iItems[itemIndex];
       
   283 
       
   284         if (itemMatcher->MatchL(*listItem))
       
   285         {
       
   286             User::LeaveIfError(tempArr.Append(listItem));
       
   287         }
       
   288     }
       
   289 
       
   290     CleanupStack::PopAndDestroy(itemMatcher);
       
   291     TLinearOrder<MPIMItem> order(iAdapterManager->ItemOrder());
       
   292 
       
   293     RPointerArray<CPIMItem>* retArr = SortAndConvertToCPIMItemsL(order,
       
   294                                       tempArr);
       
   295 
       
   296     CleanupStack::PopAndDestroy(); // tempArr cleanup close
       
   297     return retArr;
       
   298 }
       
   299 
       
   300 RPointerArray<CPIMItem>* CPIMList::ItemsL(const TDesC& aMatchingValue)
       
   301 {
       
   302     JELOG2(EPim);
       
   303     if (!iListAdapter)
       
   304     {
       
   305         User::Leave(KErrSessionClosed);
       
   306     }
       
   307 
       
   308     // Matching items are inserted temporarily into this array for sorting
       
   309     RPointerArray<MPIMItem> tempArr(KItemArrayGranularity);
       
   310     CleanupClosePushL(tempArr);
       
   311 
       
   312     CPIMStringMatcher* stringMatcher =
       
   313         new(ELeave) CPIMStringMatcher(iValidator);
       
   314 
       
   315     CleanupStack::PushL(stringMatcher);
       
   316 
       
   317     // Iterate through all items in the list
       
   318     const TInt numItems = iItems.Count();
       
   319     for (TInt itemIndex = 0; itemIndex < numItems; itemIndex++)
       
   320     {
       
   321         CPIMItem* listItem = iItems[itemIndex];
       
   322 
       
   323         if (stringMatcher->MatchL(aMatchingValue, *listItem))
       
   324         {
       
   325             User::LeaveIfError(tempArr.Append(listItem));
       
   326         }
       
   327     }
       
   328 
       
   329     CleanupStack::PopAndDestroy(stringMatcher);
       
   330     TLinearOrder<MPIMItem> order(iAdapterManager->ItemOrder());
       
   331 
       
   332     RPointerArray<CPIMItem>* retArr = SortAndConvertToCPIMItemsL(order,
       
   333                                       tempArr);
       
   334 
       
   335     CleanupStack::PopAndDestroy(); // tempArr cleanup close
       
   336     return retArr;
       
   337 }
       
   338 
       
   339 RPointerArray<CPIMItem>* CPIMList::ItemsByCategoryL(
       
   340     const TDesC* aCategory)
       
   341 {
       
   342     JELOG2(EPim);
       
   343     if (!iListAdapter)
       
   344     {
       
   345         User::Leave(KErrSessionClosed);
       
   346     }
       
   347 
       
   348     // Matching items are inserted temporarily into this array for sorting
       
   349     RPointerArray<MPIMItem> tempArr(KItemArrayGranularity);
       
   350     CleanupClosePushL(tempArr);
       
   351 
       
   352     // Iterate through all items in the list
       
   353     const TInt numItems = iItems.Count();
       
   354     for (TInt itemIndex = 0; itemIndex < numItems; itemIndex++)
       
   355     {
       
   356         MPIMItem* listItem = iItems[itemIndex];
       
   357 
       
   358         // Iterate through the categories in the list item
       
   359         const CDesCArray& categories = listItem->GetCategoriesL();
       
   360 
       
   361         if (!aCategory)
       
   362         {
       
   363             // We are matching non-assigned items
       
   364             if (categories.Count() == 0)
       
   365             {
       
   366                 User::LeaveIfError(tempArr.Append(listItem));
       
   367             }
       
   368         }
       
   369         else // aCategory is non-NULL
       
   370         {
       
   371             // We are matching items assigned to given category
       
   372             // Compare case-sensitive with accents etc.
       
   373             TInt dummyPosition = 0;
       
   374             if (0 == categories.Find(*aCategory, dummyPosition,
       
   375                                      ECmpNormal))
       
   376             {
       
   377                 User::LeaveIfError(tempArr.Append(listItem));
       
   378             }
       
   379         }
       
   380     }
       
   381 
       
   382     TLinearOrder<MPIMItem> order(iAdapterManager->ItemOrder());
       
   383 
       
   384     RPointerArray<CPIMItem>* retArr = SortAndConvertToCPIMItemsL(order, tempArr);
       
   385 
       
   386     CleanupStack::PopAndDestroy(); // tempArr cleanup close
       
   387     return retArr;
       
   388 }
       
   389 
       
   390 const CDesCArray& CPIMList::GetCategoriesL()
       
   391 {
       
   392     JELOG2(EPim);
       
   393     if (!iListAdapter)
       
   394     {
       
   395         User::Leave(KErrSessionClosed); // codescanner::leave
       
   396     }
       
   397 
       
   398     return iListAdapter->GetCategoriesL(); // codescanner::leave
       
   399 }
       
   400 
       
   401 jobjectArray CPIMList::getCategories(JNIEnv* aJniEnv, jintArray aError)
       
   402 {
       
   403     JELOG2(EPim);
       
   404     const CDesCArray* categories = NULL;
       
   405     TInt error = KErrNone;
       
   406     TRAP(error, categories = &(GetCategoriesL()));
       
   407 
       
   408     SetJavaErrorCode(aJniEnv, aError, error);
       
   409 
       
   410     if (error != KErrNone)
       
   411     {
       
   412         return NULL;
       
   413     }
       
   414 
       
   415     jobjectArray javaCategories = CreateJavaStringArray(aJniEnv, *categories,
       
   416                                   EFalse); // (do not handle KPIMNullArrayElement elements specially)
       
   417 
       
   418     if (!javaCategories)
       
   419     {
       
   420         SetJavaErrorCode(aJniEnv, aError, KErrNoMemory);
       
   421     }
       
   422 
       
   423     return javaCategories;
       
   424 }
       
   425 
       
   426 TBool CPIMList::IsCategoryL(const TDesC& aCategory)
       
   427 {
       
   428     JELOG2(EPim);
       
   429     TBool retVal = EFalse;
       
   430 
       
   431     if (!iListAdapter)
       
   432     {
       
   433         User::Leave(KErrSessionClosed);
       
   434     }
       
   435 
       
   436     const CDesCArray& categories = iListAdapter->GetCategoriesL();
       
   437     TInt dummyIndex = -1;
       
   438 
       
   439     if (0 == categories.Find(aCategory, dummyIndex, ECmpNormal))
       
   440     {
       
   441         retVal = ETrue;
       
   442     }
       
   443 
       
   444     return retVal;
       
   445 }
       
   446 
       
   447 jboolean CPIMList::isCategory(jstring aCategory, JNIEnv* aJniEnv,
       
   448                               jintArray aError)
       
   449 {
       
   450     JELOG2(EPim);
       
   451     __ASSERT_DEBUG(aCategory, User::Panic(KPIMPanicCategory,
       
   452                                           EPIMPanicNullArgument));
       
   453     const JStringUtils nativeCategory(*aJniEnv, aCategory);
       
   454     TBool retVal = EFalse;
       
   455     TInt error = KErrNone;
       
   456     TRAP(error, retVal = IsCategoryL(*(static_cast<const TDesC*>(&nativeCategory))));
       
   457     SetJavaErrorCode(aJniEnv, aError, error);
       
   458     return static_cast<jboolean>(retVal);
       
   459 }
       
   460 
       
   461 void CPIMList::AddCategoryL(const TDesC& aCategory)
       
   462 {
       
   463     JELOG2(EPim);
       
   464     if (!iListAdapter)
       
   465     {
       
   466         User::Leave(KErrSessionClosed);
       
   467     }
       
   468 
       
   469     iListAdapter->AddCategoryL(aCategory);
       
   470 }
       
   471 
       
   472 void CPIMList::addCategory(jstring aCategory, JNIEnv* aJniEnv,
       
   473                            jintArray aError)
       
   474 {
       
   475     JELOG2(EPim);
       
   476     __ASSERT_DEBUG(aCategory, User::Panic(KPIMPanicCategory,
       
   477                                           EPIMPanicNullArgument));
       
   478     const JStringUtils category(*aJniEnv, aCategory);
       
   479     TInt error = KErrNone;
       
   480     TRAP(error, AddCategoryL(*(static_cast<const TDesC*>(&category))));
       
   481     SetJavaErrorCode(aJniEnv, aError, error);
       
   482 }
       
   483 
       
   484 RPointerArray<CPIMItem>* CPIMList::DeleteCategoryL(
       
   485     const TDesC& aCategory)
       
   486 {
       
   487     JELOG2(EPim);
       
   488     if (!iListAdapter)
       
   489     {
       
   490         User::Leave(KErrSessionClosed);
       
   491     }
       
   492 
       
   493     // The adapter category deletion operation does not tell whether
       
   494     // the category did exist, so we'll put it down here.
       
   495     TBool categoryExists = EFalse;
       
   496     TInt dummyPosition = 0;
       
   497     if (0 == iListAdapter->GetCategoriesL().Find(aCategory,
       
   498             dummyPosition, ECmpNormal))
       
   499     {
       
   500         categoryExists = ETrue;
       
   501     }
       
   502 
       
   503     iListAdapter->DeleteCategoryL(aCategory);
       
   504 
       
   505     // NULL return value indicates that the category was not really
       
   506     // deleted (because it did not exist).
       
   507     RPointerArray<CPIMItem>* unassignedItems = NULL;
       
   508 
       
   509     if (categoryExists)
       
   510     {
       
   511         RPointerArray<CPIMItem> categoryMembers(KItemArrayGranularity);
       
   512         CleanupClosePushL(categoryMembers);
       
   513 
       
   514         const TInt n = iItems.Count();
       
   515         for (TInt i = 0; i < n; i++)
       
   516         {
       
   517             TBool wasMember = iItems[i]->CategoryDeleted(aCategory);
       
   518             if (wasMember)
       
   519             {
       
   520                 User::LeaveIfError(categoryMembers.Append(iItems[i]));
       
   521             }
       
   522         }
       
   523 
       
   524         unassignedItems = ResolveUnassignedItemsL(categoryMembers);
       
   525         CleanupStack::PopAndDestroy(); // categoryMembers cleanup close
       
   526     }
       
   527 
       
   528     return unassignedItems;
       
   529 }
       
   530 
       
   531 jintArray CPIMList::deleteCategory(jstring aCategory, JNIEnv* aJniEnv,
       
   532                                    jintArray aError)
       
   533 {
       
   534     JELOG2(EPim);
       
   535     __ASSERT_DEBUG(aCategory, User::Panic(KPIMPanicCategory,
       
   536                                           EPIMPanicNullArgument));
       
   537 
       
   538     RPointerArray<CPIMItem>* unassignedItems = NULL;
       
   539     const JStringUtils category(*aJniEnv, aCategory);
       
   540     TInt error = KErrNone;
       
   541     TRAP(error, unassignedItems = DeleteCategoryL(
       
   542                                       *(static_cast<const TDesC*>(&category))));
       
   543     SetJavaErrorCode(aJniEnv, aError, error);
       
   544     if (error != KErrNone || !unassignedItems)
       
   545     {
       
   546         // If the operation leaved, unassignedItems was never created.
       
   547         // If no unassignedItems are present, we're OK but no return
       
   548         // value is needed.
       
   549         return NULL;
       
   550     }
       
   551 
       
   552     // We now own the array of removed items
       
   553 
       
   554     jintArray itemHandles = GetJavaItemHandles(*aJniEnv, *unassignedItems);
       
   555     unassignedItems->Close();
       
   556     delete unassignedItems;
       
   557 
       
   558     if (!itemHandles)
       
   559     {
       
   560         SetJavaErrorCode(aJniEnv, aError, KErrNoMemory);
       
   561         return NULL;
       
   562     }
       
   563     return itemHandles;
       
   564 
       
   565 }
       
   566 
       
   567 void CPIMList::RenameCategoryL(const TDesC& aCurrentCategory,
       
   568                                const TDesC& aNewCategory)
       
   569 {
       
   570     JELOG2(EPim);
       
   571     if (!iListAdapter)
       
   572     {
       
   573         User::Leave(KErrSessionClosed);
       
   574     }
       
   575 
       
   576     iListAdapter->RenameCategoryL(aCurrentCategory, aNewCategory);
       
   577 
       
   578     const TInt n = iItems.Count();
       
   579     for (TInt i = 0; i < n; i++)
       
   580     {
       
   581         iItems[i]->CategoryRenamedL(aCurrentCategory, aNewCategory);
       
   582     }
       
   583 }
       
   584 
       
   585 jint CPIMList::renameCategory(jstring aCurrentCategory,
       
   586                               jstring aNewCategory, JNIEnv* aJniEnv)
       
   587 {
       
   588     JELOG2(EPim);
       
   589     __ASSERT_DEBUG(aCurrentCategory, User::Panic(KPIMPanicCategory,
       
   590                    EPIMPanicNullArgument));
       
   591 
       
   592     __ASSERT_DEBUG(aNewCategory, User::Panic(KPIMPanicCategory,
       
   593                    EPIMPanicNullArgument));
       
   594 
       
   595     const JStringUtils currentCategory(*aJniEnv, aCurrentCategory);
       
   596     const JStringUtils newCategory(*aJniEnv, aNewCategory);
       
   597     TInt error = KErrNone;
       
   598 
       
   599     TRAP(error, RenameCategoryL(
       
   600              *(static_cast<const TDesC*>(&currentCategory)),
       
   601              *(static_cast<const TDesC*>(&newCategory))));
       
   602 
       
   603     return error;
       
   604 }
       
   605 
       
   606 jint CPIMList::maxCategories()
       
   607 {
       
   608     JELOG2(EPim);
       
   609     return iAdapterManager->MaxCategories();
       
   610 }
       
   611 
       
   612 jboolean CPIMList::isSupportedField(TPIMField aField)
       
   613 {
       
   614     JELOG2(EPim);
       
   615     TBool isSupportedField = iAdapterManager->IsSupportedField(aField);
       
   616     return static_cast<jboolean>(isSupportedField);
       
   617 }
       
   618 
       
   619 jintArray CPIMList::getSupportedFields(JNIEnv* aJniEnv)
       
   620 {
       
   621     JELOG2(EPim);
       
   622     const CArrayFix<TPIMField>* fields = NULL;
       
   623     TInt error = KErrNone;
       
   624     TRAP(error, fields = &(iAdapterManager->GetSupportedFieldsL()));
       
   625     if (error != KErrNone)
       
   626     {
       
   627         // If a leave occurred the field array was never created
       
   628         return NULL; // Error
       
   629     }
       
   630     jintArray javaFields = ConvertToJavaIntArray(*aJniEnv, *fields);
       
   631     return javaFields; // NULL indicates error
       
   632 }
       
   633 
       
   634 jboolean CPIMList::isSupportedAttribute(TPIMField aField,
       
   635                                         TPIMAttribute aAttribute)
       
   636 {
       
   637     JELOG2(EPim);
       
   638     TBool isSupportedAttribute = iAdapterManager->IsSupportedAttribute(aField, aAttribute);
       
   639     return static_cast<jboolean>(isSupportedAttribute);
       
   640 }
       
   641 
       
   642 const CArrayFix<TPIMAttribute>& CPIMList::GetSupportedAttributesL(
       
   643     TPIMField aField)
       
   644 {
       
   645     JELOG2(EPim);
       
   646     if (!iValidator.IsValidField(aField))
       
   647     {
       
   648         User::Leave(KErrArgument); // codescanner::leave
       
   649     }
       
   650 
       
   651     if (!iAdapterManager->IsSupportedField(aField))
       
   652     {
       
   653         User::Leave(KErrNotSupported); // codescanner::leave
       
   654     }
       
   655 
       
   656     return iAdapterManager->GetSupportedAttributesL(aField); // codescanner::leave
       
   657 }
       
   658 
       
   659 jintArray CPIMList::getSupportedAttributes(TPIMField aField,
       
   660         JNIEnv* aJniEnv, jintArray aError)
       
   661 {
       
   662     JELOG2(EPim);
       
   663     const CArrayFix<TPIMAttribute>* attributes = NULL;
       
   664     TInt error = KErrNone;
       
   665     TRAP(error, attributes = &(GetSupportedAttributesL(aField)));
       
   666     SetJavaErrorCode(aJniEnv, aError, error);
       
   667 
       
   668     if (error != KErrNone)
       
   669     {
       
   670         return NULL;
       
   671     }
       
   672 
       
   673     jintArray javaAttributes = ConvertToJavaIntArray(*aJniEnv,
       
   674                                *attributes);
       
   675 
       
   676     if (!javaAttributes)
       
   677     {
       
   678         SetJavaErrorCode(aJniEnv, aError, KErrNoMemory);
       
   679     }
       
   680     return javaAttributes;
       
   681 }
       
   682 
       
   683 jboolean CPIMList::isSupportedArrayElement(TPIMField aStringArrayField,
       
   684         TPIMArrayElement aArrayElement)
       
   685 {
       
   686     JELOG2(EPim);
       
   687     TBool retVal = iAdapterManager->IsSupportedArrayElement(
       
   688                        aStringArrayField, aArrayElement);
       
   689     return static_cast<jboolean>(retVal);
       
   690 }
       
   691 
       
   692 const CArrayFix<TPIMArrayElement>& CPIMList::GetSupportedArrayElementsL(
       
   693     TPIMField aStringArrayField)
       
   694 {
       
   695     JELOG2(EPim);
       
   696     if (iValidator.FieldDataType(aStringArrayField)
       
   697             != EPIMFieldStringArray)
       
   698     {
       
   699         User::Leave(KErrArgument); // codescanner::leave
       
   700     }
       
   701 
       
   702     if (!iAdapterManager->IsSupportedField(aStringArrayField))
       
   703     {
       
   704         User::Leave(KErrNotSupported); // codescanner::leave
       
   705     }
       
   706 
       
   707     return iAdapterManager->GetSupportedArrayElementsL( // codescanner::leave
       
   708                aStringArrayField);
       
   709 }
       
   710 
       
   711 jintArray CPIMList::getSupportedArrayElements(
       
   712     TPIMField aStringArrayField, JNIEnv* aJniEnv, jintArray aError)
       
   713 {
       
   714     JELOG2(EPim);
       
   715     const CArrayFix<TPIMArrayElement>* elements = NULL;
       
   716     TInt error = KErrNone;
       
   717     TRAP(error, elements = &(GetSupportedArrayElementsL(
       
   718                                  aStringArrayField)));
       
   719     SetJavaErrorCode(aJniEnv, aError, error);
       
   720 
       
   721     if (error != KErrNone)
       
   722     {
       
   723         return NULL;
       
   724     }
       
   725 
       
   726     jintArray javaElements = ConvertToJavaIntArray(*aJniEnv, *elements);
       
   727 
       
   728     if (!javaElements)
       
   729     {
       
   730         SetJavaErrorCode(aJniEnv, aError, KErrNoMemory);
       
   731     }
       
   732     return javaElements;
       
   733 }
       
   734 
       
   735 TPIMFieldDataType CPIMList::GetFieldDataTypeL(TPIMField aField)
       
   736 {
       
   737     JELOG2(EPim);
       
   738     TPIMFieldDataType fieldDataType = iValidator.FieldDataType(aField);
       
   739 
       
   740     if (fieldDataType == EPIMFieldInvalid)
       
   741     {
       
   742         User::Leave(KErrArgument);
       
   743     }
       
   744 
       
   745     if (!iAdapterManager->IsSupportedField(aField))
       
   746     {
       
   747         User::Leave(KErrNotSupported);
       
   748     }
       
   749 
       
   750     return fieldDataType;
       
   751 }
       
   752 
       
   753 jint CPIMList::getFieldDataType(TPIMField aField, JNIEnv* aJniEnv,
       
   754                                 jintArray aError)
       
   755 {
       
   756     JELOG2(EPim);
       
   757     TPIMFieldDataType fieldDataType = EPIMFieldInvalid;
       
   758     TInt error = KErrNone;
       
   759     TRAP(error, fieldDataType = GetFieldDataTypeL(aField));
       
   760     SetJavaErrorCode(aJniEnv, aError, error);
       
   761     return fieldDataType;
       
   762 }
       
   763 
       
   764 HBufC* CPIMList::GetFieldLabelL(TPIMField aField)
       
   765 {
       
   766     JELOG2(EPim);
       
   767     if (!iValidator.IsValidField(aField))
       
   768     {
       
   769         User::Leave(KErrArgument);
       
   770     }
       
   771 
       
   772     if (!iAdapterManager->IsSupportedField(aField))
       
   773     {
       
   774         User::Leave(KErrNotSupported);
       
   775     }
       
   776 
       
   777     return iLocalizationData->GetFieldLabelL(aField);
       
   778 }
       
   779 
       
   780 HBufC* CPIMList::GetAttributeLabelL(TPIMAttribute aAttribute)
       
   781 {
       
   782     JELOG2(EPim);
       
   783     if (!IS_SINGLE_BIT(aAttribute) || !(iValidator.ValidAttributes()& aAttribute))
       
   784     {
       
   785         User::Leave(KErrArgument);
       
   786     }
       
   787 
       
   788     if (!(iAdapterManager->GetAllSupportedAttributesCombined() & aAttribute))
       
   789     {
       
   790         User::Leave(KErrNotSupported);
       
   791     }
       
   792 
       
   793     return iLocalizationData->GetAttributeLabelL(aAttribute);
       
   794 }
       
   795 
       
   796 HBufC* CPIMList::GetArrayElementLabelL(TPIMField aStringArrayField,
       
   797                                        TPIMArrayElement aArrayElement)
       
   798 {
       
   799     JELOG2(EPim);
       
   800     if ((!iValidator.IsValidField(aStringArrayField)) || (aArrayElement < 0)
       
   801             || (aArrayElement >= iValidator.NumElementsL(aStringArrayField)))
       
   802     {
       
   803         User::Leave(KErrArgument);
       
   804     }
       
   805 
       
   806     if (!iAdapterManager->IsSupportedArrayElement(aStringArrayField,
       
   807             aArrayElement))
       
   808     {
       
   809         User::Leave(KErrNotSupported);
       
   810     }
       
   811 
       
   812     return iLocalizationData->GetArrayElementLabelL(aStringArrayField,
       
   813             aArrayElement);
       
   814 }
       
   815 
       
   816 TInt CPIMList::MaxValuesL(TPIMField aField)
       
   817 {
       
   818     JELOG2(EPim);
       
   819     if (!iValidator.IsValidField(aField))
       
   820     {
       
   821         User::Leave(KErrArgument);
       
   822     }
       
   823 
       
   824     return iAdapterManager->MaxValues(aField);
       
   825 }
       
   826 
       
   827 jint CPIMList::maxValues(TPIMField aField, JNIEnv* aJniEnv,
       
   828                          jintArray aError)
       
   829 {
       
   830     JELOG2(EPim);
       
   831     jint maxVal = 0;
       
   832     TInt error = KErrNone;
       
   833     TRAP(error, maxVal = MaxValuesL(aField));
       
   834     SetJavaErrorCode(aJniEnv, aError, error);
       
   835     return maxVal;
       
   836 }
       
   837 
       
   838 int CPIMList::StringArraySizeL(TPIMField aStringArrayField)
       
   839 {
       
   840     JELOG2(EPim);
       
   841     if (iValidator.FieldDataType(aStringArrayField)
       
   842             != EPIMFieldStringArray)
       
   843     {
       
   844         User::Leave(KErrArgument);
       
   845     }
       
   846 
       
   847     return iValidator.NumElementsL(aStringArrayField);
       
   848 }
       
   849 
       
   850 int CPIMList::stringArraySize(TPIMField aStringArrayField,
       
   851                               jintArray aError, JNIEnv* aJniEnv)
       
   852 {
       
   853     JELOG2(EPim);
       
   854     TInt error = KErrNone;
       
   855     int retVal = 0;
       
   856     TRAP(error, retVal = StringArraySizeL(aStringArrayField));
       
   857 
       
   858     SetJavaErrorCode(aJniEnv, aError, error);
       
   859     return retVal;
       
   860 }
       
   861 
       
   862 RPointerArray<CPIMItem>* CPIMList::UpdateListL(CPIMItem* aMatchingItem)
       
   863 {
       
   864     JELOG2(EPim);
       
   865     if (!iListAdapter)
       
   866     {
       
   867         User::Leave(KErrSessionClosed);
       
   868     }
       
   869 
       
   870     RPointerArray<CPIMItem> tempNewItems(KItemArrayGranularity);
       
   871     CleanupClosePushL(tempNewItems);
       
   872 
       
   873     RPointerArray<CPIMItem> tempRemovedItems(KItemArrayGranularity);
       
   874     CleanupClosePushL(tempRemovedItems);
       
   875 
       
   876     MPIMListAdapter::TExternalItemChangeClass changeClass =
       
   877         iListAdapter->IsItemsExternallyModified();
       
   878 
       
   879     if (changeClass == MPIMListAdapter::EExternalChangesNone)
       
   880     {
       
   881         // No changes, skip.
       
   882     }
       
   883     else if (changeClass == MPIMListAdapter::EExternalChangesMinor)
       
   884     {
       
   885         HandleMinorItemChangesL(tempNewItems, tempRemovedItems,
       
   886                                 aMatchingItem);
       
   887     }
       
   888     else if (changeClass == MPIMListAdapter::EExternalChangesMajor)
       
   889     {
       
   890         HandleMajorItemChangesL(tempNewItems, tempRemovedItems,
       
   891                                 aMatchingItem);
       
   892     }
       
   893     else
       
   894     {
       
   895         // Should never happen
       
   896         User::Panic(KPIMPanicCategory,
       
   897                     EPIMPanicInvalidNativeChangeClass);
       
   898     }
       
   899 
       
   900     UpdateCategoriesL();
       
   901 
       
   902     // Return value
       
   903     RPointerArray<CPIMItem> * newAndRemovedItems =
       
   904         new(ELeave) RPointerArray<CPIMItem> (KItemArrayGranularity);
       
   905 
       
   906     // The array object needs to be pushed for deletion and closing
       
   907     // separately.
       
   908     CleanupStack::PushL(newAndRemovedItems);
       
   909     CleanupClosePushL(*newAndRemovedItems);
       
   910 
       
   911     // Copy the pointers to new and removed items to the result array.
       
   912     // First go the new items, then NULL, and then removed items.
       
   913 
       
   914     TInt i = 0; // reused iterator
       
   915     const TInt numNewItems = tempNewItems.Count();
       
   916     for (i = 0; i < numNewItems; i++)
       
   917     {
       
   918         User::LeaveIfError(newAndRemovedItems->Append(tempNewItems[i]));
       
   919     }
       
   920 
       
   921     // Add boundary element
       
   922     User::LeaveIfError(newAndRemovedItems->Append(NULL));
       
   923 
       
   924     const TInt numRemovedItems = tempRemovedItems.Count();
       
   925     for (i = 0; i < numRemovedItems; i++)
       
   926     {
       
   927         User::LeaveIfError(newAndRemovedItems->Append(
       
   928                                tempRemovedItems[i]));
       
   929     }
       
   930 
       
   931     CleanupStack::Pop(); // newAndRemovedItems cleanup close
       
   932     CleanupStack::Pop(newAndRemovedItems);
       
   933 
       
   934     CleanupStack::PopAndDestroy(); // tempRemovedItems cleanup close
       
   935     CleanupStack::PopAndDestroy(); // tempNewItems cleanup close
       
   936 
       
   937     return newAndRemovedItems;
       
   938 }
       
   939 
       
   940 TInt CPIMList::FindItemByItemID(const TPIMItemID& aItemId)
       
   941 {
       
   942     JELOG2(EPim);
       
   943     // Any RPointerArray.Find() variant cannot be used because we're
       
   944     // matching with just an Item ID, not another item.
       
   945 
       
   946     const TInt n = iItems.Count();
       
   947     for (TInt i = 0; i < n; i++)
       
   948     {
       
   949         if (iItems[i]->GetId() == aItemId)
       
   950         {
       
   951             return i;
       
   952         }
       
   953     }
       
   954 
       
   955     return KErrNotFound;
       
   956 }
       
   957 
       
   958 RPointerArray<CPIMItem>* CPIMList::SortAndConvertToCPIMItemsL(
       
   959     TLinearOrder<MPIMItem> aOrder,
       
   960     RPointerArray<MPIMItem>& aSourceArray)
       
   961 {
       
   962     JELOG2(EPim);
       
   963     aSourceArray.Sort(aOrder);
       
   964 
       
   965     RPointerArray<CPIMItem> * retArr = new(ELeave) RPointerArray<
       
   966     CPIMItem> (KItemArrayGranularity);
       
   967 
       
   968     CleanupStack::PushL(retArr);
       
   969     CleanupClosePushL(*retArr);
       
   970 
       
   971     const TInt n = aSourceArray.Count();
       
   972     for (TInt i = 0; i < n; i++)
       
   973     {
       
   974         User::LeaveIfError(retArr->Append(
       
   975                                static_cast<CPIMItem*>(aSourceArray[i])));
       
   976     }
       
   977 
       
   978     CleanupStack::Pop(); // *retArr
       
   979     CleanupStack::Pop(retArr);
       
   980     return retArr;
       
   981 }
       
   982 
       
   983 void CPIMList::HandleMinorItemChangesL(
       
   984     RPointerArray<CPIMItem>& aTempNewItems,
       
   985     RPointerArray<CPIMItem>& aTempRemovedItems, CPIMItem* aMatchingItem)
       
   986 {
       
   987     JELOG2(EPim);
       
   988     RPointerArray<CPIMItemStateChange>* itemChanges =
       
   989         iListAdapter->GetExternalItemModificationsL();
       
   990 
       
   991     __ASSERT_DEBUG(itemChanges, User::Panic(KPIMPanicCategory,
       
   992                                             EPIMPanicUnexpectedNullExternalChangeList));
       
   993 
       
   994     __ASSERT_ALWAYS(itemChanges, User::Leave(KErrCorrupt));
       
   995 
       
   996     CleanupStack::PushL(itemChanges);
       
   997     CleanupResetAndDestroyPushL(*itemChanges);
       
   998 
       
   999     const TInt n = itemChanges->Count();
       
  1000     for (TInt i = 0; i < n; i++)
       
  1001     {
       
  1002         const CPIMItemStateChange& itemChange = *(*itemChanges)[i];
       
  1003         switch (itemChange.ChangeType())
       
  1004         {
       
  1005         case EPIMExternalChangeNew:
       
  1006         {
       
  1007             // Check that the item is really new and not e.g. resulting from
       
  1008             // our own action.
       
  1009             if (KErrNotFound == FindItemByItemID(itemChange.ItemID()))
       
  1010             {
       
  1011                 HandleItemChangeNewL(itemChange.ItemID(),
       
  1012                                      aTempNewItems, aMatchingItem);
       
  1013             }
       
  1014             break;
       
  1015         }
       
  1016 
       
  1017         case EPIMExternalChangeModified:
       
  1018         {
       
  1019             // Find the index. The item should be present when this happens
       
  1020             const TInt itemIndex =
       
  1021                 FindItemByItemID(itemChange.ItemID());
       
  1022 
       
  1023             __ASSERT_DEBUG((itemIndex != -1), User::Panic(
       
  1024                                KPIMPanicCategory,
       
  1025                                EPIMPanicExternalChangeUpdatingNonExistentItem));
       
  1026 
       
  1027             if (itemIndex == KErrNotFound)
       
  1028             {
       
  1029                 User::Leave(KErrCorrupt);
       
  1030             }
       
  1031 
       
  1032             CPIMItem* item = iItems[itemIndex];
       
  1033             HandleItemChangeModifiedL(*item);
       
  1034 
       
  1035             break;
       
  1036         }
       
  1037 
       
  1038         case EPIMExternalChangeRemoved:
       
  1039         {
       
  1040             // Find the item index by Item ID and remove only if it really
       
  1041             // is present (and not e.g. already removed by us).
       
  1042             const TInt itemIndex =
       
  1043                 FindItemByItemID(itemChange.ItemID());
       
  1044             if (itemIndex != KErrNotFound)
       
  1045             {
       
  1046                 HandleItemChangeRemovedL(itemIndex, aTempRemovedItems);
       
  1047             }
       
  1048             break;
       
  1049         }
       
  1050 
       
  1051         default:
       
  1052         {
       
  1053             User::Panic(KPIMPanicCategory,
       
  1054                         EPIMPanicInvalidNativeChangeType);
       
  1055             break;
       
  1056         }
       
  1057         }
       
  1058     }
       
  1059 
       
  1060     CleanupStack::PopAndDestroy(2, itemChanges);
       
  1061 
       
  1062     // Refresh any items that have been modified from the Java side.
       
  1063     // This is done after getting the removed and modified items above
       
  1064     // because we don't want to try to update removed or already
       
  1065     // updated items. However, if such situations occur, we just
       
  1066     // ignore them at this point and handle them during next update.
       
  1067     RefreshModifiedItemsL();
       
  1068 }
       
  1069 
       
  1070 void CPIMList::HandleMajorItemChangesL(
       
  1071     RPointerArray<CPIMItem>& aTempNewItems,
       
  1072     RPointerArray<CPIMItem>& aTempRemovedItems, CPIMItem* aMatchingItem)
       
  1073 {
       
  1074     JELOG2(EPim);
       
  1075     // The situation here is that the underlying list adapter
       
  1076     // cannot classify the changes occurred in the native database.
       
  1077     // We need to refresh the whole set of items and try to figure
       
  1078     // out which entries are new and which entries have been removed.
       
  1079 
       
  1080     // At the time of writing handles to both new and removed native
       
  1081     // side items are passed to the Java side in return. We want to
       
  1082     // do the major update so that it does not differ in any way for
       
  1083     // that mechanism. We also want to be memory-efficient rather than
       
  1084     // fast, so we'll reuse and refresh the existing items that still
       
  1085     // have their counterparts in the database and only create the
       
  1086     // truely new items. Removed entries will, of course, be removed
       
  1087     // from the framework, too.
       
  1088 
       
  1089     RPointerArray<CPIMItemStateChange>* itemChanges =
       
  1090         iListAdapter->GetExternalItemModificationsL();
       
  1091 
       
  1092     __ASSERT_DEBUG(itemChanges, User::Panic(KPIMPanicCategory,
       
  1093                                             EPIMPanicUnexpectedNullExternalChangeList));
       
  1094 
       
  1095     if (!itemChanges)
       
  1096     {
       
  1097         // No changes (although there should be some!)
       
  1098         User::Leave(KErrCorrupt);
       
  1099     }
       
  1100 
       
  1101     CleanupStack::PushL(itemChanges);
       
  1102     CleanupResetAndDestroyPushL(*itemChanges);
       
  1103 
       
  1104     // Iterate through the item list. Some of the items will be removed
       
  1105     // during the iteration, so the item count must be resolved on
       
  1106     // every iteration.
       
  1107     TInt itemIndex = 0;
       
  1108     while (itemIndex < iItems.Count())
       
  1109     {
       
  1110         TPIMItemID itemId = iItems[itemIndex]->GetId();
       
  1111 
       
  1112         TBool exists = EFalse;
       
  1113 
       
  1114         // Iterate through the change list. One of the changes may be
       
  1115         // removed during the iteration.
       
  1116         for (TInt changeIndex = 0; changeIndex < itemChanges->Count(); changeIndex++)
       
  1117         {
       
  1118             CPIMItemStateChange* itemChange =
       
  1119                 (*itemChanges)[changeIndex];
       
  1120 
       
  1121             const TPIMItemID changedItemId = itemChange->ItemID();
       
  1122 
       
  1123             if (itemId == changedItemId)
       
  1124             {
       
  1125                 // Exists already - update
       
  1126                 exists = ETrue;
       
  1127                 HandleItemChangeModifiedL(*(iItems[itemIndex]));
       
  1128 
       
  1129                 // This change has been handled
       
  1130                 delete itemChange;
       
  1131                 itemChanges->Remove(changeIndex);
       
  1132 
       
  1133                 // Next item
       
  1134                 itemIndex++;
       
  1135                 break; // out of the change loop
       
  1136             }
       
  1137         }
       
  1138 
       
  1139         if (!exists)
       
  1140         {
       
  1141             // The item didn't match a change entry - remove.
       
  1142             // The item index used in the loop must not be updated, because
       
  1143             // After the following operation the index will refer to the
       
  1144             // next item.
       
  1145             HandleItemChangeRemovedL(itemIndex, aTempRemovedItems);
       
  1146         }
       
  1147     }
       
  1148 
       
  1149     // Now the changes in the change list are truely new entries
       
  1150     for (TInt changeIndex = 0; changeIndex < itemChanges->Count(); changeIndex++)
       
  1151     {
       
  1152         const CPIMItemStateChange& itemChange =
       
  1153             *(*itemChanges)[changeIndex];
       
  1154 
       
  1155         const TPIMItemID newItemId = itemChange.ItemID();
       
  1156         HandleItemChangeNewL(newItemId, aTempNewItems, aMatchingItem);
       
  1157     }
       
  1158 
       
  1159     CleanupStack::PopAndDestroy(2, itemChanges);
       
  1160 }
       
  1161 
       
  1162 void CPIMList::HandleItemChangeNewL(const TPIMItemID aNewItemId,
       
  1163                                     RPointerArray<CPIMItem>& aTempNewItems, CPIMItem* aMatchingItem)
       
  1164 {
       
  1165     JELOG2(EPim);
       
  1166     // Create new item
       
  1167     CPIMItem* newItem = NULL;
       
  1168     TRAPD(errCreateItem, newItem = DoCreateItemL(aNewItemId,
       
  1169                                    aMatchingItem));
       
  1170 
       
  1171     if (errCreateItem == KErrNotFound)
       
  1172     {
       
  1173         // The item was not in the database. The case is
       
  1174         // probably that the item was created and removed
       
  1175         // after last update. Skip.
       
  1176         return;
       
  1177     }
       
  1178     else
       
  1179     {
       
  1180         User::LeaveIfError(errCreateItem);
       
  1181     }
       
  1182 
       
  1183     // OK
       
  1184     newItem->SetModified(EFalse);
       
  1185     CleanupStack::PushL(newItem);
       
  1186     User::LeaveIfError(iItems.Append(newItem));
       
  1187     CleanupStack::Pop(newItem);
       
  1188 
       
  1189     // Add to list of new items
       
  1190     TInt errAddToNewItems = aTempNewItems.Append(newItem);
       
  1191     if (errAddToNewItems != KErrNone)
       
  1192     {
       
  1193         iItems.Remove(iItems.Find(newItem));
       
  1194         delete newItem;
       
  1195         User::Leave(errAddToNewItems);
       
  1196     }
       
  1197 }
       
  1198 
       
  1199 void CPIMList::HandleItemChangeModifiedL(CPIMItem& aModifiedItem)
       
  1200 {
       
  1201     JELOG2(EPim);
       
  1202     // Any Java-originated modifications will be discarded.
       
  1203     TRAPD(errUpdateItem, DoUpdateItemL(aModifiedItem));
       
  1204 
       
  1205     if (errUpdateItem == KErrNotFound)
       
  1206     {
       
  1207         // The item was not in the database. The case is
       
  1208         // probably that the item was changed and removed
       
  1209         // after last update. Let's pretend that the item
       
  1210         // is up-to-date and skip it.
       
  1211         aModifiedItem.SetModified(EFalse);
       
  1212         return;
       
  1213     }
       
  1214     else
       
  1215     {
       
  1216         User::LeaveIfError(errUpdateItem);
       
  1217     }
       
  1218 
       
  1219     // OK
       
  1220     aModifiedItem.SetModified(EFalse);
       
  1221 }
       
  1222 
       
  1223 void CPIMList::HandleItemChangeRemovedL(TInt aRemovedItemIndex,
       
  1224                                         RPointerArray<CPIMItem>& aTempRemovedItems)
       
  1225 {
       
  1226     JELOG2(EPim);
       
  1227     CPIMItem* removedItem = iItems[aRemovedItemIndex];
       
  1228 
       
  1229     // Add to list of removed items
       
  1230     TInt errAddToRemovedItems = aTempRemovedItems.Append(removedItem);
       
  1231 
       
  1232     if (errAddToRemovedItems != KErrNone)
       
  1233     {
       
  1234         User::Leave(KErrCorrupt);
       
  1235     }
       
  1236 
       
  1237     // Remove from item list and remove adapter association
       
  1238     iItems.Remove(aRemovedItemIndex);
       
  1239     removedItem->RemoveAdapterAssociation();
       
  1240 }
       
  1241 
       
  1242 void CPIMList::RefreshModifiedItemsL()
       
  1243 {
       
  1244     JELOG2(EPim);
       
  1245     const TInt numItems = iItems.Count();
       
  1246     for (TInt itemIndex = 0; itemIndex < numItems; itemIndex++)
       
  1247     {
       
  1248         CPIMItem& item = *(iItems[itemIndex]);
       
  1249         if (item.isModified())
       
  1250         {
       
  1251             TRAPD(errUpdate, DoUpdateItemL(item));
       
  1252 
       
  1253             // If the update succeeds, we're OK. If the entry is not
       
  1254             // found, we'll pretend that the entry is present until
       
  1255             // next update (or failing commit). In other error,
       
  1256             // leave.
       
  1257             if (errUpdate == KErrNone || errUpdate == KErrNotFound)
       
  1258             {
       
  1259                 item.SetModified(EFalse);
       
  1260             }
       
  1261             else
       
  1262             {
       
  1263                 User::Leave(errUpdate);
       
  1264             }
       
  1265         }
       
  1266     }
       
  1267 }
       
  1268 
       
  1269 void CPIMList::UpdateCategoriesL()
       
  1270 {
       
  1271     JELOG2(EPim);
       
  1272     if (!iListAdapter)
       
  1273     {
       
  1274         User::Leave(KErrSessionClosed);
       
  1275     }
       
  1276 
       
  1277     RPointerArray<CPIMCategoryStateChange>* categoryChanges =
       
  1278         iListAdapter->GetExternalCategoryModificationsL();
       
  1279 
       
  1280     if (!categoryChanges)
       
  1281     {
       
  1282         // Nothing to do
       
  1283         return;
       
  1284     }
       
  1285 
       
  1286     CleanupStack::PushL(categoryChanges);
       
  1287     CleanupResetAndDestroyPushL(*categoryChanges);
       
  1288 
       
  1289     const TInt n = categoryChanges->Count();
       
  1290     for (TInt i = 0; i < n; i++)
       
  1291     {
       
  1292         const CPIMCategoryStateChange& change = *(*categoryChanges)[i];
       
  1293         const TPIMExternalChangeType changeType = change.ChangeType();
       
  1294 
       
  1295         switch (changeType)
       
  1296         {
       
  1297         case EPIMExternalChangeNew:
       
  1298         {
       
  1299             // Nothing to do.
       
  1300             break;
       
  1301         }
       
  1302 
       
  1303         case EPIMExternalChangeModified:
       
  1304         {
       
  1305             // Update items
       
  1306             const TInt numItems = iItems.Count();
       
  1307             for (TInt itemIndex = 0; itemIndex < numItems; itemIndex++)
       
  1308             {
       
  1309                 iItems[itemIndex]->CategoryRenamedL(change.Category(),
       
  1310                                                     change.NewCategoryNameL());
       
  1311             }
       
  1312             break;
       
  1313         }
       
  1314 
       
  1315         case EPIMExternalChangeRemoved:
       
  1316         {
       
  1317             // Update items
       
  1318             const TInt numItems = iItems.Count();
       
  1319             for (TInt itemIndex = 0; itemIndex < numItems; itemIndex++)
       
  1320             {
       
  1321                 iItems[itemIndex]->CategoryDeleted(change.Category());
       
  1322             }
       
  1323             break;
       
  1324         }
       
  1325 
       
  1326         default:
       
  1327         {
       
  1328             // Should never happen
       
  1329             User::Panic(KPIMPanicCategory,
       
  1330                         EPIMPanicInvalidNativeChangeClass);
       
  1331         }
       
  1332         }
       
  1333     }
       
  1334 
       
  1335     CleanupStack::PopAndDestroy(); // categoryChanges cleanup close
       
  1336     CleanupStack::PopAndDestroy(categoryChanges);
       
  1337 }
       
  1338 
       
  1339 RPointerArray<CPIMItem>* CPIMList::ResolveUnassignedItemsL(
       
  1340     RPointerArray<CPIMItem>& aSearchedItems)
       
  1341 {
       
  1342     JELOG2(EPim);
       
  1343     RPointerArray<CPIMItem>* unassignedItems = new(ELeave) RPointerArray<
       
  1344     CPIMItem> (KItemArrayGranularity);
       
  1345 
       
  1346     CleanupStack::PushL(unassignedItems);
       
  1347     CleanupClosePushL(*unassignedItems);
       
  1348 
       
  1349     // Find out the items that do not belong to any category and add
       
  1350     // them to the returned array.
       
  1351     const TInt n = aSearchedItems.Count();
       
  1352     for (TInt i = 0; i < n; i++)
       
  1353     {
       
  1354         if (aSearchedItems[i]->GetCategoriesL().Count() == 0)
       
  1355         {
       
  1356             CPIMItem* unassignedItem = aSearchedItems[i];
       
  1357             User::LeaveIfError(unassignedItems->Append(unassignedItem));
       
  1358         }
       
  1359     }
       
  1360 
       
  1361     CleanupStack::Pop(); // unassignedItems cleanup close
       
  1362     CleanupStack::Pop(unassignedItems);
       
  1363     return unassignedItems;
       
  1364 }
       
  1365 
       
  1366 jintArray CPIMList::updateList(JNIEnv* aJniEnv,
       
  1367                                pimbaseitem* aMatchingItem)
       
  1368 {
       
  1369     JELOG2(EPim);
       
  1370     TInt error = KErrNone;
       
  1371     jintArray itemHandles = NULL;
       
  1372     TRAP(error,
       
  1373     {
       
  1374         CPIMItem* matchingItem = static_cast<CPIMItem*>(aMatchingItem);
       
  1375         RPointerArray< CPIMItem>* newAndRemovedItems =
       
  1376             UpdateListL(matchingItem);
       
  1377         // We now own the array
       
  1378         CleanupStack::PushL(newAndRemovedItems);
       
  1379         CleanupClosePushL(*newAndRemovedItems);
       
  1380         const TInt numItems = newAndRemovedItems->Count();
       
  1381 
       
  1382         // Make a temporary integer array which we can push to cleanup stack
       
  1383         TInt* tempElems = new(ELeave) TInt[ numItems ];
       
  1384         CleanupArrayDeletePushL(tempElems);
       
  1385 
       
  1386         // Iterate through the item array in two parts.
       
  1387         // First make and set handles to the new items
       
  1388         // then get the handles of the removed items.
       
  1389         // Put all handles to the result Java int array, separated by
       
  1390         // a zero.
       
  1391         TInt i = 0; // reused iterator
       
  1392 
       
  1393 
       
  1394         for (i = 0; i < numItems; i++)
       
  1395         {
       
  1396             pimbaseitem* item = (*newAndRemovedItems)[ i ];
       
  1397 
       
  1398             if (!item)
       
  1399             {
       
  1400                 // Reached the boundary; the next item is the first
       
  1401                 // removed item. Index variable is reused.
       
  1402                 break;
       
  1403             }
       
  1404 
       
  1405             TInt newItemHandle = reinterpret_cast<int>(item);
       
  1406 
       
  1407             tempElems[ i ] = newItemHandle;
       
  1408         }
       
  1409 
       
  1410         // The boundary element
       
  1411         tempElems[ i++ ] = 0; // boundary mark
       
  1412 
       
  1413         // For each removed item, get its JNI handle and append it to the
       
  1414         // result array.
       
  1415         for (/* reuse i with its current value */; i < numItems; i++)
       
  1416         {
       
  1417             pimbaseitem* item = (*newAndRemovedItems)[ i ];
       
  1418             tempElems[ i ] = reinterpret_cast<int>(item);
       
  1419         }
       
  1420 
       
  1421         // Create the result (Java) array and copy the handles in it
       
  1422         itemHandles = aJniEnv->NewIntArray(numItems);
       
  1423         if (!itemHandles)
       
  1424         {
       
  1425             User::Leave(KErrNoMemory);   // codescanner::leave
       
  1426         }
       
  1427 
       
  1428         aJniEnv->SetIntArrayRegion(itemHandles, 0, numItems, tempElems);
       
  1429         CleanupStack::PopAndDestroy(tempElems);
       
  1430 
       
  1431         CleanupStack::Pop(); // newAndRemovedItems cleanup close
       
  1432         CleanupStack::PopAndDestroy(newAndRemovedItems);
       
  1433 
       
  1434     }
       
  1435         );
       
  1436     if (error != KErrNone)
       
  1437         throw error;
       
  1438     return itemHandles;
       
  1439 }
       
  1440 
       
  1441 //  End of File