javauis/lcdui_akn/lcdui/src/CMIDTicker.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 14:23:59 +0300
branchRCL_3
changeset 83 26b2b12093af
parent 66 2455ef1f5bbc
permissions -rw-r--r--
Revision: v2.2.17 Kit: 201041

/*
* 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:  Implementation of the Ticker component
*
*/


#include <eikenv.h>
#include <coecntrl.h>
#include <coeccntx.h>
#include <coecobs.h>
// needed API for iAvkonAppUi
#include <aknappui.h>
#include <AknsUtils.h>
#include <aknconsts.h>

//#include <aknlayoutdef.h>
//#include <aknlayout.lag>
// CAknLayoutFont API for font layouting
#include <AknLayoutFont.h>

#include <aknenv.h>
// CAknIndicatorContainer API for updating text capacity indicator
#include <AknIndicatorContainer.h>
// MAknEditingStateIndicator API for updating text capacity indicator
// and setting state to edit indicators
#include <aknEditStateIndicator.h>
#include <aknnavi.h>
// CAknNavigationDecorator* iNaviDecorator
#include <aknnavide.h>

#include <AknsDrawUtils.h>
#include <j2me/jdebug.h>
#include "CMIDTicker.h"
// needed for setting and removing displayables (iDisplayableRArray)
#include "CMIDDisplayable.h"
// CMIDUtils::MapJavaToETextChars in CMIDScrollingText::SetTextL
#include "CMIDUtils.h"
#include "CMIDUIManager.h"

/**
 * To enable ticker tracing, uncomment the follwing two lines and link
 * to estlib.lib:
 *
 *#include <stdio.h>
 *#define TRACE_TICKER 1
 */

/** Time between each tick.*/
const TInt KTickPeriod = 40000;

/** Scrolling width in pixels where increment increases*/
const TInt KScrollingWidthLimit = 200;

/** Increment values for two different scrolling widths*/
const TInt KOnePixel = 1;
const TInt KTwoPixels = 2;

_LIT(KLeftSquareBracket, "[");
_LIT(KRightSquareBracket, "]");
_LIT(KTextCapacity, "(999) ");

_LIT(KLeftSmalllBracket, "(");
_LIT(KRightSmallBracket, ")");

#ifdef _DEBUG
#define DEBUG_ARG(x) x
#else
#define DEBUG_ARG(x)
#endif

//
// Private helper functions
//
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CleanupTicker(TAny* aTicker)
{
    static_cast< CMIDTicker* >(aTicker)->Dispose();
}


// ---------------------------------------------------------------------------
// Return the navi pane container. The method trapped should not leave.
// ---------------------------------------------------------------------------
//
CAknNavigationControlContainer* NaviContainerL()
{
    CEikStatusPane *sp = iAvkonAppUi->StatusPane();
    CAknNavigationControlContainer* naviC =
        static_cast<CAknNavigationControlContainer*>(sp->ControlL(TUid::Uid(EEikStatusPaneUidNavi)));

    return naviC;
}

// ---------------------------------------------------------------------------
// Return a text layout defined in the platform LAF
// for text to be shown in the navi pane. According to the
// type of navi pane control the text layout may be different.
// We have chosen to use the same layout as the edit indicator
// text (the text showing how many chars are left in an editor).
// To use the layout used by navi pane labels use
// Navi_pane_texts_Line_1. This layout information determines the
// font and the text color. Text positioning is not taken from
// layout, the text is vertically centered and scrolled horizontally
// instead, h aligned to the left or right of the navi pane according
// to the directionality.
// ---------------------------------------------------------------------------
//
const TAknTextLineLayout Layout()
{
    return AknLayout::Small_status_pane_texts_Line_1(0);
}

// ---------------------------------------------------------------------------
// Return the text alignment according to locale alignment
// ---------------------------------------------------------------------------
//
CGraphicsContext::TTextAlign TextAlign()
{
    return AknLayoutUtils::LayoutMirrored() ? CGraphicsContext::ERight : CGraphicsContext::ELeft;
}

