calendarui/views/src/calendaylistboxmodel.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 09 Jun 2010 09:40:23 +0300
branchRCL_3
changeset 36 9c5b1510919f
parent 0 f979ecb2b13e
child 67 1539a383d7b6
permissions -rw-r--r--
Revision: 201021 Kit: 2010123

/*
* Copyright (c) 2002 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: List Box Model class for Calendar Day view  
 *
*/

#include <calencommands.hrh>            // Calendar commands
#include <AknBidiTextUtils.h>
#include <AknUtils.h>
#include <eikenv.h>
#include <PUAcodes.hrh>
#include <StringLoader.h>
#include <txtrich.h>
#include <calentry.h>
#include <calinstance.h>
#include <calrrule.h>
#include <calalarm.h>
#include <centralrepository.h>
#include <Calendar.rsg>
#include <calsession.h>
#include <caleninstanceid.h>            // TCalenInstanceId
#include <calenviewutils.h>
#include <calenagendautils.h>
#include "CalendarVariant.hrh"
#ifdef RD_CALEN_MIDNIGHT_VISUALIZATION
#include <calendateutils.h>
#endif // RD_CALEN_MIDNIGHT_VISUALIZATION
#include <calcalendarinfo.h>
#include <calenservices.h>

//debug
#include "calendarui_debug.h"
#include "calendaylistboxmodel.h"
#include "calencontroller.h"
#include "CalendarVariant.hrh"
#include "calendaylistbox.h"
#include "calentodoview.h" // for priorities
#include "calendar.hrh"
#include "CalendarPrivateCRKeys.h"
#include "calenglobaldata.h"

// LOCAL CONSTANTS AND MACROS
_LIT(KDesTimeSpace, " ");
_LIT(KDesSeparator, "\t");
_LIT(KIconSeperatorFormat, "%d\t"); // Day LB icon seperator format

#ifdef RD_CALEN_MIDNIGHT_VISUALIZATION
_LIT(KUnicodeRightwardsArrow, "\x2192"); // ->
_LIT(KUnicodeLeftwardsArrow, "\x2190");  // <-
_LIT(K24hFmt12am, " 00"); // already starts at hr 00
_LIT(K24hFmt12pm, "24 ");
#endif // RD_CALEN_MIDNIGHT_VISUALIZATION


const TInt KTimedNoteMaxLines(4);
const TInt KHypenBufSize(4);
const TInt KNonTimedNoteMaxLines(1);

// KMaxColumnDataLength is Avkon defined minimal maximum length for column texts.
const TInt KMaxLengthOfDisplayedText(KTimedNoteMaxLines * KMaxColumnDataLength);

// =========================== MEMBER FUNCTIONS ===============================

