javauis/eswt_akn/org.eclipse.ercp.swt.s60/native/src/swthyperlink.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 09 Jun 2010 09:34:07 +0300
branchRCL_3
changeset 19 71c436fe3ce0
parent 14 04becd199f91
child 24 6c158198356e
permissions -rw-r--r--
Revision: v2.1.28 Kit: 2010123

/*******************************************************************************
 * Copyright (c) 2005, 2010 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Nokia Corporation - S60 implementation
 *******************************************************************************/


#include <swtlaffacade.h>
#include <swtbrowserschemehandler.h>
#include <AknBidiTextUtils.h>
#include <AknsUtils.h>
#ifdef RD_TACTILE_FEEDBACK
#include <touchfeedback.h>
#endif // RD_TACTILE_FEEDBACK
#include "swtfont.h"
#include "swthyperlink.h"


// The scheme prefixes used by the scheme handler to recognise the content type
_LIT(KSwtHyperLinkMail, "mailto:");
_LIT(KSwtHyperLinkTel, "tel:");
_LIT(KSwtHyperLinkHttp, "http://");


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


CSwtHyperLink* CSwtHyperLink::NewL(MSwtDisplay&   aDisplay,
                                   TSwtPeer       aPeer,
                                   MSwtComposite& aParent,
                                   TInt           aStyle)
{
    CSwtHyperLink* self = new(ELeave) CSwtHyperLink(aDisplay,
            aPeer,
            aParent,
            aStyle);
    CleanupStack::PushL(self);
    self->ConstructL();
    self->InitControlBaseL();
    CleanupStack::Pop(self);
    return self;
}


CSwtHyperLink::~CSwtHyperLink()
{
#ifdef RD_TACTILE_FEEDBACK
    if (iFeedback)
    {
        iFeedback->RemoveFeedbackForControl(this);
    }
#endif // RD_TACTILE_FEEDBACK
    if (iDefaultFont)
    {
        iDefaultFont->RemoveRef();
        iDefaultFont = NULL;
    }
    iFormattedText.Close();
    iOriginalText.Close();
}


CSwtHyperLink::CSwtHyperLink(MSwtDisplay&   aDisplay,
                             TSwtPeer       aPeer,
                             MSwtComposite& aParent,
                             TInt           aStyle)
        : ASwtControlBase(aDisplay, aPeer, &aParent, aStyle)
        , iFormat(MSwtHyperLink::EInvalid)
{
}


void CSwtHyperLink::ConstructL()
{
    CCoeControl& coeParent = iParent->Control()->CoeControl();

    SetContainerWindowL(coeParent);
    CAknControl::MakeVisible(coeParent.IsVisible());
    CAknControl::SetDimmed(coeParent.IsDimmed());

    UpdateDefaultFontL();
    iFormattedText.CreateL(KNullDesC);
    iOriginalText.CreateL(KNullDesC);
    UpdateSkinColor();
    SetBackground(this);   // Back will be drawn by ASwtControlBase::Draw

#ifdef RD_TACTILE_FEEDBACK
    iFeedback = MTouchFeedback::Instance();
#endif // RD_TACTILE_FEEDBACK

    ActivateL();
}


void CSwtHyperLink::SwtHandleResourceChangeL(TInt aType)
{
    if (aType == KEikDynamicLayoutVariantSwitch)
    {
        UpdateDefaultFontL();
    }
    else if (aType == KAknsMessageSkinChange)
    {
        if (!iCustomTextColor)
        {
            UpdateSkinColor();
        }
    }
}


