--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/emailservices/emailstore/message_store/server/src/MsgStoreSortResultRowSet.cpp Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,596 @@
+/*
+* Copyright (c) 2006 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: Message store sort result row set implementation.
+*
+*/
+
+
+#include "MsgStoreSortResultRowSet.h"
+#include "ContainerStoreDefs.h"
+
+_LIT( KEqual, " = " );
+_LIT( KNotEqual, " <> " );
+_LIT( KGreaterOrEqual, " >= " );
+_LIT( KLessThan, " < " );
+
+const TUint KQuerrySize = 200;
+
+// ==================================
+// CLASS: CMsgStoreSortResultRowSet
+// ==================================
+
+// ==========================================================================
+// FUNCTION: NewL
+// ==========================================================================
+CMsgStoreSortResultRowSet* CMsgStoreSortResultRowSet::NewL( const TMsgStoreSortCriteria& aSortCriteria,
+ TInt aMessageIdColNum,
+ TInt aReceivedDateColNum,
+ TInt aReadUnreadColNum,
+ TInt aPriotiryColNum,
+ TInt aFlagStatusColNum,
+ TInt aSizeColNum,
+ TInt aAttachmentFlagColNum )
+ {
+ CMsgStoreSortResultRowSet* self = new(ELeave) CMsgStoreSortResultRowSet( aSortCriteria,
+ aMessageIdColNum,
+ aReceivedDateColNum,
+ aReadUnreadColNum,
+ aPriotiryColNum,
+ aFlagStatusColNum,
+ aSizeColNum,
+ aAttachmentFlagColNum );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ==========================================================================
+// FUNCTION: Constructor
+// ==========================================================================
+CMsgStoreSortResultRowSet::CMsgStoreSortResultRowSet( const TMsgStoreSortCriteria& aSortCriteria,
+ TInt aMessageIdColNum,
+ TInt aReceivedDateColNum,
+ TInt aReadUnreadColNum,
+ TInt aPriotiryColNum,
+ TInt aFlagStatusColNum,
+ TInt aSizeColNum,
+ TInt aAttachmentFlagColNum )
+: iIsAutoRefresh( ETrue ), iMessageIdColNum( aMessageIdColNum ), iReceivedDateColNum(aReceivedDateColNum),
+ iReadUnreadColNum(aReadUnreadColNum), iPriotiryColNum(aPriotiryColNum), iFlagStatusColNum(aFlagStatusColNum), iSizeColNum(aSizeColNum),
+ iAttachmentFlagColNum(aAttachmentFlagColNum)
+ {
+ __LOG_CONSTRUCT( "msg", "CMsgStoreSortResultRowSet" )
+ __LOG_CLOSE_BETWEEN_WRITES
+
+ iMailBoxId = aSortCriteria.iMailBoxId;
+ iFolderId = aSortCriteria.iFolderId;
+ iSortBy = aSortCriteria.iSortBy;
+ iSortOrder = aSortCriteria.iSortOrder;
+ }
+
+// ==========================================================================
+// FUNCTION: Destructor
+// ==========================================================================
+CMsgStoreSortResultRowSet::~CMsgStoreSortResultRowSet()
+ {
+ iPropertyNames.ResetAndDestroy();
+ //iSubjectPrefixToIgnore.ResetAndDestroy();
+ iDbView.Close();
+ __LOG_DESTRUCT
+ }
+
+// ==========================================================================
+// FUNCTION: ConstructL
+// ==========================================================================
+void CMsgStoreSortResultRowSet::ConstructL()
+ {
+ }
+
+// ==========================================================================
+// FUNCTION: ToTopL
+// ==========================================================================
+void CMsgStoreSortResultRowSet::ToTopL()
+ {
+ iDbView.BeginningL();
+ }
+
+// ==========================================================================
+// FUNCTION: ToEndL
+// ==========================================================================
+void CMsgStoreSortResultRowSet::ToEndL()
+ {
+ iDbView.EndL();
+ }
+
+// ==========================================================================
+// FUNCTION: HasMorePreviousL
+// ==========================================================================
+TBool CMsgStoreSortResultRowSet::HasMorePreviousL()
+ {
+ TBool hasMorePrevious = !iDbView.AtBeginning();
+ if ( hasMorePrevious )
+ {
+ //if PreviousL() returns false, that means no more previous
+ if ( !iDbView.PreviousL() )
+ {
+ hasMorePrevious = EFalse;
+ }
+ //move it back
+ iDbView.NextL();
+ }
+ return hasMorePrevious;
+ }
+
+// ==========================================================================
+// FUNCTION: HasMoreNextL
+// ==========================================================================
+TBool CMsgStoreSortResultRowSet::HasMoreNextL()
+ {
+ TBool hasMoreNext = !iDbView.AtEnd();
+ if ( hasMoreNext )
+ {
+ //if NextL() returns false, that means no more next
+ if ( !iDbView.NextL() )
+ {
+ hasMoreNext = EFalse;
+ }
+ //move it back
+ iDbView.PreviousL();
+ }
+ return hasMoreNext;
+ }
+
+// ==========================================================================
+// FUNCTION: NextL
+// ==========================================================================
+TMsgStoreId CMsgStoreSortResultRowSet::NextL()
+ {
+ iDbView.NextL();
+ if ( iDbView.AtEnd() )
+ {
+ User::Leave( KErrOverflow );
+ }
+ return GetRowL();
+ }
+
+// ==========================================================================
+// FUNCTION: PreviousL
+// ==========================================================================
+TMsgStoreId CMsgStoreSortResultRowSet::PreviousL()
+ {
+ iDbView.PreviousL();
+ if ( iDbView.AtBeginning() )
+ {
+ User::Leave( KErrUnderflow );
+ }
+ return GetRowL();
+ }
+
+// ==========================================================================
+// FUNCTION: GotoL
+// ==========================================================================
+void CMsgStoreSortResultRowSet::GotoL( TContainerId aMessageId )
+ {
+
+ //check if the aMessageId is right on the cursor
+ TBool found = EFalse;
+ if ( iDbView.AtRow() )
+ {
+ iDbView.GetL();
+ if ( iDbView.ColUint32( iMessageIdColNum ) == aMessageId )
+ {
+ found = ETrue;
+ }
+ }
+
+ if ( !found )
+ {
+ //have to search it from the begining
+
+ TBuf<KQuerrySize> query;
+ query.Copy( KSortingTableMessageIdCol );
+ query.Append( KEqual );
+ query.AppendNum( aMessageId );
+
+ iDbView.FirstL();
+
+ TInt rc = iDbView.FindL( RDbRowSet::EForwards, query );
+ if ( rc < 0 )
+ {
+ User::Leave( rc );
+ }
+ }
+ }
+
+// ==========================================================================
+// FUNCTION: GotoL
+// ==========================================================================
+void CMsgStoreSortResultRowSet::GotoL( const TDesC& /*aStartWith*/, TMsgStoreIteratorDirection /*aDirection*/ )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+// ==========================================================================
+// FUNCTION: SkipCurrentGroupL - for UI "group" support
+// ==========================================================================
+TBool CMsgStoreSortResultRowSet::SkipCurrentGroupL( TMsgStoreIteratorDirection aDirection, TUint& aItemsInPreviousGroup )
+ {
+ __LOG_ENTER_SUPPRESS( "SkipCurrentGroupL" )
+ //if we are at the begining or end, return right away because there is NO "current group"
+ if ( iDbView.AtBeginning() || iDbView.AtEnd() )
+ {
+ return ETrue;
+ }
+
+ TBuf<KQuerrySize> query;
+ TInt8 curValue = 0;
+ TUint32 curSizeValue = 0;
+ TInt64 curDateValue = 0;
+
+ iDbView.GetL();
+
+ switch( iSortBy )
+ {
+ case EMsgStoreSortByReceivedDate:
+ query.Copy( KSortingTableReceivedDateCol );
+ curDateValue = iDbView.ColInt64( iReceivedDateColNum );
+ break;
+
+ case EMsgStoreSortByPriority:
+ query.Copy( KSortingTablePriorityCol );
+ curValue = iDbView.ColInt8( iPriotiryColNum );
+ break;
+
+ case EMsgStoreSortByFlagStatus:
+ query.Copy( KSortingTableFlagStatusCol );
+ curValue = iDbView.ColInt8( iFlagStatusColNum );
+ break;
+
+ case EMsgStoreSortByUnRead:
+ query.Copy( KSortingTableReadUnreadCol );
+ curValue = iDbView.ColInt8( iReadUnreadColNum );
+ break;
+
+ case EMsgStoreSortBySize:
+ query.Copy( KSortingTableSizeCol );
+ curSizeValue = iDbView.ColUint32( iSizeColNum );
+ break;
+
+ case EMsgStoreSortByAttachment:
+ query.Copy( KSortingTableAttachmentFlagCol );
+ curValue = iDbView.ColInt8( iAttachmentFlagColNum );
+ break;
+
+ default:
+ User::Leave( KErrCorrupt );
+ break;
+ }
+
+
+ if ( iSortBy == EMsgStoreSortByReceivedDate )
+ {
+ TTime curTime(curDateValue);
+ const TUint bufSize = 100;
+ TBuf<bufSize> timeString;
+ _LIT( KDateTimeFormat, "%F%M/%D/%Y %H:%T:%S" );
+ curTime.FormatL( timeString, KDateTimeFormat() );
+ __LOG_WRITE_FORMAT1_INFO( "cur msg time=%S", &timeString )
+
+ TLocale locale;
+ TTimeIntervalSeconds offset = locale.UniversalTimeOffset();
+
+
+ //get the local time
+ curTime += offset;
+ //change it to 0 o'clock
+ TDateTime curDT = curTime.DateTime();
+ TDateTime dayBoundary( curDT.Year(), curDT.Month(), curDT.Day(), 0, 0, 0, 0 );
+ TTime timeBoundary( dayBoundary );
+ //change it back to UTC
+ timeBoundary -= offset;
+
+ timeBoundary.FormatL( timeString, KDateTimeFormat() );
+ __LOG_WRITE_FORMAT1_INFO( "timeBoundary=%S", &timeString )
+
+ //We are search from earlier date to find the next date if
+ // 1) sort order is ASCENDING and movinf FORWARD, or
+ // 2) sort order is DESCENDING and moving BACKWARD
+ //We are search from later date to find the previous date if
+ // 1) sort order is DESCENDING and moving FORWARD, or
+ // 2) sort order is ASCENDING and moving BACKWARD
+ if ( ( iSortOrder == EMsgStoreSortAscending && aDirection == EMsgStoreIteratorForward ) ||
+ ( iSortOrder == EMsgStoreSortDescending && aDirection == EMsgStoreIteratorBackward ) )
+ {
+ //search the next date,
+ //so add one day to the search criteria and
+ TTimeIntervalDays day(1);
+ timeBoundary += day;
+ query.Append( KGreaterOrEqual );
+ query.AppendNum( timeBoundary.Int64() );
+ }
+ else
+ {
+ //search for previous date, use less than current date
+ query.Append( KLessThan );
+ query.AppendNum( timeBoundary.Int64() );
+ }
+ }
+ else if ( iSortBy == EMsgStoreSortBySize )
+ {
+ query.Append( KNotEqual );
+ query.AppendNum( curSizeValue );
+ }
+ else
+ {
+ query.Append( KNotEqual );
+ query.AppendNum( curValue );
+ }
+
+ TInt rc = KErrNone;
+ TBool hasMore = ETrue;
+
+ if ( aDirection == EMsgStoreIteratorForward )
+ {
+ rc = iDbView.FindL( RDbRowSet::EForwards, query );
+ }
+ else
+ {
+ rc = iDbView.FindL( RDbRowSet::EBackwards, query );
+ }
+
+ if ( rc >= 0 )
+ {
+ aItemsInPreviousGroup = rc;
+ if ( aDirection == EMsgStoreIteratorForward )
+ {
+ PreviousL();
+ }
+ else
+ {
+ NextL();
+ }
+ }
+ else
+ {
+ hasMore = EFalse;
+ }
+
+ return hasMore;
+ }
+
+// ==========================================================================
+// FUNCTION: GroupCountL
+// ==========================================================================
+TInt CMsgStoreSortResultRowSet::GroupCountL( RArray<TUint>& aItemsInGroup )
+ {
+ TInt count = 0;
+ TUint itemsInPreviousGroup;
+ TBool hasMore = EFalse;
+
+ iDbView.BeginningL();
+
+ TInt curTotal = 0;
+
+ do {
+ if ( !iDbView.NextL() )
+ {
+ break;
+ }
+
+ itemsInPreviousGroup = 0;
+ hasMore = SkipCurrentGroupL( EMsgStoreIteratorForward, itemsInPreviousGroup );
+
+ if ( itemsInPreviousGroup > 0 )
+ {
+ ++count;
+ curTotal += itemsInPreviousGroup;
+ aItemsInGroup.Append( itemsInPreviousGroup );
+ }
+ } while ( hasMore );
+
+ //since we can't get the item counts in the last group, we need to check if there is a last group
+ // the we may have missed
+ TInt lastGroupCount = iDbView.CountL() - curTotal;
+ if ( lastGroupCount > 0 )
+ {
+ ++count;
+ aItemsInGroup.Append( lastGroupCount );
+ }
+
+ return count;
+ }
+
+
+// ==========================================================================
+// FUNCTION: SortedIdsL
+// ==========================================================================
+void CMsgStoreSortResultRowSet::SortedIdsL( RArray<TContainerId>& aIdArray )
+ {
+ aIdArray.Reset();
+ TInt count = iDbView.CountL();
+ iDbView.BeginningL();
+ for ( TInt i = 0 ; i < count ; i++ )
+ {
+ iDbView.NextL();
+ aIdArray.Append( GetRowL() );
+ }
+ }
+
+// ==========================================================================
+// FUNCTION: IndexOfL
+// ==========================================================================
+TInt CMsgStoreSortResultRowSet::IndexOfL( TContainerId aMessageId )
+ {
+ //have to search it from the begining
+ const TUint bufSize = 200;
+ TBuf<bufSize> query;
+ query.Copy( KSortingTableMessageIdCol );
+ query.Append( KEqual );
+ query.AppendNum( aMessageId );
+
+ iDbView.FirstL();
+
+ return iDbView.FindL( RDbRowSet::EForwards, query );
+ }
+
+// ==========================================================================
+// FUNCTION: SortedIdsAndGroupCountL
+// ==========================================================================
+void CMsgStoreSortResultRowSet::SortedIdsAndGroupCountL( RArray<TContainerId>& aIdArray, RArray<TUint>& aItemsInGroup )
+ {
+ SortedIdsL( aIdArray );
+ GroupCountL( aItemsInGroup );
+ }
+
+// ==========================================================================
+// FUNCTION: SetPropertyNamesL
+// ==========================================================================
+void CMsgStoreSortResultRowSet::SetPropertyNamesL( RPointerArray<HBufC8>& aPropertyNames )
+ {
+ iPropertyNames.ResetAndDestroy();
+ for ( int i = 0 ; i < aPropertyNames.Count() ; i++ )
+ {
+ iPropertyNames.Append( aPropertyNames[i]->Des().AllocL() );
+ }
+ }
+
+// ==========================================================================
+// FUNCTION: GetRowL
+// ==========================================================================
+TMsgStoreId CMsgStoreSortResultRowSet::GetRowL()
+ {
+ iDbView.GetL();
+ TContainerId msgId = iDbView.ColUint32( iMessageIdColNum );
+ return msgId;
+ }
+
+// ==========================================================================
+// FUNCTION: MessageUpdate
+// ==========================================================================
+void CMsgStoreSortResultRowSet::MessageUpdate ( TContainerId /*aMessageId*/,
+ TContainerId aFolderId,
+ TMsgStoreOperation aOperation, //EMsgStoreAdd, EMsgStoreDelete, EMsgStoreUpdateProperties
+ TUint aFieldsChanged, //For EMsgStoreUpdateProperties only, combinations of TSortableFieldsMasks
+ const TDesC& /*aFrom*/,
+ const TDesC& /*aTo*/,
+ const TDesC& /*aSubject*/,
+ TInt64 /*aDate*/)
+ {
+ TBool reEvaluate = EFalse;
+ if ( iIsAutoRefresh && iFolderId == aFolderId )
+ {
+ if ( aOperation == EMsgStoreAdd || aOperation == EMsgStoreDelete )
+ {
+ reEvaluate = ETrue;
+ }
+ else if ( aOperation == EMsgStoreUpdateProperties )
+ {
+ //if received date changed, always refresh because it's always used
+ if ( aFieldsChanged & EMaskReceivedDate > 0 )
+ {
+ reEvaluate = ETrue;
+ }
+ else
+ {
+ switch( iSortBy )
+ {
+ case EMsgStoreSortByPriority:
+ if ( aFieldsChanged & EMaskPriotiry )
+ {
+ reEvaluate = ETrue;
+ }
+ break;
+
+ case EMsgStoreSortByFlagStatus:
+ if ( aFieldsChanged & EMaskFlagStatus )
+ {
+ reEvaluate = ETrue;
+ }
+ break;
+
+ case EMsgStoreSortByUnRead:
+ if ( aFieldsChanged & EMaskReadUnread )
+ {
+ reEvaluate = ETrue;
+ }
+ break;
+
+ case EMsgStoreSortBySize:
+ if ( aFieldsChanged & EMaskSize )
+ {
+ reEvaluate = ETrue;
+ }
+ break;
+
+ case EMsgStoreSortByAttachment:
+ if ( aFieldsChanged & EMaskAttachmentFlag )
+ {
+ reEvaluate = ETrue;
+ }
+ break;
+
+ default:
+ //do nothing
+ break;
+ }
+ }
+ }
+ }
+ if ( reEvaluate )
+ {
+ ReEvaluate(); //ignore error
+ }
+ }
+
+// ==========================================================================
+// FUNCTION: FolderDeleted
+// ==========================================================================
+void CMsgStoreSortResultRowSet::FolderDeleted ( TContainerId aFolderId )
+ {
+ if ( iIsAutoRefresh && iFolderId == aFolderId )
+ {
+ //this folder does not exist anymore.
+ //reset and re-evaluate the view
+ ReEvaluate(); //ignore error
+ }
+ }
+
+// ==========================================================================
+// FUNCTION: MailBoxDeleted
+// ==========================================================================
+void CMsgStoreSortResultRowSet::MailBoxDeleted ( TContainerId aMailBoxId )
+ {
+ if ( iIsAutoRefresh && iMailBoxId == aMailBoxId )
+ {
+ //this mail box has been deleted, so the folder does not exist anymore.
+ //reset and re-evaluate the view
+ ReEvaluate(); //ignore error
+ }
+ }
+
+// ==========================================================================
+// FUNCTION: ReEvaluate
+// ==========================================================================
+TInt CMsgStoreSortResultRowSet::ReEvaluate()
+ {
+ __LOG_ENTER_SUPPRESS( "ReEvaluate" )
+ iDbView.Reset();
+ TInt rc = iDbView.EvaluateAll();
+ if ( rc != KErrNone )
+ {
+ __LOG_WRITE_FORMAT1_ERROR("EvaluateAll() failed. rc=%d", rc)
+ }
+ return rc;
+ }