// ----------------------------------------------------------------------------
// CCalenDayListBoxModel::CCalenDayListBoxModel
// C++ default constructor can NOT contain any code, that
// might leave.
// ----------------------------------------------------------------------------
//
CCalenDayListBoxModel::CCalenDayListBoxModel()
    {
    TRACE_ENTRY_POINT;
    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenDayListBoxModel::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CCalenDayListBoxModel::ConstructL( const CCalenDayContainer* aDayContainer )
    {
    TRACE_ENTRY_POINT;

    iDayContainer = aDayContainer;
    iItemTextArray = new(ELeave) CDesCArrayFlat(5);

    // Read time formats
    iTimeFormat = StringLoader::LoadL( R_QTN_TIME_USUAL_WITH_ZERO );

    TRACE_EXIT_POINT;
    }

void CCalenDayListBoxModel::UpdateLayoutValues( TInt aLayoutVariant,
TBool aMidnightVisualization)
    {
    TRACE_ENTRY_POINT;

    CCalenDayListBox::ReadLayout(
        aLayoutVariant,
        iLocale,
        iLaf.iGfxA,
        iLaf.iTextA,
        iLaf.iTextB,
        iLaf.iTextC,
        iLaf.iIconA,
        iLaf.iIconB,
        aMidnightVisualization );

    TRACE_EXIT_POINT;
    }

// Destructor
CCalenDayListBoxModel::~CCalenDayListBoxModel()
    {
    TRACE_ENTRY_POINT;

    delete iTimeFormat;
    delete iItemTextArray;

    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenDayListBoxModel::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CCalenDayListBoxModel* CCalenDayListBoxModel::NewL( const CCalenDayContainer* aDayContainer )
    {
    TRACE_ENTRY_POINT;

    CCalenDayListBoxModel* self =
        new( ELeave ) CCalenDayListBoxModel();

    CleanupStack::PushL( self );
    self->ConstructL( aDayContainer );
    CleanupStack::Pop( self );

    TRACE_EXIT_POINT;
    return self;
    }

// ----------------------------------------------------------------------------
// CCalenDayListBoxModel::?member_function
// ?implementation_description
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
CDesCArrayFlat* CCalenDayListBoxModel::ItemTextArray()
    {
    TRACE_ENTRY_POINT;

    TRACE_EXIT_POINT;
    return iItemTextArray;
    }

// ----------------------------------------------------------------------------
// CCalenDayListBoxModel::?member_function
// ?implementation_description
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDayListBoxModel::GetEntryTextDataL(CCalEntry& aEntry,
                                              TDes& aBuf) const
    {
    TRACE_ENTRY_POINT;

    const TInt maxLen( aBuf.MaxLength() - KTimedNoteMaxLines * KAknBidiExtraSpacePerLine );
    CalenViewUtils::GetSummaryLocationTextL( aEntry, aBuf, maxLen );

    TRACE_EXIT_POINT;
    }

#ifndef RD_CALEN_MIDNIGHT_VISUALIZATION
// ----------------------------------------------------------------------------
// CCalenDayListBoxModel::?member_function
// ?implementation_description
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDayListBoxModel::LimitStartAndEndTime(TTime& aCurrentDay,
                                                 TTime& aStart,
                                                 TTime& aEnd)
    {
    TRACE_ENTRY_POINT;

    TTimeIntervalDays days(aCurrentDay.DaysFrom(TTime(TInt64(0))));
    TTimeIntervalDays startDays(aStart.DaysFrom(TTime(TInt64(0))));
    TTimeIntervalDays endDays(aEnd.DaysFrom(TTime(TInt64(0))));

    // set start time to 00:00, if event starts before current day
    if (startDays != days)
        {
        aStart = TTime(TInt64(0)) + startDays;
        }

    // Set end time to 23:59, if event continues to next day
    if (endDays != days)
        {
        TDateTime endDate = aEnd.DateTime();
        endDate.SetHour(ECalenMaxHour);
        endDate.SetMinute(ECalenMaxMinute);
        aEnd = endDate;
        }

    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDayListBoxModel::?member_function
// ?implementation_description
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDayListBoxModel::InsertTimeL(TDes& aBuf,
                                        const TTime& aTime)
    {
    TRACE_ENTRY_POINT;

    TBuf<32> timeDes;
    aTime.FormatL( timeDes, *iTimeFormat );
    AknTextUtils::DisplayTextLanguageSpecificNumberConversion( timeDes );
    AknBidiTextUtils::ConvertToVisualAndClipL( timeDes,
                                               *iLaf.iTextA.Font(),
                                               iLaf.iTextA.TextRect().Width(),
                                               iLaf.iTextA.TextRect().Width() );
    aBuf.Append(timeDes);

    TRACE_EXIT_POINT;
    }

#else // Midnight is ON

void CCalenDayListBoxModel::InsertTimeL(TDes& aBuf, const TTime& aTime, const TTimeStringFormat aInsert)
    {
    TRACE_ENTRY_POINT;

    TBuf<32> timeDes;
    switch(aInsert)
        {
            case EInsertTimeGiven:
                aTime.FormatL( timeDes, *iTimeFormat );
                break;

            case EInsert00:
                timeDes = K24hFmt12am();
                break;

            case EInsert24:
                timeDes = K24hFmt12pm();
                break;

            default:
                ASSERT(KErrArgument);
        }


    AknTextUtils::DisplayTextLanguageSpecificNumberConversion( timeDes );
    AknBidiTextUtils::ConvertToVisualAndClipL( timeDes,
                                               *iLaf.iTextA.Font(),
                                               iLaf.iTextA.TextRect().Width(),
                                               iLaf.iTextA.TextRect().Width() );
    aBuf.Append(timeDes);

    TRACE_EXIT_POINT;
    }


#endif // RD_CALEN_MIDNIGHT_VISUALIZATION


// ----------------------------------------------------------------------------
// CCalenDayListBoxModel::?member_function
// ?implementation_description
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
#ifdef RD_CALEN_MIDNIGHT_VISUALIZATION
void CCalenDayListBoxModel::InsertHyphenL(TDes& aBuf,
                                               const TTime& aStart,
                                               const TTime& aEnd)

#else // keep the old definition
void CCalenDayListBoxModel::InsertHyphen(TDes& aBuf,
                                               const TTime& aStart,
                                               const TTime& aEnd)
#endif //RD_CALEN_MIDNIGHT_VISUALIZATION
    {
    TRACE_ENTRY_POINT;

    if (aStart != aEnd)
        {

        TBuf<KHypenBufSize> hyphen;
        hyphen.Append(TChar(KPuaCodeNarrowDash));

#ifdef RD_CALEN_MIDNIGHT_VISUALIZATION

        AknBidiTextUtils::ConvertToVisualAndClipL( hyphen,
                                              *iLaf.iTextB.Font(),
                                               iLaf.iTextB.TextRect().Width(),
                                               iLaf.iTextB.TextRect().Width() );
        aBuf.Append(hyphen);
#else
        aBuf.Append(hyphen);
#endif // RD_CALEN_MIDNIGHT_VISUALIZATION
        }

    TRACE_EXIT_POINT;
    }

// ---------------------------------------------------------
// CCalenDayListBoxModel::LastLineWidth
// Calculates a last line width
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt CCalenDayListBoxModel::LastLineWidthL(TInt aWidth, CCalEntry& aEntry) const
    {
    TRACE_ENTRY_POINT;

    CCalAlarm* alarmObj = aEntry.AlarmL();
    TBool alarm( alarmObj ? ETrue : EFalse );
    delete alarmObj;

    TCalRRule ignore;
    TBool repeat(CalenAgendaUtils::IsRepeatingL(aEntry));

    TBool priority( EFalse );

    if( aEntry.EntryTypeL() == CCalEntry::ETodo &&
        aEntry.PriorityL() != ETodoPriorityNormal )
        {
        priority = ETrue;
        }
    
    // Check if this entry has any geovalues for the location field
    CCalGeoValue* geovalue = aEntry.GeoValueL();  
    TBool mapIcon( geovalue ? ETrue : EFalse);
    delete geovalue;
    
    TInt width( aWidth );

    // FIXME, actually these should be read from LAF!

    if( alarm && repeat || alarm && priority || repeat && priority || mapIcon && alarm || mapIcon && repeat || mapIcon && priority)
        {
        width = aWidth -( iLaf.iIconB.Rect().Width() + iLaf.iIconA.Rect().Width() );
        }
    else if( alarm || repeat || priority || mapIcon)
        {
            width = aWidth - iLaf.iIconA.Rect().Width();
        }
    width = width - KAknBidiExtraSpacePerLine;

    TRACE_EXIT_POINT;
    return width;
    }

// ---------------------------------------------------------
// CCalenDayListBoxModel::WrapTextL
// (other items were commented in a header).
// ---------------------------------------------------------
//
HBufC* CCalenDayListBoxModel::WrapTextL(
    CCalEntry& aEntry,
    CArrayFixFlat<TPtrC>& aLineArray) const
    {
    TRACE_ENTRY_POINT;

    // This is rather complicated algorithm to calculate how many
    // lines given text takes.
    //
    // (Note: in below description of problem and solution we for simplicity
    // consider only meeting entries with maximum of 4 lines of text, but
    // code handles Todos, Day Events and Anniversaries with max 1 line
    // of text. It should be easy to adapt it to have different maximum number
    // of lines.)
    //
    // As UI spec says, textual representation of entry
    // (subject + location) takes as many lines as it needs.
    // If it doesn't fit to maximum number of lines (4), it is
    // truncated.
    //
    // Problem is that last line of entry might contain less space for
    // text than previous lines, as it can contain icons for alarm, repeat
    // and priority. Because Avkon APIs for text wrapping and truncating
    // cannot handle situation, in which line count is not defined AND
    // last line length varies, we have to programmatically try
    // to wrap and fit text first to 1 line, then to 2 lines, then to
    // 3 lines and finally truncate it to 4 lines.

    TBool isTimed =
        aEntry.EntryTypeL() == CCalEntry::EAppt ||
        aEntry.EntryTypeL() == CCalEntry::EReminder;
    const TInt KMaxLines =
        isTimed ? KTimedNoteMaxLines : KNonTimedNoteMaxLines;

    const TInt KLineWidth = iLaf.iTextC.TextRect().Width();

    CArrayFixFlat<TInt>* lineWidths = new( ELeave )CArrayFixFlat<TInt>( 5 );
    CleanupStack::PushL( lineWidths );

    // last line width is always dependent on icons and is thus calculated.
    // We insert last line width to line widths buffer here, and try to fit
    // text to this single line. After that we always add line with normal
    // width BEFORE this last line.
    // I.e.
    //  1st try: { LastLineWidth }
    //  2nd try: { NormalLineWidth, LastLineWidth }
    //  3rd try: { NormalLineWidth, NormalLineWidth, LastLineWidth }
    //  ...
    lineWidths->AppendL( LastLineWidthL( KLineWidth, aEntry ) );

    // Get entry text
    HBufC* text = HBufC::NewLC( KMaxLengthOfDisplayedText );
    TPtr textPtr = text->Des();
    GetEntryTextDataL( aEntry, textPtr );

    // First we try to fit text to [1, max_lines - 1] (i.e. 1,2 or 3 lines)
    TBool doesFit = EFalse;
    HBufC* visualText = NULL;
    while ( ! doesFit && lineWidths->Count() < KMaxLines  )
        {
        // Convert*WholeTextL wraps all text, so that if it doesn't
        // fit to given lines, it uses last line width to wrap remaining
        // texts. This is useful, because we then know did it fit or not.
        //
        // Note that it constructs new text buffer (visualText) that
        // has to be destroyed, if it's not used. If it's used, this
        // text has to be returned to caller and caller takes care of
        // destroying. This memory management is unfortunately complicated,
        // so be careful if you modify.
        visualText  =
            AknBidiTextUtils::ConvertToVisualAndWrapToArrayWholeTextL(
            *text,
            *lineWidths,
            *iLaf.iTextC.Font(),
            aLineArray);
        CleanupStack::PushL( visualText );

        // If amount of splitted lines is same (or less than) currently
        // tried lines, we can fit text to this amount of lines.
        TInt triedLines = lineWidths->Count();
        if ( aLineArray.Count() <= triedLines )
            {
            doesFit = ETrue;
            // In case Avkon method wraps text to less lines than we tried
            // it means that text fits to less lines, but icons has to
            // be put to empty line after text!
            // We have to manually add that empty line.
            if ( aLineArray.Count() < triedLines )
                {
                aLineArray.AppendL( TPtrC(KNullDesC) );
                }
            break; // exit from loop, we could fit text.
            }
        else
            {
            // Release visualText buffer and reset line array, because
            // we couldn't fit text on this try.
            CleanupStack::PopAndDestroy( visualText );
            visualText = NULL;
            aLineArray.Reset();

            // Prepend normal line width, and try again with more lines.
            // (Note: last line width stays last, because we prepend)
            lineWidths->InsertL( 0, KLineWidth );
            }
        }

    HBufC* result = NULL;
    if ( doesFit )
        {
        if ( aLineArray.Count() == 1 )
            {
            aLineArray.AppendL( TPtrC(KNullDesC) );
            }
            
        // If we could fit, we return visualText and caller has
        // to memory manage it. TPtrs in aLineArray points to this text
        // buffer.
        result = visualText;
        CleanupStack::Pop( visualText );
        CleanupStack::PopAndDestroy( text );
        }
    else
        {
        // If we couldn't fit before, we wrap text to max lines and truncate
        // it with ellipsis.
        TInt triedLines = lineWidths->Count();

        // truncate and add ellipsis
        TPtr truncatedText = text->Des();
        const TBool KUseEllipsis = ETrue;
        AknBidiTextUtils::ConvertToVisualAndWrapToArrayL(
            truncatedText,
            *lineWidths,
            *iLaf.iTextC.Font(),
            aLineArray,
            KUseEllipsis );

        // In case Avkon method wrapped text to less lines than we tried
        // it means that text fits to less lines, but icons has to
        // be put to empty line after text!
        // We have to manually add that empty line.
        if ( aLineArray.Count() < triedLines )
            {
            aLineArray.AppendL( TPtrC(KNullDesC) );
            }
            
        if ( aLineArray.Count() == 1 )
            {
            aLineArray.AppendL( TPtrC(KNullDesC) );
            }

        // We return original text, because
        // AknBidiTextUtils::ConvertToVisualAndWrapToArrayL
        // modifies that and TPtrs in aLineArray points to that buffer
        result = text;
        CleanupStack::Pop( text );
        }

    CleanupStack::PopAndDestroy( lineWidths );

    TRACE_EXIT_POINT;
    return result;
    };

// ----------------------------------------------------------------------------
// CCalenDayListBoxModel::?member_function
// ?implementation_description
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDayListBoxModel::CreateListBoxDataL(
    CArrayFixFlat<CCalenDayContainer::SItemInfo>& aLayoutTable,
    CArrayFixFlat<TInt>& aCellArray,
    MCalenServices& aServices,
    /*CCalInstanceView* aInstanceView*/
    TTime aCurrentDay)
    {
    TRACE_ENTRY_POINT;

    iItemTextArray->Reset();
    TBool isAllDayEvent;
    RPointerArray<CCalCalendarInfo> calendarInfoList;
    aServices.GetAllCalendarInfoL(calendarInfoList);
    CleanupClosePushL(calendarInfoList);

    HBufC* listItemData = HBufC::NewLC(ECalenCharsInLine);

    // iterate layout
    for (TInt loop(0); loop < aLayoutTable.Count(); ++loop)
        {
        CCalenDayContainer::SItemInfo& itemInfo = aLayoutTable[loop];

        CCalEntry& entry = itemInfo.iTmpInstance->Entry();
        isAllDayEvent = EFalse;
        if (entry.EntryTypeL() == CCalEntry::EAppt || entry.EntryTypeL()
                == CCalEntry::EEvent)
            {
            isAllDayEvent = CalenViewUtils::IsAlldayEventL(
                    *itemInfo.iTmpInstance);
            }
        TCalCollectionId collectionId =
                itemInfo.iTmpInstance->InstanceIdL().iCollectionId;
        HBufC* calendarFileName = aServices.GetCalFileNameForCollectionId(collectionId).AllocLC();
        TInt index = calendarInfoList.Find( *calendarFileName,
                CCalenDayListBoxModel::CalendarInfoIdentifierL );
        
        CleanupStack::PopAndDestroy(calendarFileName);
        
        if (index != KErrNotFound && calendarInfoList[index]->Enabled())
            {
            itemInfo.iColor = calendarInfoList[index]->Color().Value();
            TPtr ptr = listItemData->Des();
            ptr.Zero();

            TTime start(TInt64(0));
            TTime end(TInt64(0));

            if ((entry.EntryTypeL() == CCalEntry::EAppt || entry.EntryTypeL()
                    == CCalEntry::EReminder) && (!isAllDayEvent))
                {
                // meeting notes
                // \t14:00\t-\t
                // 0 1      2
                //
                // no icon
                ptr.Append(KDesSeparator);

                TTimeIntervalMinutes duration;
                entry.EndTimeL().TimeLocalL().MinutesFrom(
                        entry.StartTimeL().TimeLocalL(), duration);
                start = itemInfo.iTmpInstance->Time().TimeLocalL();
                end = start + duration;
#ifdef RD_CALEN_MIDNIGHT_VISUALIZATION
                InsertStartTimeL(ptr, start, aCurrentDay);
#else
                LimitStartAndEndTime( aCurrentDay, start, end );

                InsertTimeL(ptr, start);
#endif // RD_CALEN_MIDNIGHT_VISUALIZATION
                if (!AknLayoutUtils::LayoutMirrored())
                    {
                    ptr.Append(KDesSeparator);
                    }

#ifdef RD_CALEN_MIDNIGHT_VISUALIZATION
                InsertHyphenL(ptr, start, end);
#else               
                InsertHyphen(ptr, start, end);
#endif // RD_CALEN_MIDNIGHT_VISUALIZATION
                if (AknLayoutUtils::LayoutMirrored())
                    {
                    ptr.Append(KDesSeparator);
                    }

                ptr.Append(KDesSeparator);
                }
            else
            // Set icons and times for entry            
                {
                // non-timed notes
                TBuf<3> icon;
                icon.Num(
                        static_cast<TInt64> (iDayContainer->IconIndexFromEntryL(
                                entry, isAllDayEvent)));
                // icon\t\t\t
                // 0     1 2
                // gfxA  textA textB
                ptr.Append(icon);
                ptr.Append(KDesSeparator);
                ptr.Append(KDesSeparator);
                ptr.Append(KDesSeparator);
                }

            // textLines contain
            CArrayFixFlat<TPtrC>* textLines = new (ELeave) CArrayFixFlat<
                    TPtrC> (5);
            CleanupStack::PushL(textLines);

            // After WrapTextL call, visualText contains wrapped text in
            // memory buffer, textLines contain text pointers
            // (into visualText memory buffer) of beginning of each line of text.
            HBufC* visualText = WrapTextL(entry, *textLines);
            CleanupStack::PushL(visualText);

            // Put first line of text to current list line
            if (textLines->Count())
                {
                ptr.Append(textLines->At(0));
                }

            TBool isEndDisplayed = ETrue;
            // For subsequent text lines, we create separate list lines.
            if ((end != start) && (!isAllDayEvent))
                {
                isEndDisplayed = EFalse;
                }
            TInt textLinesCount = textLines->Count();
            for (TInt i(1); i <= textLinesCount || !isEndDisplayed; i++)
                {
                if(i == textLinesCount)
                    {
                    itemInfo.iBottomLine = iItemTextArray->Count();
                    break;
                    }
                if (itemInfo.iTopLine == KIndexError)
                    {
                    itemInfo.iTopLine = iItemTextArray->Count();
                    }
                iItemTextArray->AppendL(*listItemData);
                ptr.Zero();
                ptr.Append(KDesSeparator);
                // Sets an end time in second line
                if (!isEndDisplayed)
                    {
                    __ASSERT_ALWAYS( i == 1, User::Invariant() );

#ifdef RD_CALEN_MIDNIGHT_VISUALIZATION
                    InsertEndTimeL(ptr, end, aCurrentDay);
#else
                    InsertTimeL(ptr, end);
#endif // RD_CALEN_MIDNIGHT_VISUALIZATION
                    isEndDisplayed = ETrue;
                    }
                else
                    {
                    ptr.Append(KDesTimeSpace);
                    }
                ptr.Append(KDesSeparator);
                ptr.Append(KDesSeparator);
                if (i < textLines->Count())
                    {
                    ptr.Append(textLines->At(i));
                    }
                }

            // end of last line (also for non-timed notes)
            ptr.Append(KDesSeparator);

            CleanupStack::PopAndDestroy(visualText);
            CleanupStack::PopAndDestroy(textLines);

            // Alarm, repeat and priority icons
            iDayContainer->InsertAdditionalIconsL(entry,
                    KIconSeperatorFormat(), ptr);

            // append created list item data to array of list items
            aCellArray.AppendL(iItemTextArray->Count());

            if (itemInfo.iTopLine == KIndexError)
                {
                itemInfo.iTopLine = iItemTextArray->Count();
                }
            iItemTextArray->AppendL(*listItemData);
            }
        }
    CleanupStack::PopAndDestroy(listItemData);
    CleanupStack::PopAndDestroy(&calendarInfoList);

    TRACE_EXIT_POINT;
    }

#ifdef RD_CALEN_MIDNIGHT_VISUALIZATION
void CCalenDayListBoxModel::InsertStartTimeL(TDes& aBuf,
                             const TTime& aStartTime,
                             const TTime& aCurrentDay)
    {
    TRACE_ENTRY_POINT;

    TBuf<6> arrow;
    TBuf<50> formattedStartTime;
    TBool mirrored( AknLayoutUtils::LayoutMirrored() );

    if(StartsBeforeFocusedDay(aStartTime, aCurrentDay))
        {
        arrow = GetArrowIndicator(mirrored);

        // need to format end time acc.to 12hr or 24hr format
        if(TimeFormat() == ETime24)
            {
            // 24 hour. show 00 only
            InsertTimeL(formattedStartTime, aStartTime, EInsert00);
            }
        else
            {
            // 12 hour. show hh:mm am/pm
            formattedStartTime = GetFormattedStartTimeL(aCurrentDay);
            }
        }
    else
        {
        // meeting starts after 12:00 am on current day
        // add start time as it is
        InsertTimeL( formattedStartTime, aStartTime );
        }

    if(mirrored)
        {
        // For mirrored UI layouts:
        aBuf.Append(formattedStartTime);
        aBuf.Append(arrow);
        }
    else
        {
        // For western UI layouts:
        aBuf.Append(arrow);
        aBuf.Append(formattedStartTime);
        }

    TRACE_EXIT_POINT;
    }

TBool CCalenDayListBoxModel::StartsBeforeFocusedDay(const TTime& aStartTime,
const TTime& aFocusedTime)
    {
    TRACE_ENTRY_POINT;

    const TTime focusedDay12am = CalenDateUtils::BeginningOfDay(aFocusedTime);
    if(aStartTime < focusedDay12am)
        {
        TRACE_EXIT_POINT;
        return ETrue;
        }

    TRACE_EXIT_POINT;
    return EFalse;
    }

TBool CCalenDayListBoxModel::EndsAfterFocusedDay(const TTime& aEndTime,
const TTime& aFocusedTime)
    {
    TRACE_ENTRY_POINT;

    const TTime nextDay12am = CalenDateUtils::BeginningOfDay(aFocusedTime)
    + TTimeIntervalDays(1);

    if(aEndTime >= nextDay12am)
        {
        TRACE_EXIT_POINT;
        return ETrue;
        }

    TRACE_EXIT_POINT;
    return EFalse;
    }

const TDesC& CCalenDayListBoxModel::GetArrowIndicator(const TBool aMirroredLayout)
    {
    TRACE_ENTRY_POINT;

    if(aMirroredLayout)
        {
        // unicode leftwards arrow for right to left layouts
        TRACE_EXIT_POINT;
        return KUnicodeLeftwardsArrow;
        }

    // unicode rightwards arrow for left to right layouts
    TRACE_EXIT_POINT;
    return KUnicodeRightwardsArrow;
    }

const TDesC& CCalenDayListBoxModel::GetFormattedStartTimeL(const TTime& aFocusedTime)
    {
    TRACE_ENTRY_POINT;

    iFormattedStartTime.Zero();
    const TTime focusedDay12am = CalenDateUtils::BeginningOfDay(aFocusedTime);
    InsertTimeL(iFormattedStartTime, focusedDay12am);

    TRACE_EXIT_POINT;
    return iFormattedStartTime;
    }

const TDesC& CCalenDayListBoxModel::GetFormattedEndTimeL(const TTime& aFocusedTime)
    {
    TRACE_ENTRY_POINT;

    iFormattedEndTime.Zero();
    const TTime focusedDay24hrs = CalenDateUtils::BeginningOfDay(aFocusedTime)
        + TTimeIntervalDays(1);

    InsertTimeL(iFormattedEndTime, focusedDay24hrs);

    TRACE_EXIT_POINT;
    return iFormattedEndTime;
    }

void CCalenDayListBoxModel::InsertEndTimeL(TDes& aBuf,
                                           const TTime& aEndTime,
                                           const TTime& aCurrentDay)
    {
    TRACE_ENTRY_POINT;

    TBuf<6> arrow;
    TBuf<50> formattedEndTime;
    TBool mirrored( AknLayoutUtils::LayoutMirrored() );

    if(EndsAfterFocusedDay(aEndTime, aCurrentDay))
        {
        arrow = GetArrowIndicator(mirrored);

        // need to format end time acc.to 12hr or 24hr format
        if(TimeFormat() == ETime24)
            {
            // 24 hour. show 24 only
            InsertTimeL(formattedEndTime, aEndTime, EInsert24);
            }
        else
            {
            // 12 hour. show hh:mm am/pm
            formattedEndTime = GetFormattedEndTimeL(aCurrentDay);
            }
        }
    else
        {
        // meeting does not continue after 24:00 on current day
        // add start time as it is
        InsertTimeL( formattedEndTime, aEndTime );
        }

    if(mirrored)
        {
        // For Mirrored Layouts:
        aBuf.Append(arrow);
        aBuf.Append(formattedEndTime);
        }
    else
        {
        // For Western Layouts:
        aBuf.Append(formattedEndTime);
        aBuf.Append(arrow);
        }

    TRACE_EXIT_POINT;
    }

TTimeFormat CCalenDayListBoxModel::TimeFormat() const
    {
    TLocale locale;
    return locale.TimeFormat();
    }
#endif // RD_CALEN_MIDNIGHT_VISUALIZATION


// -----------------------------------------------------------------------------
// CCalenDayListBoxModel::CalendarInfoIdentifierL
// Searches for the index in calendar info list based on calendar file name
// -----------------------------------------------------------------------------
//
TBool CCalenDayListBoxModel::CalendarInfoIdentifierL(
        const HBufC* aName, const CCalCalendarInfo& aCalendarInfo)
    {
    TRACE_ENTRY_POINT;
    TBool retVal = EFalse;
    HBufC* calendarFileName = aCalendarInfo.FileNameL().AllocLC();
    retVal = calendarFileName->CompareF(*aName);
    CleanupStack::PopAndDestroy(calendarFileName);        
    TRACE_EXIT_POINT;
    return (!retVal);
    }

//  End of File