emailuis/emailui/src/FreestyleEmailUiMailListModel.cpp
changeset 0 8466d47a6819
child 1 12c456ceeff2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emailuis/emailui/src/FreestyleEmailUiMailListModel.cpp	Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,573 @@
+/*
+* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  FreestyleEmailUi double line list model and model item implementation.
+*
+*/
+
+
+// SYSTEM INCLUDES
+//<cmail>
+#include "emailtrace.h"
+#include "CFSMailMessage.h"
+//</cmail>
+
+
+// INTERNAL INCLUDES
+#include "FreestyleEmailUiAppui.h"
+#include "FreestyleEmailUiMailListModel.h"
+#include "FreestyleEmailUiUtilities.h"
+
+
+// MODEL ITEM CONSTRUCTION
+CFSEmailUiMailListModelItem* CFSEmailUiMailListModelItem::NewL( CFSMailMessage* aMessagePtr,
+																	TModelItemType aModelItemtype )
+    {
+    FUNC_LOG;
+    CFSEmailUiMailListModelItem* self = CFSEmailUiMailListModelItem::NewLC( aMessagePtr, aModelItemtype );
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CFSEmailUiMailListModelItem* CFSEmailUiMailListModelItem::NewLC( CFSMailMessage* aMessagePtr,
+																	TModelItemType aModelItemtype )
+	{
+    FUNC_LOG;
+    CFSEmailUiMailListModelItem* self = new (ELeave) CFSEmailUiMailListModelItem( aMessagePtr, aModelItemtype );
+    CleanupStack::PushL(self);
+    return self;
+	}
+
+CFSEmailUiMailListModelItem::CFSEmailUiMailListModelItem( CFSMailMessage* aMessagePtr,
+															  TModelItemType aModelItemtype ) 
+   	:iMessagePtr( aMessagePtr ),
+   	iModelItemType( aModelItemtype ),
+   	iSeparatorText( 0 ),
+   	iFsTreeListId( 0 )
+    {
+    FUNC_LOG;
+    }
+
+CFSEmailUiMailListModelItem::~CFSEmailUiMailListModelItem() 
+    {
+    FUNC_LOG;
+   	delete iSeparatorText;
+   	if ( iModelItemType == ETypeMailItem )
+   	    {
+        delete iMessagePtr;
+   	    }
+   	else
+   	    {
+   	    // In case of separator item, the message is not owned. This is just a pointer
+   	    // to the first message belonging under this separator. The ownership is on the
+   	    // next mail item.
+   	    iMessagePtr = NULL;
+   	    }
+    }
+
+
+void CFSEmailUiMailListModelItem::SetSeparatorTextL( const TDesC& aSeparatorText )
+    {
+    FUNC_LOG;
+    delete iSeparatorText;
+    iSeparatorText = NULL;
+    iSeparatorText = aSeparatorText.AllocL();
+    }
+	
+
+
+
+//MODEL CLASS CONSTRUCTION
+CFSEmailUiMailListModel* CFSEmailUiMailListModel::NewL( CFreestyleEmailUiAppUi* aAppUi, TBool aSearchList )
+    {
+    FUNC_LOG;
+    CFSEmailUiMailListModel* self = CFSEmailUiMailListModel::NewLC( aAppUi, aSearchList );
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CFSEmailUiMailListModel* CFSEmailUiMailListModel::NewLC( CFreestyleEmailUiAppUi* aAppUi, TBool aSearchList )
+    {
+    FUNC_LOG;
+    CFSEmailUiMailListModel* self = new (ELeave) CFSEmailUiMailListModel( aAppUi );
+    CleanupStack::PushL(self);
+    self->ConstructL( aSearchList );
+    return self;
+    }
+
+void CFSEmailUiMailListModel::ConstructL( TBool aSearchList )
+    {
+    FUNC_LOG;
+    // set default sort criteria
+    iSortCriteria.iField = EFSMailSortByDate;
+    iSortCriteria.iOrder = EFSMailDescending;
+    
+    if ( !aSearchList )
+        {
+        // Set TLS pointer to point ourselves. This is needed to access our
+        // data from static (find/sort) functions.
+        TInt err = UserSvr::DllSetTls( KTlsHandleMailListModel, this );
+        }
+    }
+ 
+CFSEmailUiMailListModel::CFSEmailUiMailListModel( CFreestyleEmailUiAppUi* aAppUi ) 
+	: iAppUi( aAppUi )
+    {
+    FUNC_LOG;
+    }
+	
+CFSEmailUiMailListModel::~CFSEmailUiMailListModel()
+    {
+    FUNC_LOG;
+	iItems.ResetAndDestroy();
+    }
+
+void CFSEmailUiMailListModel::AppendL(MFSListModelItem* aItem)
+    {
+    FUNC_LOG;
+	TInt err;
+	CFSEmailUiMailListModelItem* newItem = static_cast< CFSEmailUiMailListModelItem* >(aItem);
+	err = iItems.Append( newItem );	
+	User::LeaveIfError(err);
+	
+	// If mail item was added as first child of a separator, the message pointer
+	// of the separator has to be reset.
+	TInt insertionPoint = iItems.Count()-1; 
+    if ( insertionPoint > 0 &&
+         newItem->ModelItemType() == ETypeMailItem &&
+         iItems[insertionPoint-1]->ModelItemType() == ETypeSeparator )
+        {
+        iItems[insertionPoint-1]->SetMessagePtr( &newItem->MessagePtr() );
+        }
+    }
+	
+void CFSEmailUiMailListModel::InsertL( MFSListModelItem* aItem, TInt aIndex )
+    {
+    FUNC_LOG;
+	TInt err;	
+    CFSEmailUiMailListModelItem* newItem = static_cast< CFSEmailUiMailListModelItem* >(aItem);
+	err = iItems.Insert( newItem, aIndex);	
+	User::LeaveIfError(err);
+
+    // If mail item was added as first child of a separator, the message pointer
+    // of the separator has to be reset.
+    if ( aIndex > 0 &&
+         newItem->ModelItemType() == ETypeMailItem &&
+         iItems[aIndex-1]->ModelItemType() == ETypeSeparator )
+        {
+        iItems[aIndex-1]->SetMessagePtr( &newItem->MessagePtr() );
+        }
+    }
+
+void CFSEmailUiMailListModel::RemoveAndDestroy(TInt aIndex)
+    {
+    FUNC_LOG;
+	delete Item(aIndex);
+	iItems.Remove(aIndex);
+	iItems.Compress();
+	
+	// If the removed item was the first child of a preceeding node item, then the message
+	// pointer in the node item has to be updated.
+	if ( aIndex > 0 && iItems[aIndex-1]->ModelItemType() == ETypeSeparator )
+	    {
+	    if ( aIndex < iItems.Count() && iItems[aIndex]->ModelItemType() == ETypeMailItem )
+	        {
+	        iItems[aIndex-1]->SetMessagePtr( &iItems[aIndex]->MessagePtr() );
+	        }
+	    else
+	        {
+	        iItems[aIndex-1]->SetMessagePtr( NULL );
+	        }
+	    }
+    }
+
+MFSListModelItem* CFSEmailUiMailListModel::Item( TInt aIndex )
+	{
+    FUNC_LOG;
+	TInt numInList = iItems.Count();
+	if ( aIndex < 0 || aIndex >= numInList )
+	   {
+	   return NULL;
+       }	
+	return iItems[aIndex];
+	}
+
+const MFSListModelItem* CFSEmailUiMailListModel::Item( TInt aIndex ) const
+    {
+    FUNC_LOG;
+    TInt numInList = iItems.Count();
+    if ( aIndex < 0 || aIndex >= numInList )
+       {
+       return NULL;
+       }
+    return iItems[aIndex];
+    }
+
+TInt CFSEmailUiMailListModel::Count() const
+    {
+    FUNC_LOG;
+	return iItems.Count();
+    }
+
+CFreestyleEmailUiAppUi* CFSEmailUiMailListModel::AppUi()
+	{
+    FUNC_LOG;
+	return iAppUi;
+	}
+
+void CFSEmailUiMailListModel::SetSortCriteria( TFSMailSortCriteria aSortCriteria )
+    {
+    FUNC_LOG;
+    iSortCriteria = aSortCriteria;
+    }
+
+TFSMailSortCriteria CFSEmailUiMailListModel::SortCriteria()
+    {
+    FUNC_LOG;
+    return iSortCriteria;
+    }
+
+void CFSEmailUiMailListModel::SortL()
+    {
+    FUNC_LOG;
+    TLinearOrder<CFSEmailUiMailListModelItem> orderFunc( CompareModelItemsL );
+    iItems.Sort( orderFunc );
+    }
+
+void CFSEmailUiMailListModel::ReplaceMessagePtr( TInt aIndex, CFSMailMessage* aNewPtr )
+    {
+    FUNC_LOG;
+    CFSEmailUiMailListModelItem* item = 
+        static_cast< CFSEmailUiMailListModelItem* >( Item(aIndex) );
+    
+    // Mail type items own the message. Delete the existing message first.
+    if ( item->ModelItemType() == ETypeMailItem )
+        {
+        delete &item->MessagePtr();
+        }
+    item->SetMessagePtr( aNewPtr );
+    
+    // If the item was the first child of a node, then also message pointer in the parent
+    // node needs to be updated
+    if ( aIndex > 0 &&
+         item->ModelItemType() == ETypeMailItem &&
+         iItems[aIndex-1]->ModelItemType() == ETypeSeparator )
+        {
+        iItems[aIndex-1]->SetMessagePtr( aNewPtr );
+        }
+    }
+
+TInt CFSEmailUiMailListModel::GetInsertionPointL( const CFSEmailUiMailListModelItem& aItemToInsert ) const
+    {
+    FUNC_LOG;
+    TInt index;
+    TLinearOrder<CFSEmailUiMailListModelItem> orderFunc( CompareModelItemsL );
+    TInt ret = iItems.SpecificFindInOrder( &aItemToInsert, index, orderFunc, EArrayFindMode_First );
+    return index;
+    }
+
+TInt CFSEmailUiMailListModel::GetInsertionPointL( const CFSEmailUiMailListModelItem& aItemToInsert,
+                                                  TInt& aChildIdx,
+                                                  TInt& aParentNodeIdx ) const
+    {
+    FUNC_LOG;
+    TInt index = GetInsertionPointL( aItemToInsert );
+    
+    // Find out the parent node
+    aChildIdx = KErrNotFound;
+    aParentNodeIdx = KErrNotFound;
+    if ( index > 0 )
+        {
+        CFSEmailUiMailListModelItem* preceedingItem = iItems[index-1];
+        if ( MessagesBelongUnderSameSeparatorL( aItemToInsert.MessagePtr(), 
+                                                preceedingItem->MessagePtr(),
+                                                iSortCriteria.iField ) )
+            {
+            // The new item belongs under the same node as the previous item
+            // (or the previous item is a node under which the item belongs).
+            // Find out the previous node item.
+            aParentNodeIdx = index-1;
+            while ( aParentNodeIdx >= 0 && iItems[aParentNodeIdx]->ModelItemType() != ETypeSeparator )
+                {
+                aParentNodeIdx--;
+                }
+            if ( aParentNodeIdx >= 0 )
+                {
+                aChildIdx = index - aParentNodeIdx - 1;
+                }
+            }
+        }
+    
+    return index;
+    }
+
+TInt CFSEmailUiMailListModel::CompareModelItemsL( const CFSEmailUiMailListModelItem& aItem1,
+                                                  const CFSEmailUiMailListModelItem& aItem2 )
+    {
+    FUNC_LOG;
+    // Retrieve the current sort criteria from model instance in TLS
+    CFSEmailUiMailListModel* self = 
+        static_cast<CFSEmailUiMailListModel*>( UserSvr::DllTls(KTlsHandleMailListModel) );
+    TFSMailSortCriteria sortCriteria = self->SortCriteria();
+    
+    TInt value = CompareMessagesL( aItem1.MessagePtr(), 
+                                   aItem2.MessagePtr(), 
+                                   sortCriteria.iField );
+    
+    // The logic of the CompareMessagesL matches ascending order. In descending mode it must
+    // be inverted.
+    if ( sortCriteria.iOrder == EFSMailDescending )
+        {
+        value = -value;
+        }
+    
+    // If items are equal with the primary sorting criterion and this primary criterion
+    // is not date sort, then descending date order is used as secondary criterion.
+    if ( !value && sortCriteria.iField != EFSMailSortByDate )
+        {
+        value = -CompareMessagesL( aItem1.MessagePtr(),
+                                   aItem2.MessagePtr(),
+                                   EFSMailSortByDate );
+        }
+    
+    // Some magic is needed in case one of the items (but not both) is a separator
+    if ( aItem1.ModelItemType() == ETypeSeparator && aItem2.ModelItemType() == ETypeMailItem )
+        {
+        if ( !value )
+            { // In case an item is equal to the first item under the node, it's greater than the node
+            value = -1;
+            }
+        else if ( value > 0 )
+            {
+            // In case an item is smaller than the first item under the node, it may still be greater 
+            // than the node (i.e. when the item belongs under this same node).
+            if ( MessagesBelongUnderSameSeparatorL( aItem1.MessagePtr(), 
+                                                    aItem2.MessagePtr(), 
+                                                    sortCriteria.iField ) )
+                {
+                value = -1;
+                }
+            }
+        }
+    else if ( aItem1.ModelItemType() == ETypeMailItem && aItem2.ModelItemType() == ETypeSeparator )
+        {
+        if ( !value )
+            { // In case an item is equal to the first item under the node, it's greater than the node
+            value = 1;
+            }
+        else if ( value < 0 )
+            {
+            // In case an item is smaller than the first item under the node, it may still be greater 
+            // than the node (i.e. when the item belongs under this same node).
+            if ( MessagesBelongUnderSameSeparatorL( aItem1.MessagePtr(), 
+                                                    aItem2.MessagePtr(), 
+                                                    sortCriteria.iField ) )
+                {
+                value = 1;
+                }
+            }
+        }
+    
+    return value;
+    }
+
+// ---------------------------------------------------------------------------
+// CompareMessagesL
+// Compares given messages using the given sorting mode. Return positive 
+// value if aMessage1 is greater, negative value if aMessage1 is smaller, and 
+// 0 if the messages are equal.
+// ---------------------------------------------------------------------------
+//
+TInt CFSEmailUiMailListModel::CompareMessagesL( const CFSMailMessage& aMessage1, 
+                                                const CFSMailMessage& aMessage2,
+                                                TFSMailSortField aSortField )
+    {
+    FUNC_LOG;
+    // For now, cast away the constness from the argument because CFSMailMessage does 
+    // not declare all its logically constant functions as const. This is dirty and
+    // should be fixed in the CFSMailMessage interface.
+    CFSMailMessage& message1 = const_cast<CFSMailMessage&>( aMessage1 );
+    CFSMailMessage& message2 = const_cast<CFSMailMessage&>( aMessage2 );
+    
+    TInt retVal = 0;
+    
+    switch ( aSortField )
+        {
+        case EFSMailSortByFlagStatus:
+            {
+            TInt compVal1 = 0;
+            if ( message1.IsFlagSet(EFSMsgFlag_FollowUpComplete) ) { compVal1 = 1; }
+            else if ( message1.IsFlagSet(EFSMsgFlag_FollowUp) ) { compVal1 = 2; }
+
+            TInt compVal2 = 0;
+            if ( message2.IsFlagSet(EFSMsgFlag_FollowUpComplete) ) { compVal2 = 1; }
+            else if ( message2.IsFlagSet(EFSMsgFlag_FollowUp) ) { compVal2 = 2; }
+
+            retVal = compVal1 - compVal2;
+            }
+            break;
+        case EFSMailSortByPriority:
+            {
+            TInt compVal1 = 1;
+            if ( message1.IsFlagSet(EFSMsgFlag_Low) ) { compVal1 = 0; }
+            else if ( message1.IsFlagSet(EFSMsgFlag_Important) ) { compVal1 = 2; }
+
+            TInt compVal2 = 1;
+            if ( message2.IsFlagSet(EFSMsgFlag_Low) ) { compVal2 = 0; }
+            else if ( message2.IsFlagSet(EFSMsgFlag_Important) ) { compVal2 = 2; }
+
+            retVal = compVal1 - compVal2;
+            }
+            break;
+        case EFSMailSortByRecipient:
+            {
+            CFSMailAddress* toAddress1(NULL);
+            CFSMailAddress* toAddress2(NULL); 
+
+            RPointerArray<CFSMailAddress>& toArray1 = message1.GetToRecipients();
+            RPointerArray<CFSMailAddress>& toArray2 = message2.GetToRecipients();
+            if ( toArray1.Count() )
+                {
+                toAddress1 = toArray1[0];
+                }           
+            if ( toArray2.Count() )
+                {
+                toAddress2 = toArray2[0];
+                }           
+            retVal = TFsEmailUiUtility::CompareMailAddressesL( toAddress1, toAddress2 );
+            }
+            break;
+        case EFSMailSortBySender:
+            {
+            CFSMailAddress* fromAddress1 = message1.GetSender();
+            CFSMailAddress* fromAddress2 = message2.GetSender();
+            retVal = TFsEmailUiUtility::CompareMailAddressesL( fromAddress1, fromAddress2 );
+            }
+            break;
+        case EFSMailSortByAttachment:
+            {
+            TInt compVal1 = 0;
+            if ( message1.IsFlagSet(EFSMsgFlag_Attachments) ) { compVal1 = 1; }
+
+            TInt compVal2 = 0;
+            if ( message2.IsFlagSet(EFSMsgFlag_Attachments) ) { compVal2 = 1; }
+
+            retVal = compVal1 - compVal2;
+            }
+            break;
+        case EFSMailSortByUnread:
+            {
+            TInt compVal1 = 1;
+            if ( message1.IsFlagSet(EFSMsgFlag_Read) ) { compVal1 = 0; }
+
+            TInt compVal2 = 1;
+            if ( message2.IsFlagSet(EFSMsgFlag_Read) ) { compVal2 = 0; }
+
+            retVal = compVal1 - compVal2;
+            }
+            break;
+        case EFSMailSortBySubject:
+            {
+            retVal = TFsEmailUiUtility::CompareMailSubjectsL( &message1, &message2 );
+            }
+            break;  
+        case EFSMailSortByDate:
+            {
+            TTime time1 = message1.GetDate();
+            TTime time2 = message2.GetDate();
+            TTimeIntervalSeconds diff;
+            TInt err = time1.SecondsFrom( time2, diff );
+            if ( !err )
+                {
+                // Normal case, no overflow
+                retVal = diff.Int();
+                }
+            else
+                {
+                // Overflow happens if the difference in time stamps is more than roughly 68 years.
+                // This is a very unlikely special case but handle it properly just in case.
+                retVal = ( time1 > time2 ? 1 : -1 );
+                }
+            }
+            break;
+        default:
+            {
+            retVal = 0;
+            }
+            break;
+        }
+    
+    return retVal;
+    }
+
+TBool CFSEmailUiMailListModel::MessagesBelongUnderSameSeparatorL( 
+                                                           const CFSMailMessage& aMessage1, 
+                                                           const CFSMailMessage& aMessage2,
+                                                           TFSMailSortField aSortField )
+    {
+    FUNC_LOG;
+    TBool retVal = EFalse;
+    
+    switch ( aSortField )
+        {
+        case EFSMailSortByFlagStatus:
+        case EFSMailSortByPriority:
+        case EFSMailSortByRecipient:
+        case EFSMailSortBySender:
+        case EFSMailSortByAttachment:
+        case EFSMailSortByUnread:
+        case EFSMailSortBySubject:
+            {
+            retVal = ( !CompareMessagesL(aMessage1, aMessage2, aSortField) );
+            }
+            break;
+        case EFSMailSortByDate:
+            {
+            TTime time1InHomeTime = aMessage1.GetDate();
+            TTime time2InHomeTime = aMessage2.GetDate();
+            TLocale currentLocaleSettings;      
+            time1InHomeTime += currentLocaleSettings.UniversalTimeOffset();                      
+            time1InHomeTime += currentLocaleSettings.QueryHomeHasDaylightSavingOn() 
+                                  ? TTimeIntervalHours(1) : TTimeIntervalHours(0);          
+            time2InHomeTime += currentLocaleSettings.UniversalTimeOffset();                      
+            time2InHomeTime += currentLocaleSettings.QueryHomeHasDaylightSavingOn() 
+                                  ? TTimeIntervalHours(1) : TTimeIntervalHours(0);      
+            // Check that the day of the year and the year number are the same
+            TInt day1 = time1InHomeTime.DayNoInYear();
+            TInt day2 = time2InHomeTime.DayNoInYear();
+            TTimeIntervalYears year1 = time1InHomeTime.YearsFrom(0);
+            TTimeIntervalYears year2 = time2InHomeTime.YearsFrom(0);
+            retVal = ( day1 == day2 && year1 == year2 );
+            }
+            break;
+        default:
+            {
+            retVal = EFalse;
+            }
+            break;
+        }
+    
+    return retVal;
+    }
+
+/**
+ * CFSEmailUiMailListModel::Reset
+ */
+void CFSEmailUiMailListModel::Reset()
+    {
+    FUNC_LOG;
+	iItems.ResetAndDestroy();
+    iSortCriteria.iField = EFSMailSortByDate;
+    iSortCriteria.iOrder = EFSMailDescending;
+    }
+