uifw/AvKon/src/akntextcontrol.cpp
changeset 0 2f259fa3e83a
child 14 3320e4e6e8bb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/AvKon/src/akntextcontrol.cpp	Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,495 @@
+/*
+* 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:
+*
+*/
+
+
+#include "AknPanic.h"
+#include "akntextcontrol.h"
+
+#include "AknUtils.h"
+#include "AknBidiTextUtils.h"
+
+#include <AknPictographInterface.h>
+#include <AknPictographDrawerInterface.h>
+
+// CONSTANTS
+
+const TInt KDefaultMinCharWidthInPixels = 4;
+
+const TText KLineFeed               = 0x000A;
+const TText KCarriageReturn         = 0x000D;
+const TText KLineSeparator          = 0x2028;
+const TText KParagraphSeparator     = 0x2029;
+
+CAknTextControl* CAknTextControl::NewL(const CAknText::TType& aTextType)
+	{
+	CAknTextControl* self = new (ELeave) CAknTextControl();
+	CleanupStack::PushL(self);
+	self->ConstructL(aTextType);
+	CleanupStack::Pop(); //self
+	return self;
+	}
+
+void CAknTextControl::ConstructL(const CAknText::TType& aTextType)
+	{
+	iText = new (ELeave) CAknText( aTextType );
+	iWrappedArray = new (ELeave) CArrayFixFlat<TPtrC>(5);
+	iPictoInterface = CAknPictographInterface::NewL( *this, *this );
+	}
+
+CAknTextControl::CAknTextControl() 
+	{
+	}
+
+CAknTextControl::~CAknTextControl()
+	{
+	delete iText;
+	delete iWrappedArray;
+	delete iPictoInterface;
+	iLines.ResetAndDestroy();
+	iLines.Close();
+	}
+
+/*
+ * Copy text and labels across (pointer copy)
+ */
+CAknTextControl& CAknTextControl::operator=(CAknTextControl& aTextControl)
+	{
+	if (&aTextControl == this)
+		return *this;
+
+	if (aTextControl.iText && iText)
+		*iText = *aTextControl.iText;
+
+	if (aTextControl.NumberOfLines() > 0 && NumberOfLines() == 0)
+		{
+		iLines.ResetAndDestroy();
+		
+		for ( TInt i = aTextControl.NumberOfLines() - 1; i >= 0; i--)
+			if (iLines.Insert( aTextControl.iLines[i], 0) == KErrNone)
+				aTextControl.iLines.Remove(i);
+		}
+
+	if (aTextControl.iTextIsAlreadyInLabel)
+		iTextIsAlreadyInLabel = aTextControl.iTextIsAlreadyInLabel;
+
+	return *this;
+	}
+
+void CAknTextControl::ConstructFromResourceL(TResourceReader& aRes)
+	{
+	if (iText)
+		iText->ConstructFromResourceL(aRes);
+	}
+
+TInt CAknTextControl::CountComponentControls() const
+	{
+	return NumberOfLines();
+	}
+
+CCoeControl* CAknTextControl::ComponentControl(TInt anIndex) const
+	{
+	return const_cast<CEikLabel*>(Line(anIndex));
+	}
+
+TInt CAknTextControl::NumberOfLines() const
+	{
+	__ASSERT_DEBUG(iLines.Count() >= iNumberOfLines, Panic(EAknPanicSelfCheckFailure));
+	return iNumberOfLines;
+	}
+
+CEikLabel* CAknTextControl::Line(TInt aIndex) const
+	{
+	if (aIndex >= 0 && aIndex < NumberOfLines())
+		return iLines[aIndex]->iLabel;
+	return NULL;
+	}
+
+TBool CAknTextControl::LineModified(TInt aIndex) const
+	{
+	if (aIndex >= 0 && aIndex < NumberOfLines())
+		return iLines[aIndex]->iModified;
+	return EFalse;
+	}
+
+void  CAknTextControl::SetLineModified(TInt aIndex, TBool aValue)
+	{
+	if (aIndex >= 0 && aIndex < NumberOfLines())
+		iLines[aIndex]->iModified = aValue;
+	}
+
+void CAknTextControl::SetTextPluralityL(TBool aIsPlural)
+	{
+	if (iText)
+		iText->SetPluralityL(aIsPlural);
+    }
+
+void CAknTextControl::SetTextNumberL(TInt aNumber)
+	{
+	if (iText)
+		iText->SetNumberL(aNumber);
+    }
+
+/**
+ * Set the text, to be spread across labels.
+ */
+void CAknTextControl::SetTextL(const TDesC& aText)
+	{
+	if (iText)
+		{
+		iText->SetL(aText);
+		iTextIsAlreadyInLabel = EFalse;
+		}
+	}
+
+/**
+ * Set text into a single label. ParseText will do nothing if this
+ * method has been called.
+ *
+ * If the line already exists and it has already the same text and font
+ * then return without doing anything.
+ *
+ * If the line does not exist, create it.
+ *
+ * SetBufferReserveLengthL causes a reallocation but this should never
+ * be called unless somebody decides to change the font after the label
+ * has been created and with this new font you can fit more characters 
+ * in the same width
+ */
+
+
+void CAknTextControl::SetTextL(
+    const TDesC& aText,
+    TInt aLineNum,
+    const CFont* aFont,
+    CArrayFixFlat<TInt>* aLineWidths )
+	{
+	__ASSERT_DEBUG( aLineNum >= 0, Panic( EAknPanicInvalidValue ) );
+	
+	if ( aLineNum >= iNumberOfLines )
+		{
+		CreateLabelsL( aLineNum + 1, aFont, aLineWidths );
+		iNumberOfLines = aLineNum + 1;
+		}
+	else
+		{
+		if ( aText == *( Line( aLineNum )->Text() ) )
+			{
+			iTextIsAlreadyInLabel = ETrue;
+            return;
+			}
+		}
+
+    TInt newReservedLength = aText.Length() + KAknBidiExtraSpacePerLine;
+
+    HBufC* visualText = HBufC::NewL( newReservedLength );
+    CleanupStack::PushL( visualText );
+
+    *visualText = aText;
+
+	Line( aLineNum )->SetFont( aFont );
+
+	if ( Line( aLineNum )->BufferReserveLength() < newReservedLength )
+        {
+		Line( aLineNum )->SetBufferReserveLengthL( newReservedLength );
+        }
+
+    TInt clipWidth = aLineWidths->At( aLineNum );
+
+    // Logical-to-visual conversion is disabled in the owned CEikLabel instances,
+    // so we do the conversion here, while clipping.
+
+    TPtr ptr = visualText->Des();
+
+    AknBidiTextUtils::ConvertToVisualAndClipL(
+        ptr,
+        *aFont,
+        clipWidth,
+        clipWidth );
+
+	Line( aLineNum )->SetTextL( *visualText );
+	iLines[aLineNum]->iModified = ETrue;
+	iTextIsAlreadyInLabel = ETrue;
+
+    CleanupStack::PopAndDestroy(); // visualText;
+	}
+
+
+TPtr CAknTextControl::Text() const
+	{
+	if (iText) 
+		return iText->Get();
+	return TPtr(0,0);
+	}
+
+/**
+ * Wraps the text and sets it into the labels.
+ */
+void CAknTextControl::ParseTextL(const CFont* aFont, CArrayFixFlat<TInt>* aLineWidths,const TWrapMethod& aWrapMethod)
+    { 
+	if ( aWrapMethod == ENoAllocation && iWrappedArray )
+		{
+		// We preallocate text required in construction of alert win, so we just replace the texts in labels.
+        TPtrC remainder = Text();
+		TChar endlchar('\n');
+		TInt linebreak = remainder.LocateReverse(endlchar);
+        
+		TBuf<17 + KAknBidiExtraSpacePerLine> temp; //KEikAlertMaxMsgLength not declared in this scope
+
+        if ( linebreak == KErrNotFound )
+            {
+            AknBidiTextUtils::ConvertToVisualAndClip(remainder, temp, *aFont, KMaxTInt, KMaxTInt );
+            Line(0)->SetTextL(temp); // won't leave as there is enough space in buffer
+            iLines[0]->iModified = ETrue;
+            Line(1)->SetTextL(KNullDesC);
+            iLines[1]->iModified = ETrue;
+            }
+        else
+            {
+            AknBidiTextUtils::ConvertToVisualAndClip(
+                remainder.Left(linebreak), temp, *aFont, KMaxTInt, KMaxTInt );
+            Line(0)->SetTextL(temp);
+            iLines[0]->iModified = ETrue;
+            if ( remainder.Length()-1 == linebreak) // Line break is the last character
+                {
+                Line(1)->SetTextL(KNullDesC);
+                }
+            else
+                {
+                AknBidiTextUtils::ConvertToVisualAndClip( 
+                    remainder.Right(remainder.Length()-linebreak-1), temp, *aFont, KMaxTInt, KMaxTInt );
+                Line(1)->SetTextL(temp); // we don't want new line to label, thus -1
+                }
+            iLines[1]->iModified = ETrue;		
+			}
+		return;
+		}
+	if (iTextIsAlreadyInLabel || !iWrappedArray)
+		return;
+
+    TInt maxLines = aLineWidths->Count();
+
+    // user handles all text processing
+    if ( aWrapMethod == ENoProcessing )
+        {
+        iWrappedArray->Reset();
+
+        TPtrC remainder = Text();
+
+        while ( remainder.Length() && iWrappedArray->Count() < maxLines )
+            {
+            const TText* textArray = remainder.Ptr();
+            TInt textLength = remainder.Length();
+
+            TInt i = 0;
+
+            for ( ; i < textLength ; i++ )
+                {
+                TText t = textArray[i];
+
+                if ( t == KLineFeed ||
+                     t == KLineSeparator ||
+                     t == KParagraphSeparator ||
+                     t == KCarriageReturn )
+                    {
+                    break;
+                    }
+                }
+
+            iWrappedArray->AppendL( remainder.Left( i ) );
+
+            // After a CR, skip also possible matching LF
+            if ( i < textLength - 1 &&
+                 textArray[i] == KCarriageReturn &&
+                 textArray[i + 1] == KLineFeed )
+                {
+                i++;
+                }
+
+            i++;
+
+            if ( i >= textLength )
+                {
+                break;
+                }
+            remainder.Set( remainder.Right( textLength - i ) );
+            }
+        }
+
+    else
+        {
+        TPtr text = Text();
+
+        HBufC* visualBuffer = HBufC::NewLC( 
+            text.Length() + maxLines * KAknBidiExtraSpacePerLine );
+        *visualBuffer = text;
+        TPtr ptr = visualBuffer->Des();
+
+        AknTextUtils::DisplayTextLanguageSpecificNumberConversion( ptr);
+
+	    if (aWrapMethod == EWord)
+            {
+            AknBidiTextUtils::ConvertToVisualAndWrapToArrayL(
+                ptr, *aLineWidths, *aFont, *iWrappedArray, ETrue );
+            }
+	    else if (aWrapMethod == ELine)
+            {
+		    AknBidiTextUtils::ConvertToVisualAndChopToArrayL(
+                ptr, *aLineWidths, *aFont, *iWrappedArray );
+            }
+	    else
+            {
+		    __ASSERT_DEBUG(0,Panic(EAknPanicNotSupported));
+            }
+        }
+
+    TInt numLines = iWrappedArray->Count();
+
+	UpdateLabelsL(numLines,aFont,aLineWidths);	
+	SetWrappedTextIntoLabelsL(*iWrappedArray, numLines, aFont);
+
+    if ( aWrapMethod != ENoProcessing )
+        {
+        CleanupStack::PopAndDestroy(); // visualBuffer
+        }
+    }
+
+/**
+ * Set text and font into labels.
+ *
+ * SetBufferReserveLengthL causes a reallocation but this should never
+ * be called unless somebody decides to change the font after the label
+ * has been created and with this new font you can fit more characters 
+ * in the same width
+
+ */
+void CAknTextControl::SetWrappedTextIntoLabelsL(const CArrayFix<TPtrC>& aWrappedArray, TInt aNumLines, const CFont* aFont)
+	{
+	__ASSERT_DEBUG(aNumLines == iNumberOfLines, Panic(EAknPanicSelfCheckFailure));
+	aNumLines = aNumLines ; // just for fixing warning
+	for (TInt i=0; i < iNumberOfLines; i++)
+		{
+		
+		if (Line(i)->BufferReserveLength() < aWrappedArray.At(i).Length())
+			Line(i)->SetBufferReserveLengthL(aWrappedArray.At(i).Length());
+
+		if (*(Line(i)->Text()) != aWrappedArray.At(i) )
+			{
+			Line(i)->SetTextL(aWrappedArray.At(i));
+			Line(i)->SetFont(aFont);
+			iLines[i]->iModified = ETrue;
+			}
+		}
+	}
+/**
+ * Reset text in existing labels and create new ones if needed.
+ *
+ * Update the number of lines.
+ */
+void CAknTextControl::UpdateLabelsL(const TInt aNum,const CFont* aFont, CArrayFixFlat<TInt>* aLineWidths)
+	{
+	__ASSERT_DEBUG(iNumberOfLines <= iLines.Count(), Panic(EAknPanicSelfCheckFailure));
+
+	if (aNum <= iNumberOfLines)
+		{
+		for (TInt i = aNum; i < iNumberOfLines; i++)
+			{
+			Line(i)->SetTextL(KNullDesC);
+			iLines[i]->iModified = ETrue;
+			}
+		}
+	else
+		{
+		CreateLabelsL(aNum,aFont,aLineWidths);
+		}
+
+	iNumberOfLines = aNum;
+	}
+
+/**
+ * Create labels up to the specified number. 
+ *
+ * When a new label is created, allocate a buffer inside the label so 
+ * that it can contains a text as long as the maximum number of 'l' characters 
+ * that fit into the given line width (in pixels). 
+ */
+void CAknTextControl::CreateLabelsL(const TInt aNum,const CFont* aFont, CArrayFixFlat<TInt>* aLineWidths)
+	{
+	__ASSERT_DEBUG(aFont,Panic(EAknPanicSelfCheckFailure));
+	__ASSERT_DEBUG(aLineWidths->Count() >= aNum,Panic(EAknPanicSelfCheckFailure));
+
+    TInt minCharWidthInPixels = aFont->CharWidthInPixels('l');
+    if ( minCharWidthInPixels < 1)
+        {
+        minCharWidthInPixels = KDefaultMinCharWidthInPixels;
+        }
+
+	for (TInt i = iNumberOfLines; i < aNum; i++)
+		{
+		CEikLabel* label = CreateLabelLC(aLineWidths->At(i) / minCharWidthInPixels);
+		CLine* line = new (ELeave) CLine(label);
+		CleanupStack::Pop(); //label
+		CleanupStack::PushL(line);
+		User::LeaveIfError(iLines.Append(line));
+		CleanupStack::Pop(); //line
+		}
+	}
+
+/**
+ * Create a label
+ */
+CEikLabel* CAknTextControl::CreateLabelLC(TInt aLen)
+	{
+	CEikLabel* label = new(ELeave) CEikLabel;
+	CleanupStack::PushL(label);
+
+	label->SetContainerWindowL(*this);
+	label->SetBufferReserveLengthL(aLen);
+#ifdef RD_UI_TRANSITION_EFFECTS_POPUPS
+    label->SetParent( this );
+#endif	
+	
+    // we do logical to visual conversion ourselves while wrapping text
+    label->UseLogicalToVisualConversion( EFalse );
+
+    if ( iPictoInterface )
+        {
+        label->EnablePictographsL( *iPictoInterface );
+        }
+	
+	return label;
+	}
+
+void CAknTextControl::SetPictographCallBackL( TCallBack& aCallBack )
+    {
+    iPictoCallBack = aCallBack;
+    }
+
+CAknPictographInterface* CAknTextControl::PictographInterface() const
+    {
+    return iPictoInterface;
+    }
+
+void CAknTextControl::DrawPictographArea()
+    {
+    if ( iPictoCallBack.iFunction )
+        {
+        iPictoCallBack.CallBack();
+        }
+    }
+
+		
+// End of File