void CSwtHyperLink::DrawText(CWindowGc& aGc,
                             const CFont* aFont,
                             const TDesC& aText,
                             const TRect& aTextRect,
                             const CGraphicsContext::TTextAlign& aAlignment) const
{
    if (!aFont)
    {
        return;
    }

    // Vertically center the text inside the text rect
    const TInt excessSpace = aTextRect.Height() - aFont->FontMaxHeight();
    const TInt baseLineY = (excessSpace / 2) + aFont->FontMaxAscent();

    TPtrC textToDraw(aText.Ptr(), aText.Length());
    RBuf convertedText;

    TInt error = convertedText.Create(aText.Length() + KAknBidiExtraSpacePerLine);
    if (error == KErrNone)
    {
        TInt availableWidth(aTextRect.Width());
        TBool clipped = AknBidiTextUtils:: ConvertToVisualAndClip(
                            aText,
                            convertedText,
                            *aFont,
                            availableWidth,
                            availableWidth);

        textToDraw.Set(convertedText.Ptr(), convertedText.Length());
    }

    CFont::TMeasureTextInput::TFlags order = CFont::TMeasureTextInput::EFVisualOrder;
    if (AknLayoutUtils::LayoutMirrored())
    {
        order = CFont::TMeasureTextInput::EFVisualOrderRightToLeft;
    }

    TInt textWidth = AknBidiTextUtils::MeasureTextBoundsWidth(*aFont,
                     textToDraw,
                     order);
    TInt alignmentSpace = aTextRect.Width() - textWidth;
    TPoint textLocation(aTextRect.iTl.iX, aTextRect.iTl.iY + baseLineY);
    if (aAlignment == CGraphicsContext::ECenter)
    {
        textLocation.iX += (alignmentSpace / 2);
    }
    else if (aAlignment == CGraphicsContext::ERight)
    {
        textLocation.iX += alignmentSpace;
    }

    TRgb textColor = iLinkColor;
    // Same background highlight as that of Link
    if (iPressed || (iDisplay.UiUtils().NaviKeyInput() && IsFocused()))
    {
        textColor = iHighlightedLinkColor;
        aGc.SetPenStyle(CGraphicsContext::ENullPen);
        aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
        aGc.SetBrushColor(iHighlightColor);
        aGc.DrawRect(TRect(TPoint(textLocation.iX, textLocation.iY - aFont->FontMaxAscent()),
                           TSize(textWidth, aFont->FontLineGap())));
    }

    aGc.UseFont(aFont);
    aGc.SetPenStyle(CGraphicsContext::ESolidPen);
    aGc.SetBrushStyle(CGraphicsContext::ENullBrush);
    aGc.SetUnderlineStyle(EUnderlineOn);
    aGc.SetPenColor(textColor);

    aGc.DrawText(textToDraw, textLocation);
    convertedText.Close();
}


void CSwtHyperLink::UpdateSkinColor()
{
    AknsUtils::GetCachedColor(AknsUtils::SkinInstance(),
                              iLinkColor,
                              KAknsIIDQsnHighlightColors,
                              EAknsCIQsnHighlightColorsCG3);
    AknsUtils::GetCachedColor(AknsUtils::SkinInstance(),
                              iHighlightColor,
                              KAknsIIDQsnHighlightColors,
                              EAknsCIQsnHighlightColorsCG2);
    AknsUtils::GetCachedColor(AknsUtils::SkinInstance(),
                              iHighlightedLinkColor,
                              KAknsIIDQsnTextColors,
                              EAknsCIQsnTextColorsCG24);
}


void CSwtHyperLink::UpdateDefaultFontL()
{
    if (iDefaultFont)
    {
        iDefaultFont->RemoveRef();
        iDefaultFont = NULL;
    }
    iDefaultFont = CSwtFont::NewL(iDisplay.Device(), iDisplay.Device().GetSystemFont()->Font());
}


void CSwtHyperLink::LaunchHandler()
{
    TPtrC scheme;
    scheme.Set(Scheme());

    RBuf textForHandler;
    TInt err = textForHandler.Create(scheme.Length() + iFormattedText.Length());
    if (err != KErrNone)
    {
        ASSERT(EFalse);
        return;
    }
    textForHandler.Append(scheme);
    textForHandler.Append(iFormattedText);

    CSwtBrowserSchemeHandler* handler = NULL;
    TRAP(err, handler = CSwtBrowserSchemeHandler::NewL(textForHandler));
    if (err != KErrNone)
    {
        ASSERT(EFalse);
    }
    else
    {
        TRAP(err, handler->HandleUrlStandaloneL());
        if (err != KErrNone)
        {
            ASSERT(EFalse);
        }
        delete handler;
        handler = NULL;
    }
    textForHandler.Close();
}


TPtrC CSwtHyperLink::Scheme()
{
    TPtrC scheme;
    switch (iFormat)
    {
    case MSwtHyperLink::EPhone:
        scheme.Set(KSwtHyperLinkTel);
        break;
    case MSwtHyperLink::EUrl:
        scheme.Set(KSwtHyperLinkHttp);
        break;
    case MSwtHyperLink::EEmail:
        scheme.Set(KSwtHyperLinkMail);
        break;
    default:
        ASSERT(EFalse);
        break;
    }
    return scheme;
}


// ---------------------------------------------------------------------------
// From class CCoeControl.
// ---------------------------------------------------------------------------
//
TKeyResponse CSwtHyperLink::OfferKeyEventL(const TKeyEvent& aKeyEvent,
        TEventCode       aType)
{
    TBool traversalDoIt(ETrue);
    if (aKeyEvent.iCode == EKeyOK || aKeyEvent.iCode == EKeyEnter)
    {
        traversalDoIt = EFalse;
    }
    return HandleKeyL(aKeyEvent, aType, traversalDoIt);
}


