/*
* Copyright (c) 1997-2009 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 <e32std.h>
#include <e32base.h>
#include <gdi.h>
#include <s32file.h>
#include <e32test.h>
#include <txtrich.h>
#include <txtfmlyr.h>
#include <txtfrmat.h>
#include <txtstyle.h>
#define UNUSED_VAR(a) a = a
const TInt KTestCleanupStack=0x40;
LOCAL_D RTest test(_L("Testing Paragraph Styles"));
LOCAL_D CTrapCleanup* TheTrapCleanup;
LOCAL_D CRichText* TheText;
LOCAL_D CStyleList* TheStyleList;
LOCAL_D CParaFormatLayer* TheNormalParaLayer;
LOCAL_D CCharFormatLayer* TheNormalCharLayer;
LOCAL_D CParagraphStyle* TheStyleOne;
LOCAL_D CParagraphStyle* TheStyleTwo;
_LIT(KOutputFile, "c:\\etext\\t_style.tst");
template <class T>
void testStoreRestoreL(T& aCopy,const T& aOriginal)
// Test document persistance.
//
{
// set up the store
RFs theFs;
theFs.Connect();
//
theFs.Delete(KOutputFile);
theFs.MkDirAll(KOutputFile);
CFileStore* theStore=CDirectFileStore::CreateL(theFs,KOutputFile,EFileRead|EFileWrite);
CleanupStack::PushL(theStore);
theStore->SetTypeL(KDirectFileStoreLayoutUid);
//
// store the original
TStreamId id(0);
TRAPD(ret,id=aOriginal.StoreL(*theStore));
test(ret==KErrNone);
//
// restore into the copy
TRAP(ret,aCopy.RestoreL(*theStore,id));
test(ret==KErrNone);
//
// tidy up
CleanupStack::PopAndDestroy(); // theStore
theFs.Close();
}
LOCAL_C TInt IsEqual(const CRichText* aCopy,const CRichText* aOriginal)
//
// Returns true if aCopy contents matches aOriginal contents.
// Takes account of multiple segments of a segmented text component.
//
{
TInt lengthOfOriginal=aOriginal->DocumentLength();
TInt lengthOfCopy=aCopy->DocumentLength();
test(lengthOfOriginal==lengthOfCopy);
//
TPtrC copy,orig;
//
TInt lengthRead=0;
while(lengthRead<=lengthOfOriginal)
{
copy.Set((aCopy->Read(lengthRead)));
orig.Set((aOriginal->Read(lengthRead)));
for (TInt offset=0; offset<orig.Length(); offset++)
test(copy[offset]==orig[offset]);
lengthRead+=orig.Length();
}
test(lengthRead==lengthOfOriginal+1);
//
CStyleList* origStyle=aOriginal->StyleList();
CStyleList* copyStyle=aCopy->StyleList();
TInt origStyleCount=origStyle->Count();
TInt copyStyleCount=copyStyle->Count();
test(origStyleCount==copyStyleCount);
for (TInt ii=0;ii<origStyleCount;ii++)
{
RParagraphStyleInfo oInfo=origStyle->At(ii);
RParagraphStyleInfo cInfo=copyStyle->At(ii);
test(oInfo.iStyle->iName==cInfo.iStyle->iName);
if (oInfo.iStyleForNextPara==NULL)
test(cInfo.iStyleForNextPara==NULL);
}
return 1;
}
LOCAL_C void ConstructEnvWithNullParaFormat()
{
// Create global layers
CParaFormat* normalPara=CParaFormat::NewLC();
TParaFormatMask paraFormatMask;
normalPara->iHorizontalAlignment=CParaFormat::ELeftAlign;
paraFormatMask.SetAttrib(EAttAlignment);
TheNormalParaLayer=CParaFormatLayer::NewL(normalPara,paraFormatMask);
CleanupStack::PopAndDestroy(); // normalPara
TCharFormat charFormat;
TCharFormatMask charFormatMask;
TheNormalCharLayer=CCharFormatLayer::NewL(charFormat,charFormatMask);
//
// Create some paragraph styles
TheStyleOne=CParagraphStyle::NewL(*TheNormalParaLayer,*TheNormalCharLayer);
TheStyleOne->iName=_L("Style1");
// Style two is based on style one
TheStyleTwo=CParagraphStyle::NewL( *TheStyleOne, *(TheStyleOne->CharFormatLayer()));
TheStyleTwo->iName=_L("Style2");
//
CParaFormat* styleFormat=CParaFormat::NewLC();
TParaFormatMask styleMask;
styleFormat->iHorizontalAlignment=CParaFormat::ECenterAlign;
styleMask.SetAttrib(EAttAlignment);
TheStyleOne->SetL(styleFormat,styleMask);
//
styleFormat->iHorizontalAlignment=CParaFormat::ERightAlign;
// Set paragraph format to NULL
TheStyleTwo->SetL( NULL,styleMask);
CleanupStack::PopAndDestroy(); // styleFormat
//
// Create style table and insert styles.
TheStyleList=CStyleList::NewL();
RParagraphStyleInfo info(TheStyleOne);
TInt error=TheStyleList->AppendL(&info);
test(error==KErrNone);
RParagraphStyleInfo info1=TheStyleList->At(0);
CParagraphStyle* style=info1.iStyle;
style=NULL;
RParagraphStyleInfo info2(TheStyleTwo,TheStyleOne);
error=TheStyleList->AppendL(&info2);
test(error==KErrNone);
error=TheStyleList->AppendL(&info2);
test(error==KErrAlreadyExists);
test(TheStyleList->Count()==2);
style=TheStyleList->At(1).iStyle;
test(style->iName==_L("Style2"));
//
// Create the rich text with styles.
TheText=CRichText::NewL(TheNormalParaLayer,TheNormalCharLayer,*TheStyleList);
}
LOCAL_C void ConstructEnvironment()
// Create some styles.
//
{
// Create global layers
CParaFormat* normalPara=CParaFormat::NewLC();
TParaFormatMask paraFormatMask;
normalPara->iHorizontalAlignment=CParaFormat::ELeftAlign;
paraFormatMask.SetAttrib(EAttAlignment);
TheNormalParaLayer=CParaFormatLayer::NewL(normalPara,paraFormatMask);
CleanupStack::PopAndDestroy(); // normalPara
TCharFormat charFormat;
TCharFormatMask charFormatMask;
TheNormalCharLayer=CCharFormatLayer::NewL(charFormat,charFormatMask);
//
// Create some paragraph styles
TheStyleOne=CParagraphStyle::NewL(*TheNormalParaLayer,*TheNormalCharLayer);
TheStyleOne->iName=_L("Style1");
TheStyleTwo=CParagraphStyle::NewL(*TheNormalParaLayer,*TheNormalCharLayer);
TheStyleTwo->iName=_L("Style2");
//
CParaFormat* styleFormat=CParaFormat::NewLC();
TParaFormatMask styleMask;
styleFormat->iHorizontalAlignment=CParaFormat::ECenterAlign;
styleMask.SetAttrib(EAttAlignment);
TheStyleOne->SetL(styleFormat,styleMask);
//
styleFormat->iHorizontalAlignment=CParaFormat::ERightAlign;
TheStyleTwo->SetL(styleFormat,styleMask);
CleanupStack::PopAndDestroy(); // styleFormat
//
// Create style table and insert styles.
TheStyleList=CStyleList::NewL();
RParagraphStyleInfo info(TheStyleOne);
TInt error=TheStyleList->AppendL(&info);
test(error==KErrNone);
RParagraphStyleInfo info1=TheStyleList->At(0);
CParagraphStyle* style=info1.iStyle;
style=NULL;
RParagraphStyleInfo info2(TheStyleTwo,TheStyleOne);
error=TheStyleList->AppendL(&info2);
test(error==KErrNone);
error=TheStyleList->AppendL(&info2);
test(error==KErrAlreadyExists);
test(TheStyleList->Count()==2);
style=TheStyleList->At(1).iStyle;
test(style->iName==_L("Style2"));
//
// Create the rich text with styles.
TheText=CRichText::NewL(TheNormalParaLayer,TheNormalCharLayer,*TheStyleList);
}
LOCAL_C void KillEnvironment()
// Kill everything
//
{
delete TheText;
// the style table is owned by the rich text, and is destroyed there.
delete TheNormalParaLayer;
delete TheNormalCharLayer;
}
LOCAL_C void TestConstruction()
// Test the construction/destruction of rich text with styles
//
{
__UHEAP_MARK;
ConstructEnvironment();
KillEnvironment();
__UHEAP_MARKEND;
}
LOCAL_C void TestParaWithNullParaFormat()
{
CParagraphStyle::TApplyParaStyleMode applyMode=CParagraphStyle::ERetainNoSpecificFormats;
test.Next(_L("Apply style to paragraph with NULL para format"));
ConstructEnvWithNullParaFormat();
TheText->InsertL(0,_L("HEADINGBODYTEXT"));
//
TheText->ApplyParagraphStyleL(*TheStyleList->At(1).iStyle,0,1,applyMode);
CParaFormat* paraFormat=CParaFormat::NewLC();
TheText->GetParagraphFormatL(paraFormat,0);
test(paraFormat->iHorizontalAlignment==CParaFormat::ECenterAlign);
//
TChar delimiter=CEditableText::EParagraphDelimiter;
TheText->InsertL(7,delimiter);
TheText->GetParagraphFormatL(paraFormat,6);
test(paraFormat->iHorizontalAlignment==CParaFormat::ECenterAlign);
TheText->GetParagraphFormatL(paraFormat,8);
test(paraFormat->iHorizontalAlignment==CParaFormat::ECenterAlign);
CleanupStack::PopAndDestroy();
KillEnvironment();
}
LOCAL_C void TestSharedPara()
// Test
//
{
CParagraphStyle::TApplyParaStyleMode applyMode=CParagraphStyle::ERetainNoSpecificFormats;
test.Next(_L("Apply style to shared paragraph"));
ConstructEnvironment();
TheText->InsertL(0,_L("HEADINGBODYTEXT"));
//
TheText->ApplyParagraphStyleL(*TheStyleList->At(0).iStyle,0,1,applyMode);
CParaFormat* paraFormat=CParaFormat::NewLC();
TheText->GetParagraphFormatL(paraFormat,0);
test(paraFormat->iHorizontalAlignment==CParaFormat::ECenterAlign);
//
TChar delimiter=CEditableText::EParagraphDelimiter;
TheText->InsertL(7,delimiter);
TheText->GetParagraphFormatL(paraFormat,6);
test(paraFormat->iHorizontalAlignment==CParaFormat::ECenterAlign);
TheText->GetParagraphFormatL(paraFormat,8);
test(paraFormat->iHorizontalAlignment==CParaFormat::ECenterAlign);
CleanupStack::PopAndDestroy();
KillEnvironment();
}
LOCAL_C void TestNonSharedPara()
//
{
CParagraphStyle::TApplyParaStyleMode applyMode=CParagraphStyle::ERetainNoSpecificFormats;
test.Next(_L("Apply style to non-shared paragraph"));
ConstructEnvironment();
//
TheText->InsertL(0,_L("This is paragraph one.This is paragraph number two."));
TChar delimiter=CEditableText::EParagraphDelimiter;
TheText->InsertL(22,delimiter);
//
TCharFormat charFormat;
TCharFormatMask charFormatMask;
charFormat.iFontPresentation.iStrikethrough=EStrikethroughOn;
charFormatMask.SetAttrib(EAttFontStrikethrough);
TheText->ApplyCharFormatL(charFormat,charFormatMask,0,4);
//
TheText->ApplyParagraphStyleL(*(TheStyleList->At(1).iStyle),0,TheText->DocumentLength(),applyMode);
//
CParaFormat* paraFormat=CParaFormat::NewLC();
TheText->GetParagraphFormatL(paraFormat,0);
test(paraFormat->iHorizontalAlignment=CParaFormat::ERightAlign);
//
TheText->GetParagraphFormatL(paraFormat,10);
test(paraFormat->iHorizontalAlignment=CParaFormat::ERightAlign);
//
TheText->GetParagraphFormatL(paraFormat,30);
test(paraFormat->iHorizontalAlignment=CParaFormat::ERightAlign);
//
CleanupStack::PopAndDestroy(); // para format
//
/*TEtextComponentInfo info=*/TheText->ComponentInfo();
CRichText* theCopy=CRichText::NewL(TheNormalParaLayer,TheNormalCharLayer);
testStoreRestoreL(*theCopy,*TheText);
test(IsEqual(theCopy,TheText));
//
theCopy->ApplyParagraphStyleL(*(TheStyleList->At(0).iStyle),25,1,applyMode);
CParagraphStyle* tempStyle = CParagraphStyle::NewL(*TheNormalParaLayer,*TheNormalCharLayer);
theCopy->InsertL(28,delimiter);
theCopy->InsertL(31,delimiter);
charFormat.iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
charFormatMask.ClearAll();
charFormatMask.SetAttrib(EAttFontStrokeWeight);
theCopy->ApplyCharFormatL(charFormat, charFormatMask, 33, 1);
theCopy->NotifyStyleChangedL(tempStyle, TheStyleList->At(0).iStyle);
//
delete theCopy;
delete tempStyle;
KillEnvironment();
}
LOCAL_C void TestStyles()
// Perform tests
//
{
TestSharedPara();
TestNonSharedPara();
}
LOCAL_C void TestStyleWithNullParaFormat()
{
TestParaWithNullParaFormat();
}
LOCAL_C void TestStyleList()
{
__UHEAP_MARK;
// Test 1
// Construction under OOM
test.Start(_L("Construction under OOM"));
CStyleList* list=NULL;
TInt nn;
for (nn=0; ;nn++)
{
__UHEAP_RESET;
__UHEAP_SETFAIL(RHeap::EDeterministic,nn);
__UHEAP_MARK;
TRAPD(ret,
list=CStyleList::NewL());
if (ret!=KErrNone)
{
__UHEAP_MARKEND;
test(list==NULL);
}
else
{
test(list!=NULL);
delete list;
list=NULL;
__UHEAP_MARKEND;
break;
}
}
__UHEAP_RESET;
TBuf<36> answer;
answer.Format(_L(" #allocs for full c'tion: %d\n"),nn-1);
test.Printf(answer);
// Test 2
// Populated style list, Append under OOM;
test.Next(_L("AppendL() under OOM"));
CParaFormatLayer* paraLayer=CParaFormatLayer::NewL();
CCharFormatLayer* charLayer=CCharFormatLayer::NewL();
__UHEAP_MARK;
list=CStyleList::NewL();
CParagraphStyle* style=NULL;
for (TInt mm=0;mm<KMaxStyleListGranularity;mm++)
{
style=CParagraphStyle::NewL(*paraLayer,*charLayer);
RParagraphStyleInfo info(style,NULL);
TInt r=list->AppendL(&info);
test(r==KErrNone);
}
test(list->Count()==KMaxStyleListGranularity);
for (TInt oo=0; ;oo++)
{
style=CParagraphStyle::NewL(*paraLayer,*charLayer);
RParagraphStyleInfo info(style);
__UHEAP_RESET;
__UHEAP_SETFAIL(RHeap::EDeterministic,oo);
TInt r=KErrNone;
TRAPD(ret,
r=list->AppendL(&info));
if (ret!=KErrNone)
{
test(r!=KErrAlreadyExists);
test(list->Count()==KMaxStyleListGranularity);
}
else
{
test(r==KErrNone);
test(list->Count()==KMaxStyleListGranularity+1);
break;
}
__UHEAP_RESET;
}
delete list;
list=NULL;
style=NULL;
__UHEAP_MARKEND;
__UHEAP_RESET;
// Test 3
// Inserting a duplicate
test.Next(_L("AppendL() a duplicate"));
list=CStyleList::NewL();
style=NULL;
for (TInt pp=0;pp<KMaxStyleListGranularity;pp++)
{
style=CParagraphStyle::NewL(*paraLayer,*charLayer);
RParagraphStyleInfo info(style,NULL);
list->AppendL(&info);
}
test(list->Count()==KMaxStyleListGranularity);
RParagraphStyleInfo info=list->At(0);
TInt r=list->AppendL(&info);
test(r==KErrAlreadyExists);
test(list->Count()==KMaxStyleListGranularity);
test(info.iStyle->CharFormatLayer()!=NULL); // the duplicate style has not been deleted.
delete list;
// Test 4
// Looking for a style by name that does not exist.
test.Next(_L("IndexByName() where style not present"));
list=CStyleList::NewL();
style=NULL;
TUint name='A';
for (TInt qq=0;qq<KMaxStyleListGranularity;qq++)
{
style=CParagraphStyle::NewL(*paraLayer,*charLayer);
style->iName.Append(name);
name++;
RParagraphStyleInfo info(style,NULL);
list->AppendL(&info);
}
test(list->Count()==KMaxStyleListGranularity);
TParagraphStyleName search=_L("not present");
/*TInt index=*/list->IndexByName(search);
delete list;
delete paraLayer;
delete charLayer;
__UHEAP_MARKEND;
test.End();
}
LOCAL_C void TestHarness()
// Test rich text style usage.
//
{
test.Start(_L(" @SYMTestCaseID:SYSLIB-TTEXT-LEGACY-T_STYLE-0001 RichText Styles "));
// Do the tests.
TestConstruction();
TestStyles();
TestStyleWithNullParaFormat();
test.Next(_L("CStyleList"));
TestStyleList();
//
}
LOCAL_C void setupCleanup()
//
// Initialise the cleanup stack.
//
{
TheTrapCleanup=CTrapCleanup::New();
TRAPD(r,\
{\
for (TInt i=KTestCleanupStack;i>0;i--)\
CleanupStack::PushL((TAny*)1);\
test(r==KErrNone);\
CleanupStack::Pop(KTestCleanupStack);\
});
}
LOCAL_C void DeleteDataFile(const TDesC& aFullName)
{
RFs fsSession;
TInt err = fsSession.Connect();
if(err == KErrNone)
{
TEntry entry;
if(fsSession.Entry(aFullName, entry) == KErrNone)
{
RDebug::Print(_L("Deleting \"%S\" file.\n"), &aFullName);
err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly);
if(err != KErrNone)
{
RDebug::Print(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName);
}
err = fsSession.Delete(aFullName);
if(err != KErrNone)
{
RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName);
}
}
fsSession.Close();
}
else
{
RDebug::Print(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName);
}
}
GLDEF_C TInt E32Main()
//
// Test the streaming framework.
//
{
test.Title();
__UHEAP_MARK;
setupCleanup();
TRAPD(r,TestHarness());
test(r == KErrNone);
delete TheTrapCleanup;
__UHEAP_MARKEND;
::DeleteDataFile(KOutputFile); //deletion of data files must be before call to End() - DEF047652
test.End();
test.Close();
return 0;
}