//
// class CMIDTickerController
//

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
CMIDNaviPaneController* CMIDNaviPaneController::NewL()
{
    CMIDNaviPaneController* self=new(ELeave) CMIDNaviPaneController();
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
CMIDNaviPaneController::~CMIDNaviPaneController()
{
    delete iTickerTimer;
    iTickerTimer = NULL;
    delete iEditCapacityText;
    iTickerObservers.Close();
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
CMIDNaviPaneController::CMIDNaviPaneController()
{
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::ConstructL()
{
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::UpdateTextInputIndicatorL(TInt aCount)
{
    delete iEditCapacityText;
    iEditCapacityText = NULL;

    if (aCount >= 0 && aCount <= 999)
    {
        const CFont* font = AknLayoutUtils::FontFromId(Layout().FontId());
        TBuf<10> text;

        text.Append(KLeftSmalllBracket);
        text.AppendNum(aCount);
        text.Append(KRightSmallBracket);

        // set text localized (non Latin numbers)
        AknTextUtils::LanguageSpecificNumberConversion(text);

        iEditCapacityText = TBidiText::NewL(text,1);
        iEditCapacityText->WrapText(font->TextWidthInPixels(KTextCapacity), *font, NULL);

        AddEditCapacityTextToNaviPaneL();
    }
    else
    {
        // to prevent panic if state indicator is NULL (it can happen when 3rd party FEP is active)
        MAknEditingStateIndicator* indicator = CAknEnv::Static()->EditingStateIndicator();
        if (indicator)
        {
            indicator->IndicatorContainer()->SetIndicatorState(
                TUid::Uid(EAknNaviPaneEditorIndicatorMessageLength),
                EAknIndicatorStateOff);
        }
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TBidiText* CMIDNaviPaneController::EditCapacityText() const
{
    return iEditCapacityText;
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::AddTickerObserverL(
    MMIDTickerObserver* aObserver)
{
    ASSERT(aObserver);
    if (iTickerObservers.Find(aObserver) == KErrNotFound)
    {
        User::LeaveIfError(iTickerObservers.Append(aObserver));
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::RemoveTickerObserver(
    MMIDTickerObserver* aObserver)
{
    ASSERT(aObserver);
    TInt index = iTickerObservers.Find(aObserver);
    if (index != KErrNotFound)
    {
        iTickerObservers.Remove(index);
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::SetTickerL(CMIDTicker* aTicker)
{
    if (!iTickerTimer && !aTicker)
    {
        // CMIDTickerTimer instance is created only when
        // a ticker object is set
        return;
    }
    if (!iTickerTimer)
    {
        iTickerTimer = CMIDTickerTimer::NewL(this);
    }
    iTickerTimer->SetTickerL(aTicker);
}


// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::ShowTickerL(TBool aShow)
{
    if (iTickerTimer)
    {
        iTickerTimer->ShowTickerL(aShow);
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::PauseTickerL(
    TInt aInterval, MMIDTickerObserver* aPausingObserver)
{
    if (aInterval > 0)
    {
        // Set last observer to pause the ticker
        iPausingObserver = aPausingObserver;
    }
    if (iTickerTimer)
    {
        iTickerTimer->PauseTickerL(aInterval, aPausingObserver);
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::TickerChangedL(CMIDTicker* aTicker, TTickerEvent aEvent)
{
    if (iTickerTimer)
    {
        iTickerTimer->TickerChangedL(aTicker, aEvent);
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::LayoutTickerL()
{
    if (iTickerTimer)
    {
        iTickerTimer->LayoutTickerL();
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::ResetTickerScrollingSpeedL()
{
    if (iTickerTimer)
    {
        iTickerTimer->ResetScrollingSpeedL();
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::NotifyTickerObservers(TBool aShowing)
{
    TInt numObservers = iTickerObservers.Count();
    for (TInt index = 0; index < numObservers; index++)
    {
        iTickerObservers[ index ]->TickerShowing(aShowing);
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDNaviPaneController::AddEditCapacityTextToNaviPaneL()
{
    if (iEditCapacityText != NULL &&
            (!iTickerTimer ||
             !iTickerTimer->iEnabled ||
             !iTickerTimer->iTicker))
    {
        // to prevent panic if state indicator is NULL (it can happen when 3rd party FEP is active)
        MAknEditingStateIndicator* indicator = CAknEnv::Static()->EditingStateIndicator();
        if (indicator)
        {
            indicator->IndicatorContainer()->SetIndicatorState(
                TUid::Uid(EAknNaviPaneEditorIndicatorMessageLength), EAknIndicatorStateOn);
            indicator->IndicatorContainer()->SetIndicatorValueL(
                TUid::Uid(EAknNaviPaneEditorIndicatorMessageLength), iEditCapacityText->Text());
        }
    }
}


// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
CMIDTickerTimer* CMIDTickerTimer::NewL(CMIDNaviPaneController* aController)
{
    CMIDTickerTimer* self=new(ELeave) CMIDTickerTimer(aController);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
CMIDTickerTimer::~CMIDTickerTimer()
{
    DEBUG("CMIDTickerTimer::~CMIDTickerTimer - calling StopL");
    TRAPD(ignore,StopL());
    if (ignore != KErrNone)
    {
        DEBUG_INT("CMIDTickerTimer::~CMIDTickerTimer - Exception from StopL. Error = %d", ignore);
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
CMIDTickerTimer::CMIDTickerTimer(CMIDNaviPaneController* aCtrl)
        : CTimer(CActive::EPriorityHigh)
        , iCtrl(aCtrl)
        , iTicker(NULL)
        , iEnabled(EFalse)
        , iIncrement(KOnePixel)
{
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::ConstructL()
{
    CTimer::ConstructL();
    ResetScrollingSpeedL();
    CActiveScheduler::Add(this);
}


// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::RunL()
{
    if (iIsPaused)
    {
        iIsPaused = EFalse;
        StartL();
        return;
    }

    if (iTicker)
    {
        iTicker->TickL(iIncrement);
        Kick();
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::TickerChangedL(
    CMIDTicker* aTicker, CMIDNaviPaneController::TTickerEvent aEvent)
{
    ASSERT(aTicker == iTicker);
    (void)aTicker; // Just to suppress warning in release build
    switch (aEvent)
    {
    case CMIDNaviPaneController::ENone:
    case CMIDNaviPaneController::EModelChanged:
        // ignore
        break;
    case CMIDNaviPaneController::ETextChanged:
        break;

    case CMIDNaviPaneController::EPositionChanged:
        iTicker->RenderL();
        break;
    }
}


// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::ShowTickerL(TBool aShow)
{
    if (aShow)
    {
        StartL();
    }
    else
    {
        StopL();
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::SetTickerL(CMIDTicker* aTicker)
{
    if (iTicker != aTicker)
    {
        if (iTicker)
        {
            iTicker->StopL();
            iTicker->SetController(NULL);
            iTicker->RemoveRef();
        }

        iTicker = aTicker;

        if (iTicker)
        {
            iTicker->AddRef();
            iTicker->SetController(iCtrl);
        }
    }
    else
    {
        if (iTicker)
        {
            iTicker->PauseL();
        }
    }

    // If the ticker is paused for textfield and textbox and displayable is changed
    // cancel the pause timer and  start the ticker
    if (iIsPaused)
    {
        Cancel();
    }

    CheckedStart();
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::PauseTickerL(TInt aInterval, MMIDTickerObserver* aPausingObserver)
{
    if (aInterval <= 0)
    {
        if (iCtrl->iPausingObserver == aPausingObserver)
        { //only last requesting pausing observer can annulate request
            iIsPaused = EFalse;
            StartL();
        }
    }
    else
    {
        PauseL();
        After(aInterval);
        iIsPaused = ETrue;
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::StartL()
{
    Cancel();

    iEnabled = ETrue;
    iCtrl->NotifyTickerObservers(iEnabled && iTicker);

    if (iTicker)
    {
        iTicker->StartL();
    }

    iCtrl->iPausingObserver = NULL;
    iIsPaused = EFalse;

    CheckedStart();
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::PauseL()
{
    Cancel();

    iEnabled = EFalse;
    iCtrl->NotifyTickerObservers(iEnabled);

    if (iTicker)
    {
        iTicker->PauseL();
    }

    iCtrl->AddEditCapacityTextToNaviPaneL();
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::StopL()
{
    iEnabled = EFalse;
    iCtrl->NotifyTickerObservers(iEnabled);

    if (iTicker)
    {
        iTicker->StopL();
    }

    iCtrl->AddEditCapacityTextToNaviPaneL();

    Cancel();
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::CheckedStart()
{
    if (!iEnabled)
    {
        return;
    }
    if (NULL == iTicker)
    {
        return;
    }

    if (!IsActive())
    {
        Kick();
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::Kick()
{
    ASSERT(iEnabled);
    ASSERT(iTicker);
    if (!IsActive())
    {
        After(KTickPeriod);
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::LayoutTickerL()
{
    ResetScrollingSpeedL();
    if (iTicker)
    {
        iTicker->LayoutL();
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTickerTimer::ResetScrollingSpeedL()
{
    if (CMIDScrollingText::ScrollingWidthL() <= KScrollingWidthLimit)
    {
        iIncrement = KOnePixel;
    }
    else
    {
        iIncrement = KTwoPixels;
    }
}

//
// class CMIDTicker
//
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
MMIDTicker* CMIDTicker::NewL(const TDesC& aText)
{
    CMIDTicker* ticker = new(ELeave) CMIDTicker;
    CleanupStack::PushL(TCleanupItem(CleanupTicker, ticker));
    ticker->ConstructL(aText);
    CleanupStack::Pop();
    return ticker;
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
CMIDTicker::CMIDTicker() :
        iRefCount(1)
{
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
CMIDTicker::~CMIDTicker()
{
    DEBUG("CMIDTicker::~CMIDTicker - calling StopL and RemoveDisplayableFromArrayL");
    TRAPD(ignore, StopL(); RemoveDisplayableFromArrayL(NULL));
    if (ignore != KErrNone)
    {
        DEBUG_INT("CMIDTicker::~CMIDTicker - Exception from StopL or RemoveDisplayableFromArrayL. Error = %d", ignore);
    }
    iDisplayableRArray.Reset();
    iDisplayableRArray.Close();

    delete iNaviDecorator;
    iNaviScrollingText = NULL; //deleted by navi decorator
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTicker::ConstructL(const TDesC& aText)
{
    CAknNavigationControlContainer* naviC = NaviContainerL();

    iNaviScrollingText = CMIDScrollingText::NewL(this,aText);
    iNaviScrollingText->SetContainerWindowL(*naviC);
    iNaviScrollingText->SetExtent(TPoint(0,0), naviC->Size());

    iNaviDecorator = CAknNavigationDecorator::NewL(naviC, iNaviScrollingText, CAknNavigationDecorator::ENotSpecified);
    iNaviDecorator->SetContainerWindowL(*naviC);
    iNaviDecorator->MakeScrollButtonVisible(EFalse);
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTicker::Dispose()
{
    if (iController)
    {
        TRAPD(ignore, iController->SetTickerL(NULL));
        if (ignore != KErrNone)
        {
            DEBUG_INT("CMIDTicker::Dispose - Exception from CMIDNaviPaneController::SetTickerL(NULL). Error = %d", ignore);
        }
    }
    delete this;
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTicker::SetTextL(const TDesC& aText)
{
    iNaviScrollingText->SetTextL(aText);
}

void CMIDTicker::AddRef()
{
    ++iRefCount;
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTicker::RemoveRef()
{
    ASSERT(iRefCount);
    --iRefCount;
    if (0 == iRefCount)
    {
        delete this;
    }
}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CMIDTicker::SetDisplayableL(CMIDDisplayable* aDisplayable, TInt aAdd)
{
    ASSERT(aDisplayable);

    if (aAdd)
    { //KAddDisplayable:
        iDisplayableRArray.Append(aDisplayable);
    }
    else
    {
        RemoveDisplayableFromArrayL(aDisplayable);
    }
}

// ---------------------------------------------------------------------------
// if aDisplayable is not null then remove it
// if aDisplayable is NULL mean remove all
// ---------------------------------------------------------------------------
//
void CMIDTicker::RemoveDisplayableFromArrayL(CMIDDisplayable* aDisplayable)
{
    // if aDisplayable is not null then remove it.
    if (aDisplayable)
    {
        TInt index = iDisplayableRArray.Find(aDisplayable);
        if (index != KErrNotFound)
        {
            CMIDDisplayable* displayable = iDisplayableRArray[index];
            iDisplayableRArray.Remove(index);
            displayable->SetTickerL(NULL);
        }
    }
    else
    {// if aDisplayable is null mean remove all
        TInt count = iDisplayableRArray.Count();
        for (TInt ii = 0; ii<count; ii++)
        {
            // Always remove the Zeroth element as we are removing
            // the element array size is changing (reducing).
            CMIDDisplayable* displayable = iDisplayableRArray[0]; // index zero is required
            iDisplayableRArray.Remove(0);// index zero is required
            displayable->SetTickerL(NULL);
        }
    }
}

// ---------------------------------------------------------------------------
// Start the ticker: we must disable any edit indicators (this is done by observers
// but there is an observer, CDateFieldItem, which uses an editor (CEikMfne) which is not
// FEP aware and hence cannot disable the edit indicators at the right time. So we have to
// do it in here instead. The push the navi decorator on the navi pane. This will assure
// our scrolling text will be drawn. */
// ---------------------------------------------------------------------------
//
void CMIDTicker::StartL()
{
    if (iNaviScrollingText->Size() == TSize(0,0))
    {
        iNaviScrollingText->SetExtent(TPoint(0,0), NaviContainerL()->Size());
        iNaviScrollingText->UpdateTickerLayoutL();
    }

    // to prevent panic if state indicator is NULL (it can happen when 3rd party FEP is active)
    MAknEditingStateIndicator* indicator = CAknEnv::Static()->EditingStateIndicator();
    if (indicator)
    {
        indicator->SetState(EStateNone);
    }
    NaviContainerL()->PushL(*iNaviDecorator);
    iNaviScrollingText->SetPaused(EFalse);
}

// ---------------------------------------------------------------------------
// Pause the ticker, inform ScrollingText about pause mode, and remove our
// navi decorator from the navi pane. */
// ---------------------------------------------------------------------------
//
void CMIDTicker::PauseL()
{
    iNaviScrollingText->SetPaused(ETrue);
    NaviContainerL()->Pop(iNaviDecorator);
}


// ---------------------------------------------------------------------------
// Stop the ticker: just remove our navi decorator from the navi pane. */
// ---------------------------------------------------------------------------
//
void CMIDTicker::StopL()
{
    NaviContainerL()->Pop(iNaviDecorator);
    iNaviScrollingText->SetPaused(EFalse);
}

// ---------------------------------------------------------------------------
// The text position is updated every tick, this achieves text scrolling. */
// ---------------------------------------------------------------------------
//
void CMIDTicker::TickL(TInt aIncrement)
{
    iNaviScrollingText->UpdateTextPositionL(aIncrement);
}

void CMIDTicker::SetController(CMIDNaviPaneController* aController)
{
    iController = aController;
}

CMIDNaviPaneController* CMIDTicker::Controller() const
{
    return iController;
}

void CMIDTicker::ReportEventL(CMIDNaviPaneController::TTickerEvent aEvent)
{
    if (iController)
    {
        iController->TickerChangedL(this, aEvent);
    }
}

// ---------------------------------------------------------------------------
// Relayout ScrollingText, cancel pause mode.
// ---------------------------------------------------------------------------
//
void CMIDTicker::LayoutL()
{
    iNaviScrollingText->SetPaused(EFalse);
    iNaviScrollingText->UpdateTickerLayoutL();
}

// ---------------------------------------------------------------------------
// Redraw the status pane (out scrolling text is transparent so we need
// the status pane to draw the navi pane background for us)
// ---------------------------------------------------------------------------
//
void CMIDTicker::RenderL()
{
    iAvkonAppUi->StatusPane()->DrawNow();
}

//
// CMIDScrollingText
//

CMIDScrollingText* CMIDScrollingText::NewL(CMIDTicker* aParent, const TDesC& aText)
{
    CMIDScrollingText* self = new(ELeave) CMIDScrollingText(aParent);
    CleanupStack::PushL(self);
    self->ConstructL(aText);
    CleanupStack::Pop(self);
    return self;
}

CMIDScrollingText::~CMIDScrollingText()
{
    delete iPictographInterface;
    delete iText;
}

void CMIDScrollingText::UpdateTickerLayoutL()
{
    const CFont* font = AknLayoutUtils::FontFromId(Layout().FontId());
    const CAknLayoutFont* layoutFont = CAknLayoutFont::AsCAknLayoutFontOrNull(font);

    if (layoutFont)
    {
        iBaseLineOffset = (iSize.iHeight - layoutFont->TextPaneHeight())/2 + layoutFont->TextPaneTopToBaseline();
    }
    else
    {
        iBaseLineOffset = (iSize.iHeight - font->HeightInPixels())/2 + font->AscentInPixels();
    }

    iTextWidth = font->TextWidthInPixels(iText->Text());

    if (!iPaused)
    {
        InitialiseScrollingTextPosition();
    }
}

void CMIDScrollingText::SetPaused(TBool aPause)
{
    iPaused = aPause;
}

void CMIDScrollingText::SetTextL(const TDesC& aText)
{
    HBufC* buf = aText.AllocL();
    CMIDUtils::MapJavaToETextChars(buf,EFalse);
    delete iText;
    iText = NULL;
    iText = TBidiText::NewL(buf->Des(),1);

    UpdateTickerLayoutL();
}

// ---------------------------------------------------------------------------
// Static method returning an estimate of the scrolling width -
// this must be the same for all tickers
// ---------------------------------------------------------------------------
//
TInt CMIDScrollingText::ScrollingWidthL()
{
    const CFont* font = AknLayoutUtils::FontFromId(Layout().FontId());

    TInt w = NaviContainerL()->Size().iWidth;
    w -= (font->TextWidthInPixels(KLeftSquareBracket) + font->TextWidthInPixels(KRightSquareBracket));

    return w;
}

CMIDScrollingText::CMIDScrollingText(CMIDTicker* aParent) : iParent(aParent)
{
}

void CMIDScrollingText::ConstructL(const TDesC& aText)
{
    SetTextL(aText);

    iPictographInterface = CAknPictographInterface::NewL(*this,*this);
}

// ---------------------------------------------------------------------------
// Draw the text. Either "[ ... ]" or "(999) [ .. ]" where ... or .. is the
// scrolling text. Or if device is Right to Left: either "[ ... ]" or "[..] (999)" */
// ---------------------------------------------------------------------------
//
void CMIDScrollingText::Draw(const TRect& aRect) const
{
    TAknTextLineLayout layout = Layout();

    CMIDNaviPaneController* controller = iParent->Controller();
    const CFont* font = AknLayoutUtils::FontFromId(layout.FontId());
    CWindowGc& gc = SystemGc();

    gc.SetPenColor(TextColor());
    gc.UseFont(font);


    //draw edit capacity text, eg "(999)" if needed
    if (controller && controller->EditCapacityText() != NULL)
    {
        gc.DrawText(controller->EditCapacityText()->Text(), aRect, iBaseLineOffset, TextAlign(), 0);
    }

    //draw "["
    gc.DrawText(KLeftSquareBracket, TPoint(LeftTextPosition(font)
                                           - font->TextWidthInPixels(KLeftSquareBracket),iBaseLineOffset));

    //draw "]"
    gc.DrawText(KRightSquareBracket,TPoint(RightTextPosition(font),iBaseLineOffset));


    //clip area for scrolling text
    gc.SetClippingRect(TRect(TPoint(LeftTextPosition(font), 0), TPoint(RightTextPosition(font), iSize.iHeight)));

    //draw scrolling text
    iText->WrapText(iTextWidth, *font,0);
    if (iPictographInterface)
    {
        MAknPictographDrawer* aknPictographDrawer = iPictographInterface->Interface();
        aknPictographDrawer->DrawText(gc, *font, iText->DisplayText(),
                                      TPoint(iTextPosition,iBaseLineOffset));
    }
    else
    {
        iText->DrawText(gc, TPoint(iTextPosition,iBaseLineOffset));
    }

    gc.CancelClippingRect();
}

void CMIDScrollingText::HandleResourceChange(TInt aType)
{
    CCoeControl::HandleResourceChange(aType);
    if (aType==KEikDynamicLayoutVariantSwitch || aType == KEikColorResourceChange)
    {
        if (aType == KEikDynamicLayoutVariantSwitch && iParent && iParent->Controller())
        {//change scrolling velocity if needed
            DEBUG("CMIDScrollingText::HandleResourceChange - calling iParent->Controller()->ResetScrollingSpeedL");

            TRAPD(ignore, iParent->Controller()->ResetTickerScrollingSpeedL());
            if (ignore != KErrNone)
            {
                DEBUG_INT("CMIDScrollingText::HandleResourceChange - Exception from iParent->Controller()->ResetScrollingSpeedL. Error = %d", ignore);
            }
        }

        //reset position and layout
        iPaused = false;
        DEBUG("CMIDScrollingText::HandleResourceChange - calling UpdateTickerLayoutL");
        TRAPD(ignore,UpdateTickerLayoutL());
        if (ignore != KErrNone)
        {
            DEBUG_INT("CMIDScrollingText::HandleResourceChange - Exception from UpdateTickerLayoutL. Error = %d", ignore);
        }

        //and finally draw
        DrawNow();
    }
}

void CMIDScrollingText::SizeChanged()
{
    // call parent implementation
    CCoeControl::SizeChanged();

    // update layout
    TRAP_IGNORE(UpdateTickerLayoutL());
}

void CMIDScrollingText::DrawPictographArea()
{
    // Does nothing - Ticker is updating himself
}

// ---------------------------------------------------------------------------
// Scroll the text of aScrollAmount, the direction depends on the text directionality. The min
// and max text position are given by LeftTextPosition() and RightTextPosition().
// ---------------------------------------------------------------------------
//
void CMIDScrollingText::UpdateTextPositionL(TInt aScrollAmount)
{
    const CFont* font = AknLayoutUtils::FontFromId(Layout().FontId());

    if (iPaused)
    {
        return;
    }

    if (iText->Directionality() == TBidiText::ELeftToRight)
    {
        iTextPosition -= aScrollAmount;
        if (iTextPosition < LeftTextPosition(font) - iTextWidth)
        {
            iTextPosition = RightTextPosition(font);
        }
    }
    else
    {
        iTextPosition += aScrollAmount;
        if (iTextPosition > RightTextPosition(font))
        {
            iTextPosition = LeftTextPosition(font) - iTextWidth;
        }
    }

    iParent->ReportEventL(CMIDNaviPaneController::EPositionChanged);
}


// ---------------------------------------------------------------------------
// The text color, this is taken from the layout + any skinning should be taken into account.
// ---------------------------------------------------------------------------
//
inline TRgb CMIDScrollingText::TextColor() const
{
    TRgb color = AKN_LAF_COLOR(Layout().iC);

    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
    // Ignore error, color is not updated if it not found from the skin
    AknsUtils::GetCachedColor(skin, color, KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG2);

    return color;
}

// ---------------------------------------------------------------------------
// The space needed to draw "(999) " in pixels.
// ---------------------------------------------------------------------------
//
inline TInt CMIDScrollingText::EditCapacityWidth(const CFont* aFont) const
{
    CMIDNaviPaneController* controller = iParent->Controller();

    if (controller && controller->EditCapacityText() != NULL)
    {
        return aFont->TextWidthInPixels(KTextCapacity);
    }
    return 0;
}

// ---------------------------------------------------------------------------
// The left position for scrolling text. According to the device directionality
// we must add or not the edit capacity width.
// ---------------------------------------------------------------------------
//
inline TInt CMIDScrollingText::LeftTextPosition(const CFont* aFont) const
{
    return aFont->TextWidthInPixels(KLeftSquareBracket) +
           (TextAlign() == CGraphicsContext::ELeft ? EditCapacityWidth(aFont) : 0);
}

// ---------------------------------------------------------------------------
// The right position for scrolling text. According to the device directionality
// must add or not the edit capacity width.
// ---------------------------------------------------------------------------
//
inline TInt CMIDScrollingText::RightTextPosition(const CFont* aFont) const
{
    return iSize.iWidth - aFont->TextWidthInPixels(KRightSquareBracket) -
           (TextAlign() == CGraphicsContext::ELeft ? 0 : EditCapacityWidth(aFont));
}

// ---------------------------------------------------------------------------
// Sets the initial scrolling text position
// ---------------------------------------------------------------------------
//
void CMIDScrollingText::InitialiseScrollingTextPosition()
{
    const CFont* font = AknLayoutUtils::FontFromId(Layout().FontId());
    if (iText->Directionality() == TBidiText::ELeftToRight)
    {
        iTextPosition = RightTextPosition(font);
    }
    else
    {
        iTextPosition = LeftTextPosition(font) - iTextWidth;
    }
}

// End of File