// ---------------------------------------------------------------------------
// From class CCoeControl.
// ---------------------------------------------------------------------------
//
void CSwtHyperLink::HandleResourceChange(TInt aType)
{
    CAknControl::HandleResourceChange(aType);
    TRAP_IGNORE(SwtHandleResourceChangeL(aType));
}


// ---------------------------------------------------------------------------
// From class CCoeControl.
// ---------------------------------------------------------------------------
//
TTypeUid::Ptr CSwtHyperLink::MopSupplyObject(TTypeUid aId)
{
    return ASwtControlBase::SwtMopSupplyObject(aId);
}


// ---------------------------------------------------------------------------
// From class CCoeControl.
// ---------------------------------------------------------------------------
//
void CSwtHyperLink::SizeChanged()
{
    HandleSizeChanged();
}


// ---------------------------------------------------------------------------
// From class CCoeControl.
// ---------------------------------------------------------------------------
//
void CSwtHyperLink::PositionChanged()
{
    HandlePositionChanged();
}


// ---------------------------------------------------------------------------
// From class CCoeControl.
// ---------------------------------------------------------------------------
//
void CSwtHyperLink::FocusChanged(TDrawNow aDrawNow)
{
    HandleFocusChanged(aDrawNow);
}


// ---------------------------------------------------------------------------
// From class CCoeControl.
// ---------------------------------------------------------------------------
//
void CSwtHyperLink::Draw(const TRect& /*aRect*/) const
{
    CGraphicsContext::TTextAlign alignment;
    if (iStyle & KSwtStyleCenter)
    {
        alignment = CGraphicsContext::ECenter;
    }
    else if (iStyle & KSwtStyleTrail)
    {
        if (AknLayoutUtils::LayoutMirrored())
        {
            alignment = CGraphicsContext::ELeft;
        }
        else
        {
            alignment = CGraphicsContext::ERight;
        }
    }
    else // default is left
    {
        if (AknLayoutUtils::LayoutMirrored())
        {
            alignment = CGraphicsContext::ERight;
        }
        else
        {
            alignment = CGraphicsContext::ELeft;
        }
    }

    TRect textRect(Rect());
    TMargins8 padding = iDisplay.UiUtils().InlineReferencePadding();

    textRect.iTl.iX += padding.iLeft;
    textRect.iTl.iY += padding.iTop;
    textRect.iBr.iX -= padding.iRight;
    textRect.iBr.iY -= padding.iBottom;

    DrawText(SystemGc(),
             &GetFont()->Font(),
             iFormattedText,
             textRect,
             alignment);
}


// ---------------------------------------------------------------------------
// From class MSwtControl.
// ---------------------------------------------------------------------------
//
CCoeControl& CSwtHyperLink::CoeControl()
{
    return *this;
}


// ---------------------------------------------------------------------------
// From class MSwtControl.
// ---------------------------------------------------------------------------
//
const CCoeControl& CSwtHyperLink::CoeControl() const
{
    return *this;
}


// ---------------------------------------------------------------------------
// From class MSwtControl.
// ---------------------------------------------------------------------------
//
void CSwtHyperLink::ProcessKeyEventL(const TKeyEvent& aKeyEvent,
                                     TEventCode       aType)
{
    if (aType == EEventKey &&
            (aKeyEvent.iCode == EKeyOK || aKeyEvent.iCode == EKeyEnter))
    {
        LaunchHandler();
    }
}


// ---------------------------------------------------------------------------
// From class MSwtControl.
// ---------------------------------------------------------------------------
//
void CSwtHyperLink::HandlePointerEventL(const TPointerEvent& aPointerEvent)
{
    switch (aPointerEvent.iType)
    {
    case TPointerEvent::EButton1Down:
    {
        iPressed = ETrue;
#ifdef RD_TACTILE_FEEDBACK
        if (iFeedback)
        {
#ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
            iFeedback->InstantFeedback(ETouchFeedbackSensitiveButton);
#else
            iFeedback->InstantFeedback(ETouchFeedbackBasic);
#endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
        }
#endif //RD_TACTILE_FEEDBACK
        Redraw();
        break;
    }

    case TPointerEvent::EDrag:
    {
        TBool pressed = iPressed;
        if (Rect().Contains(aPointerEvent.iPosition))
        {
            iPressed = ETrue;
        }
        else
        {
            iPressed = EFalse;
        }
        if (pressed != iPressed)
        {
            Redraw();
        }
        break;
    }

    case TPointerEvent::EButton1Up:
    {
        TBool pressed = iPressed;
        iPressed = EFalse;
        if (!iDisplay.RevertPointerEvent() && Rect().Contains(aPointerEvent.iPosition))
        {
            LaunchHandler();
        }
        if (pressed != iPressed)
        {
            Redraw();
        }
        break;
    }

    default:
        break;
    }

    PostMouseEventL(aPointerEvent);
}

// ---------------------------------------------------------------------------
// From class MSwtControl.
// ---------------------------------------------------------------------------
//
void CSwtHyperLink::SetForegroundL(const MSwtColor* aColor)
{
    ASwtControlBase::DoSetForegroundL(aColor);
    aColor ? iCustomTextColor = ETrue : iCustomTextColor = EFalse;
    if (iCustomTextColor)
    {
        TRgb rgb;
        TBool overrideColorSet(GetColor(EColorControlText, rgb));
        ASSERT(overrideColorSet);
        iLinkColor = rgb;
    }
    else
    {
        UpdateSkinColor();
    }
    Redraw();
}


// ---------------------------------------------------------------------------
// From class MSwtControl.
// ---------------------------------------------------------------------------
//
TSize CSwtHyperLink::ComputeSizeL(TInt aWHint, TInt aHHint)
{
    const MSwtFont* font = GetFont();
    ASSERT(font);
    TSize res(font->TextWidthInPixels(iFormattedText), font->Font().FontMaxHeight());
    if (font == &DefaultFont())
    {
        res.iHeight = Max(iDisplay.UiUtils().InlineReferenceFontHeight(), res.iHeight);
    }

    res += iDisplay.UiUtils().InlineReferencePadding().SizeDelta();
    res += BorderSizeDelta();

    if (aWHint != KSwtDefault)
    {
        res.iWidth = aWHint;
    }
    if (aHHint != KSwtDefault)
    {
        res.iHeight = aHHint;
    }

    return res;
}


// ---------------------------------------------------------------------------
// From class ASwtControlBase.
// ---------------------------------------------------------------------------
//
const MSwtFont& CSwtHyperLink::DefaultFont() const
{
    return *iDefaultFont;
}


// ---------------------------------------------------------------------------
// From class ASwtControlBase.
// ---------------------------------------------------------------------------
//
HBufC* CSwtHyperLink::MSKLabelL() const
{
    return iEikonEnv->AllocReadResourceL(R_QTN_MSK_SELECT);
}


// ---------------------------------------------------------------------------
// From class ASwtControlBase.
// ---------------------------------------------------------------------------
//
TBool CSwtHyperLink::IsKeyUsed(TUint aKeyCode) const
{
    TBool keyUsed(EFalse);
    if (aKeyCode == EKeyOK || aKeyCode == EKeyEnter)
    {
        keyUsed = ETrue;
    }
    return keyUsed;
}


// ---------------------------------------------------------------------------
// From class MSwtHyperLink.
// Note that this function is called already before SetFormat has been
// called.
// ---------------------------------------------------------------------------
//
MSwtControl* CSwtHyperLink::Control()
{
    return this;
}


// ---------------------------------------------------------------------------
// From class MSwtHyperLink.
// ---------------------------------------------------------------------------
//
void CSwtHyperLink::SetTextL(const TDesC& aText)
{
    ASSERT(iFormat != MSwtHyperLink::EInvalid);

    iFormattedText.Close();
    iOriginalText.Close();
    iFormattedText.CreateL(aText);
    iOriginalText.CreateL(aText);

    iFormattedText.TrimAll();
    iFormattedText.LowerCase();

    TInt pos(KErrNotFound);
    TPtrC scheme;
    scheme.Set(Scheme());
    pos = iFormattedText.Find(scheme);

    TBool schemeAlreadyValid(pos == 0);
    if (schemeAlreadyValid)
    {
        RBuf tmp;
        tmp.CreateL(iFormattedText.Length() - scheme.Length());
        tmp.CleanupClosePushL();
        tmp.Append(iFormattedText.Mid(scheme.Length()));
        iFormattedText.Close();
        iFormattedText.CreateL(tmp);
        CleanupStack::PopAndDestroy(&tmp);
        iFormattedText.Trim();
    }

    Redraw();
}


// ---------------------------------------------------------------------------
// From class MSwtHyperLink.
// ---------------------------------------------------------------------------
//
const TDesC* CSwtHyperLink::GetText()
{
    ASSERT(iFormat != MSwtHyperLink::EInvalid);
    return &iOriginalText;
}


// ---------------------------------------------------------------------------
// From class MSwtHyperLink.
// This is called right after the ConstructL via another JNI call.
// This is called only once.
// ---------------------------------------------------------------------------
//
void CSwtHyperLink::SetFormat(TInt aFormat)
{
    ASSERT(iFormat == MSwtHyperLink::EInvalid);

    // Only these formats are recognised by this implementation.
    ASSERT(aFormat == MSwtHyperLink::EUrl ||
           aFormat == MSwtHyperLink::EEmail ||
           aFormat == MSwtHyperLink::EPhone);
    iFormat = static_cast<MSwtHyperLink::TFormat>(aFormat);
}