--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/textformatting/test/src/TUndo.cpp Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,3576 @@
+/*
+* Copyright (c) 2000-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:
+* TUndo.cpp test file for UndoSystem classes
+*
+*/
+
+
+#include <e32test.h>
+
+#include "UndoSystem.h"
+#include "UndoSystemImpl.h"
+#include "EditorUndo.h"
+#include "EditorPlainTextUndo.h"
+#include <txtetext.h>
+#include <conpics.h>
+#include <s32mem.h>
+#include <s32ucmp.h>
+#include "TGraphicsContext.h"
+#include "form_and_etext_editor.h"
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <txtclipboard.h>
+#include "txtfmlyr_internal.h"
+#endif
+
+#define UNUSED_VAR(a) a = a
+
+using namespace UndoSystem;
+
+namespace
+{
+CTrapCleanup* TrapCleanup;
+RTest test(_L("TUndo - Undo system"));
+}
+
+//
+//
+// logger
+//
+//
+
+class CLogger : public CBase
+ {
+public:
+ virtual void Output(const TDesC& aText) = 0;
+ void Output(TInt a)
+ {
+ TBuf<16> num(_L("<"));
+ num.AppendNum(a);
+ num.Append(_L(">"));
+ Output(num);
+ }
+ };
+
+namespace
+{
+CLogger& operator<<(CLogger& aLog, const TDesC& aText)
+ {
+ aLog.Output(aText);
+ return aLog;
+ }
+CLogger& operator<<(CLogger& aLog, TInt aVal)
+ {
+ aLog.Output(aVal);
+ return aLog;
+ }
+}
+
+class CCheckingLogger : public CLogger
+ {
+ const TDesC* iCheck;
+ TInt iPos;
+ TBool iFailed;
+public:
+ void SetCheckString(const TDesC& aCheck) { iCheck = &aCheck; iPos = 0; iFailed = EFalse; }
+ TBool Failed() { return iFailed; }
+ TBool Passed() { return !iFailed && iCheck && iCheck->Length() == iPos; }
+ void Output(const TDesC& aText)
+ {
+ if (!iCheck || iFailed)
+ return;
+ TInt length = aText.Length();
+ TInt maxLength = iCheck->Length() - iPos;
+ TPtrC mid = iCheck->Mid(iPos, length < maxLength? length : maxLength);
+ if (aText.Compare(mid) != 0)
+ iFailed = ETrue;
+ else
+ iPos += aText.Length();
+ }
+ };
+
+class CStoringLogger : public CLogger
+ {
+ HBufC* iStore;
+ TInt iMaxLength;
+public:
+ ~CStoringLogger() { delete iStore; }
+ HBufC* GetStore() { HBufC* r = iStore; iStore = 0; iMaxLength = 0; return r; }
+ void Output(const TDesC& aText)
+ {
+ if (!iStore)
+ {
+ iStore = HBufC::NewL(50);
+ iMaxLength = 50;
+ }
+ while (iMaxLength < aText.Length() + iStore->Length())
+ {
+ iMaxLength *= 2;
+ iStore = iStore->ReAllocL(iMaxLength);
+ }
+ iStore->Des().Append(aText);
+ };
+ };
+
+//
+//
+// commands
+//
+//
+
+// internal commands
+class CCommandOffset;
+class CCommandToggle;
+class CTestCommand : public CSingleCommand
+ {
+public:
+ TUid FamilyUid() const
+ {
+ return TUid::Uid(12345);
+ }
+ virtual CCommandOffset* CastToCCommandOffset() { return 0; }
+ virtual CCommandToggle* CastToCCommandToggle() { return 0; }
+ };
+
+// Offset
+class CCommandOffset : public CTestCommand
+ {
+ TInt iOffset;
+ TInt* iTarget;
+ CLogger* iLogger;
+ CCommandOffset() {}
+public:
+ static CCommandOffset* NewL(TInt aOffset, TInt* aTarget, CLogger* aLogger = 0)
+ {
+ CCommandOffset* r = new(ELeave) CCommandOffset;
+ r->iOffset = aOffset;
+ r->iTarget = aTarget;
+ r->iLogger = aLogger;
+ return r;
+ }
+ void SetLogger(CLogger* aLogger) { iLogger = aLogger; }
+ TInt ExecuteL() const
+ {
+ if (iLogger)
+ (*iLogger) << _L("offset") << iOffset;
+ *iTarget += iOffset;
+ return KErrNone;
+ }
+ CCommand* CreateInverseL() const
+ {
+ return NewL(-iOffset, iTarget, iLogger);
+ }
+ void Add(TInt aOffset) { iOffset += aOffset; }
+ CCommandOffset* CastToCCommandOffset() { return this; }
+ };
+
+// Negate (only if iTog is ETrue!)
+class CCommandToggle : public CTestCommand
+ {
+ TBool iTog;
+ TInt* iTarget;
+ CLogger* iLogger;
+ CCommandToggle() {}
+public:
+ static CCommandToggle* NewL(TBool aTog, TInt* aTarget, CLogger* aLogger = 0)
+ {
+ CCommandToggle* r = new(ELeave) CCommandToggle;
+ r->iTog = aTog;
+ r->iTarget = aTarget;
+ r->iLogger = aLogger;
+ return r;
+ }
+ void SetLogger(CLogger* aLogger) { iLogger = aLogger; }
+ TInt ExecuteL() const
+ {
+ if (iLogger)
+ {
+ (*iLogger) << _L("negate") << (iTog? 1:0);
+ }
+ if (iTog)
+ *iTarget = -*iTarget;
+ return KErrNone;
+ }
+ CCommand* CreateInverseL() const
+ {
+ return NewL(iTog, iTarget, iLogger);
+ }
+ void Add(TBool aTog)
+ {
+ if (aTog)
+ iTog = !iTog;
+ }
+ CCommandToggle* CastToCCommandToggle() { return this; }
+ };
+
+// command prototypes
+class CCommandIncProto : public CTestCommand
+ {
+ TInt* iTarget;
+ CLogger* iLogger;
+ CCommandIncProto() {}
+public:
+ static CCommandIncProto* NewL(TInt* aTarget, CLogger* aLogger = 0)
+ {
+ CCommandIncProto* r = new(ELeave) CCommandIncProto;
+ r->iTarget = aTarget;
+ r->iLogger = aLogger;
+ return r;
+ }
+ TInt ExecuteL() const
+ {
+ if (iLogger)
+ (*iLogger) << _L("inc<>");
+ ++*iTarget;
+ return KErrNone;
+ }
+ CCommand* CreateInverseL() const
+ {
+ return CCommandOffset::NewL(-1, iTarget, iLogger);
+ }
+ TBool PrepareToAddInverseToLastL(CSingleCommand& aLastCommand) const
+ {
+ if (aLastCommand.FamilyUid() != TUid::Uid(12345))
+ return EFalse;
+ return !!static_cast<CTestCommand&>(aLastCommand).CastToCCommandOffset();
+ }
+ void AddInverseToLast(CSingleCommand& aLastCommand) const
+ {
+ CCommandOffset* c =
+ static_cast<CTestCommand&>(aLastCommand).CastToCCommandOffset();
+ ASSERT(c);
+ c->Add(-1);
+ }
+ };
+
+class CCommandDecProto : public CTestCommand
+ {
+ TInt* iTarget;
+ CLogger* iLogger;
+ CCommandDecProto() {}
+public:
+ static CCommandDecProto* NewL(TInt* aTarget, CLogger* aLogger = 0)
+ {
+ CCommandDecProto* r = new(ELeave) CCommandDecProto;
+ r->iTarget = aTarget;
+ r->iLogger = aLogger;
+ return r;
+ }
+ TInt ExecuteL() const
+ {
+ if (iLogger)
+ (*iLogger) << _L("dec<>");
+ --*iTarget;
+ return KErrNone;
+ }
+ CCommand* CreateInverseL() const
+ {
+ return CCommandOffset::NewL(1, iTarget, iLogger);
+ }
+ TBool PrepareToAddInverseToLastL(CSingleCommand& aLastCommand) const
+ {
+ if (aLastCommand.FamilyUid() != TUid::Uid(12345))
+ return EFalse;
+ return !!static_cast<CTestCommand&>(aLastCommand).CastToCCommandOffset();
+ }
+ void AddInverseToLast(CSingleCommand& aLastCommand) const
+ {
+ CCommandOffset* c =
+ static_cast<CTestCommand&>(aLastCommand).CastToCCommandOffset();
+ ASSERT(c);
+ c->Add(1);
+ }
+ };
+
+class CCommandNegProto : public CTestCommand
+ {
+ TInt* iTarget;
+ CLogger* iLogger;
+ CCommandNegProto() {}
+public:
+ static CCommandNegProto* NewL(TInt* aTarget, CLogger* aLogger = 0)
+ {
+ CCommandNegProto* r = new(ELeave) CCommandNegProto;
+ r->iTarget = aTarget;
+ r->iLogger = aLogger;
+ return r;
+ }
+ TInt ExecuteL() const
+ {
+ if (iLogger)
+ (*iLogger) << _L("neg<>");
+ *iTarget = -*iTarget;
+ return KErrNone;
+ }
+ CCommand* CreateInverseL() const
+ {
+ return CCommandToggle::NewL(ETrue, iTarget, iLogger);
+ }
+ TBool PrepareToAddInverseToLastL(CSingleCommand& aLastCommand) const
+ {
+ if (aLastCommand.FamilyUid() != TUid::Uid(12345))
+ return EFalse;
+ return !!static_cast<CTestCommand&>(aLastCommand).CastToCCommandToggle();
+ }
+ void AddInverseToLast(CSingleCommand& aLastCommand) const
+ {
+ CCommandToggle* c =
+ static_cast<CTestCommand&>(aLastCommand).CastToCCommandToggle();
+ ASSERT(c);
+ c->Add(ETrue);
+ }
+ };
+
+// command whose inverse is a batch command
+class CCommandDecThenNegProto : public CTestCommand
+ {
+ TInt* iTarget;
+ CLogger* iLogger;
+ CCommandDecThenNegProto() {}
+public:
+ static CCommandDecThenNegProto* NewL(TInt* aTarget, CLogger* aLogger = 0)
+ {
+ CCommandDecThenNegProto* r = new(ELeave) CCommandDecThenNegProto;
+ r->iTarget = aTarget;
+ r->iLogger = aLogger;
+ return r;
+ }
+ TInt ExecuteL() const
+ {
+ if (iLogger)
+ (*iLogger) << _L("decneg<>");
+ *iTarget = -(*iTarget - 1);
+ return KErrNone;
+ }
+ CCommand* CreateInverseL() const
+ {
+ CBatchCommand* batch = CBatchCommand::NewLC();
+ batch->PushL(CCommandOffset::NewL(1, iTarget, iLogger));
+ batch->PushL(CCommandToggle::NewL(ETrue, iTarget, iLogger));
+ CleanupStack::Pop(batch);
+ return batch;
+ }
+ };
+
+class CCommandCannotDo : public CTestCommand
+ {
+ CLogger* iLogger;
+public:
+ static CCommandCannotDo* NewL(CLogger* aLogger)
+ {
+ CCommandCannotDo* r = new(ELeave) CCommandCannotDo;
+ r->iLogger = aLogger;
+ return r;
+ }
+ TInt ExecuteL() const
+ {
+ if (iLogger)
+ (*iLogger) << _L("nodo<>");
+ return KErrNotSupported;
+ }
+ CCommand* CreateInverseL() const
+ {
+ return 0;
+ }
+ };
+
+class CCommandCannotInvert : public CTestCommand
+ {
+ CLogger* iLogger;
+public:
+ static CCommandCannotInvert* NewL(CLogger* aLogger)
+ {
+ CCommandCannotInvert* r = new(ELeave) CCommandCannotInvert;
+ r->iLogger = aLogger;
+ return r;
+ }
+ TInt ExecuteL() const
+ {
+ if (iLogger)
+ (*iLogger) << _L("noinv<>");
+ return KErrNone;
+ }
+ CCommand* CreateInverseL() const
+ {
+ if (iLogger)
+ (*iLogger) << _L("noinvfail.");
+ User::Leave(KErrNotSupported);
+ return 0;
+ }
+ };
+
+class CCommandLeavesInvert : public CTestCommand
+ {
+ CLogger* iLogger;
+public:
+ mutable TBool iFail;
+ static CCommandLeavesInvert* NewL(CLogger* aLogger)
+ {
+ CCommandLeavesInvert* r = new(ELeave) CCommandLeavesInvert;
+ r->iLogger = aLogger;
+ r->iFail = ETrue;
+ return r;
+ }
+ TInt ExecuteL() const
+ {
+ if (iLogger)
+ (*iLogger) << _L("leaveinv<>");
+ return KErrNone;
+ }
+ CCommand* CreateInverseL() const
+ {
+ if (iFail)
+ {
+ iFail = EFalse;
+ if (iLogger)
+ (*iLogger) << _L("noinvfail.");
+ User::Leave(KErrNotFound);
+ }
+ return 0;
+ }
+ };
+
+class CCommandNoMemory : public CTestCommand
+ {
+ CLogger* iLogger;
+public:
+ TBool iFailInvert;
+ TBool iFailAddToLast;
+ TBool iFailExecute;
+ mutable TBool iLogExecuteFailed;
+
+ static CCommandNoMemory* NewL(CLogger* aLogger)
+ {
+ CCommandNoMemory* r = new(ELeave) CCommandNoMemory;
+ r->iLogger = aLogger;
+ r->iFailInvert = ETrue;
+ r->iFailAddToLast = ETrue;
+ r->iFailExecute = ETrue;
+ r->iLogExecuteFailed= ETrue;
+ return r;
+ }
+ TInt ExecuteL() const
+ {
+ if (iFailExecute)
+ {
+ if (iLogger && iLogExecuteFailed)
+ (*iLogger) << _L("nomemfailexe.");
+ iLogExecuteFailed = EFalse;
+ User::Leave(KErrNoMemory);
+ }
+ if (iLogger)
+ (*iLogger) << _L("nomem<>");
+ return KErrNone;
+ }
+ CCommand* CreateInverseL() const
+ {
+ if (iFailInvert)
+ {
+ if (iLogger)
+ (*iLogger) << _L("nomemfailinv.");
+ User::Leave(KErrNoMemory);
+ }
+ return 0;
+ }
+ TBool PrepareToAddInverseToLastL(CSingleCommand&) const
+ {
+ if (iFailAddToLast)
+ {
+ if (iLogger)
+ (*iLogger) << _L("nomemfailadd.");
+ User::Leave(KErrNoMemory);
+ }
+ return EFalse;
+ }
+ };
+
+// this gatekeeper refuses non-undoable requests
+class CRefuserGatekeeper : public CBase, public MNotUndoableGatekeeper
+ {
+public:
+ TBool RetryOutOfMemoryL(TInt)
+ {
+ return EFalse;
+ }
+ TBool AllowNotUndoableL(TInt)
+ {
+ return EFalse;
+ }
+ };
+
+// this gatekeeper permits all non-undoable requests
+// (not just KErrNotSupported and KErrNoMemory)
+class CPermitterGatekeeper : public CBase, public MNotUndoableGatekeeper
+ {
+public:
+ TBool RetryOutOfMemoryL(TInt)
+ {
+ return EFalse;
+ }
+ TBool AllowNotUndoableL(TInt)
+ {
+ return ETrue;
+ }
+ };
+
+// this gatekeeper makes the CCommandNoMemory fail less the more times it is called
+class CMemoryReclaimGatekeeper : public CRefuserGatekeeper
+ {
+public:
+ CCommandNoMemory* iTarget;
+ CMemoryReclaimGatekeeper(CCommandNoMemory* aTarget = 0) : iTarget(aTarget) {}
+ TBool RetryOutOfMemoryL(TInt aNumRetries)
+ {
+ if (aNumRetries == 0)
+ {
+ iTarget->iFailAddToLast = EFalse;
+ return ETrue;
+ }
+ if (aNumRetries == 1)
+ {
+ iTarget->iFailInvert = EFalse;
+ return ETrue;
+ }
+ if (aNumRetries == 2)
+ {
+ iTarget->iFailExecute = EFalse;
+ return ETrue;
+ }
+ return EFalse;
+ }
+ };
+
+
+//
+//
+// Editor
+//
+//
+
+// a cut-down set of attributes for testing purposes
+class CUndoTestPicture : public CPicture
+ {
+ TBuf<1> iDesc;
+public:
+ CUndoTestPicture(TInt aChar) : iDesc(1) { iDesc[0] = static_cast<TText>(aChar); }
+ void Draw(CGraphicsContext&, const TPoint&, const TRect&, MGraphicsDeviceMap*) const {}
+ void ExternalizeL(RWriteStream&) const {}
+ void GetOriginalSizeInTwips(TSize&) const {}
+ TPtrC Description() const { return iDesc; }
+ };
+
+struct TTestAttributes
+ {
+ TInt8 iCharFlags;
+ TInt8 iParFlags;
+ TInt8 iStyle;
+ TTestAttributes() : iCharFlags(0), iParFlags(0), iStyle(-1) {}
+ TBool operator==(TTestAttributes& a)
+ {
+ return iCharFlags == a.iCharFlags && iParFlags == a.iParFlags && iStyle == a.iStyle;
+ }
+ };
+CLogger& operator<<(CLogger& log, TTestAttributes& at)
+ {
+ TBuf<3> buf(_L("Aa0"));
+ buf[0] = (TText)(buf[0] + (at.iCharFlags & 15));
+ buf[1] = (TText)(buf[1] + (at.iParFlags & 15));
+ buf[2] = (TText)(buf[2] + at.iStyle);
+ return log << buf;
+ }
+// Test editor, badly behaved if something leaves.
+// The only formats supported are bold, italic, keep together and keep with next.
+class CTestEditor : public CBase, public MUnifiedEditor,
+ public MUnifiedEditor::MStyleSupport,
+ public MUnifiedEditor::MPictureSupport,
+ public MUnifiedEditor::MClipboardSupport
+ {
+ TTestAttributes iBase;
+ TTestAttributes iStyles[10];
+ TBuf<KMaxParagraphStyleName> iStyleNames[10];
+ TInt iNumStyles;
+ CArrayFix<TTestAttributes>* iAttrs;
+ CBufSeg* iText;
+ CArrayFix<CUndoTestPicture*>* iPics;
+
+ CTestEditor* ConstructL()
+ {
+ iText = CBufSeg::NewL(5 * sizeof(TText));
+ iAttrs = new(ELeave) CArrayFixFlat<TTestAttributes>(5);
+ iPics = new(ELeave) CArrayFixFlat<CUndoTestPicture*>(5);
+ return this;
+ }
+ TInt Style(const TDesC& aName) const
+ {
+ for (int i = 0; i != iNumStyles; ++i)
+ if (aName == iStyleNames[i])
+ return i;
+ return -1;
+ }
+ TInt InsertStylePos(const TDesC& aName) const
+ {
+ int i;
+ for (i = 0; i != iNumStyles; ++i)
+ if (aName.Compare(iStyleNames[i]) <= 0)
+ return i;
+ return i;
+ }
+ void ReassignStyles(TInt aFrom, TInt aTo)
+ {
+ ASSERT(-1 <= aTo && aTo < iNumStyles);
+ ASSERT(0 <= aFrom && aFrom < iNumStyles);
+ if (aTo == aFrom)
+ return;
+ TInt setTo = aTo;
+ if (aTo == -1)
+ aTo = iNumStyles - 1;
+ TInt low = aFrom;
+ TInt high = aTo;
+ TInt delta = -1;
+ if (aTo < aFrom)
+ {
+ low = aTo;
+ high = aFrom;
+ delta = 1;
+ }
+ TInt len = DocumentLength();
+
+ int i;
+ for (i = 0; i != len; ++i)
+ {
+ TTestAttributes* attr = &iAttrs->At(i);
+ if (aFrom == attr->iStyle)
+ attr->iStyle = static_cast<TInt8>(setTo);
+ else if (low <= attr->iStyle && attr->iStyle <= high)
+ attr->iStyle = static_cast<TInt8>(attr->iStyle + delta);
+ }
+ for (i = aFrom; i != aTo; i -= delta)
+ {
+ iStyles[i] = iStyles[i - delta];
+ iStyleNames[i] = iStyleNames[i - delta];
+ }
+ }
+ void DoDeleteStyle(TInt aForDeletion)
+ {
+ ASSERT(aForDeletion < iNumStyles);
+ ReassignStyles(aForDeletion, -1);
+ --iNumStyles;
+ }
+ void DoAddStyle(const TDesC& aNewName, const TTestAttributes& aAttr)
+ {
+ ASSERT(iNumStyles < 10);
+ TInt pos = InsertStylePos(aNewName);
+ ++iNumStyles;
+ ReassignStyles(iNumStyles - 1, pos);
+ iStyles[pos] = aAttr;
+ iStyleNames[pos] = aNewName;
+ }
+ static void BoldToAttr(TTestAttributes& aAttr, const TTmCharFormat& aCFormat)
+ {
+ if (aCFormat.iFontSpec.IsBold())
+ aAttr.iCharFlags |= 1;
+ else
+ aAttr.iCharFlags &= ~1;
+ }
+ static void ItalicToAttr(TTestAttributes& aAttr, const TTmCharFormat& aCFormat)
+ {
+ if (aCFormat.iFontSpec.IsItalic())
+ aAttr.iCharFlags |= 2;
+ else
+ aAttr.iCharFlags &= ~2;
+ }
+ static void CharFormatToAttr(TTestAttributes& aAttr, const TTmCharFormat& aCFormat)
+ {
+ aAttr.iCharFlags = 0;
+ BoldToAttr(aAttr, aCFormat);
+ ItalicToAttr(aAttr, aCFormat);
+ }
+ static void CharLayerToAttr(TTestAttributes& aAttr, const TTmCharFormatLayer& aCLayer)
+ {
+ if (aCLayer.iMask.iFlags & TTmCharFormatMask::EBold)
+ {
+ aAttr.iCharFlags |= 4;
+ BoldToAttr(aAttr, aCLayer.iFormat);
+ }
+ if (aCLayer.iMask.iFlags & TTmCharFormatMask::EItalic)
+ {
+ aAttr.iCharFlags |= 8;
+ ItalicToAttr(aAttr, aCLayer.iFormat);
+ }
+ }
+ static void KeepTogetherToAttr(TTestAttributes& aAttr, const RTmParFormat& aPFormat)
+ {
+ if (aPFormat.iFlags & RTmParFormat::EKeepTogether)
+ aAttr.iParFlags |= 1;
+ else
+ aAttr.iParFlags &= ~1;
+ }
+ static void KeepWithNextToAttr(TTestAttributes& aAttr, const RTmParFormat& aPFormat)
+ {
+ if (aPFormat.iFlags & RTmParFormat::EKeepWithNext)
+ aAttr.iParFlags |= 2;
+ else
+ aAttr.iParFlags &= ~2;
+ }
+ static void ParFormatToAttr(TTestAttributes& aAttr, const RTmParFormat& aPFormat)
+ {
+ aAttr.iParFlags = 0;
+ KeepTogetherToAttr(aAttr, aPFormat);
+ KeepWithNextToAttr(aAttr, aPFormat);
+ }
+ static void ParLayerToAttr(TTestAttributes& aAttr, const RTmParFormatLayer& aPLayer)
+ {
+ if (aPLayer.iMask.iFlags & TTmParFormatMask::EKeepTogether)
+ {
+ aAttr.iParFlags |= 4;
+ KeepTogetherToAttr(aAttr, aPLayer.iFormat);
+ }
+ if (aPLayer.iMask.iFlags & TTmParFormatMask::EKeepWithNext)
+ {
+ aAttr.iParFlags |= 8;
+ KeepWithNextToAttr(aAttr, aPLayer.iFormat);
+ }
+ }
+ static void BoldAttrToCharFormat(TTmCharFormat& aCFormat, const TTestAttributes& aAttr)
+ {
+ if (aAttr.iCharFlags & 1)
+ aCFormat.iFontSpec.SetBold(ETrue);
+ }
+ static void ItalicAttrToCharFormat(TTmCharFormat& aCFormat, const TTestAttributes& aAttr)
+ {
+ if (aAttr.iCharFlags & 2)
+ aCFormat.iFontSpec.SetItalic(ETrue);
+ }
+ static void ResetCharFormat(TTmCharFormat& aCFormat)
+ {
+ TTmCharFormat c;
+ aCFormat = c;
+ }
+ static void AttrToCharFormat(TTmCharFormat& aCFormat, const TTestAttributes& aAttr)
+ {
+ ResetCharFormat(aCFormat);
+ BoldAttrToCharFormat(aCFormat, aAttr);
+ ItalicAttrToCharFormat(aCFormat, aAttr);
+ }
+ static void MergeAttrToCharLayer(TTmCharFormatLayer& aCLayer, const TTestAttributes& aAttr)
+ {
+ if (aAttr.iCharFlags & 4)
+ {
+ aCLayer.iMask.iFlags |= TTmCharFormatMask::EBold;
+ BoldAttrToCharFormat(aCLayer.iFormat, aAttr);
+ }
+ if (aAttr.iCharFlags & 8)
+ {
+ aCLayer.iMask.iFlags |= TTmCharFormatMask::EItalic;
+ ItalicAttrToCharFormat(aCLayer.iFormat, aAttr);
+ }
+ }
+ static void AttrToCharLayer(TTmCharFormatLayer& aCLayer, const TTestAttributes& aAttr)
+ {
+ ResetCharFormat(aCLayer.iFormat);
+ aCLayer.iMask.iFlags = 0;
+ MergeAttrToCharLayer(aCLayer, aAttr);
+ }
+ static void ResetParFormat(RTmParFormat& aPFormat)
+ {
+ RTmParFormat p;
+ CleanupClosePushL(p);
+ aPFormat.CopyL(p);
+ CleanupStack::PopAndDestroy();
+ }
+ static void KeepTogetherAttrToParFormat(RTmParFormat& aPFormat, const TTestAttributes& aAttr)
+ {
+ if (aAttr.iParFlags & 1)
+ aPFormat.iFlags |= RTmParFormat::EKeepTogether;
+ }
+ static void KeepWithNextAttrToParFormat(RTmParFormat& aPFormat, const TTestAttributes& aAttr)
+ {
+ if (aAttr.iParFlags & 2)
+ aPFormat.iFlags |= RTmParFormat::EKeepWithNext;
+ }
+ static void AttrToParFormat(RTmParFormat& aPFormat, const TTestAttributes& aAttr)
+ {
+ ResetParFormat(aPFormat);
+ KeepTogetherAttrToParFormat(aPFormat, aAttr);
+ KeepWithNextAttrToParFormat(aPFormat, aAttr);
+ }
+ static void MergeAttrToParLayer(RTmParFormatLayer& aPLayer, const TTestAttributes& aAttr)
+ {
+ if (aAttr.iParFlags & 4)
+ {
+ aPLayer.iMask.iFlags |= TTmParFormatMask::EKeepTogether;
+ KeepTogetherAttrToParFormat(aPLayer.iFormat, aAttr);
+ }
+ if (aAttr.iParFlags & 8)
+ {
+ aPLayer.iMask.iFlags |= TTmParFormatMask::EKeepWithNext;
+ KeepWithNextAttrToParFormat(aPLayer.iFormat, aAttr);
+ }
+ }
+ static void AttrToParLayer(RTmParFormatLayer& aPLayer, const TTestAttributes& aAttr)
+ {
+ ResetParFormat(aPLayer.iFormat);
+ aPLayer.iMask.iFlags = 0;
+ MergeAttrToParLayer(aPLayer, aAttr);
+ }
+public:
+ ~CTestEditor()
+ {
+ delete iAttrs;
+ // workaround for CBufSeg bug
+ if (0 < iText->Size())
+ iText->Delete(iText->Size() - 1, 1);
+ delete iText;
+ delete iPics;
+ }
+ static CTestEditor* NewL() { return (new(ELeave) CTestEditor)->ConstructL(); }
+ void Reset()
+ {
+ iAttrs->Reset();
+ iText->Reset();
+ iPics->Reset();
+ iNumStyles = 0;
+ }
+ void AlterGranularityL(TInt aNewGranularity)
+ {
+ CBufSeg* newIText = CBufSeg::NewL(aNewGranularity * sizeof(TText));
+ CleanupStack::PushL(newIText);
+ TBuf8<32> transfer;
+ TInt pos = 0;
+ while (pos < iText->Size())
+ {
+ TInt length = transfer.MaxLength();
+ if (iText->Size() - pos < length)
+ length = iText->Size() - pos;
+ iText->Read(pos, transfer, length);
+ newIText->InsertL(pos, transfer, length);
+ pos += transfer.Length();
+ }
+ CleanupStack::Pop(newIText);
+ // workaround for CBufSeg bug
+ if (0 < iText->Size())
+ iText->Delete(iText->Size() - 1, 1);
+ delete iText;
+ iText = newIText;
+ }
+ void Print(CLogger& log)
+ {
+ TInt length = DocumentLength();
+ int i;
+ log << _L("text{");
+ for (i = 0; i < length;)
+ {
+ TPtrC seg;
+ GetText(i, seg);
+ TInt picPos = seg.Locate(CEditableText::EPictureCharacter);
+ if (0 < picPos)
+ {
+ // shorten seg to just before the picture character
+ TPtrC temp(seg.Ptr(), picPos);
+ seg.Set(temp);
+ }
+ if (0 == picPos)
+ {
+ CUndoTestPicture* pic = iPics->At(i);
+ if (pic)
+ log << _L("{pic:") << pic->Description() << _L("}");
+ else
+ log << _L("{nopic}");
+ ++i;
+ }
+ else
+ {
+ log << seg;
+ i += seg.Length();
+ }
+ }
+ log << _L("} styles{");
+ for(i = 0; i != iNumStyles; ++i)
+ {
+ if (i)
+ log << _L(", ");
+ log << iStyleNames[i] << _L(":") << iStyles[i];
+ }
+ log << _L("} attr{");
+ for (i = 0; i != length; ++i)
+ log << iAttrs->At(i);
+ log << _L("} ");
+ }
+ MTmOptionalInterface* Interface(TUint aId)
+ {
+ if (aId == KUidMUnifiedEditorStyleSupport)
+ return static_cast<MUnifiedEditor::MStyleSupport*>(this);
+ if (aId == KUidMUnifiedEditorPictureSupport)
+ return static_cast<MUnifiedEditor::MPictureSupport*>(this);
+ if (aId == KUidMUnifiedEditorClipboardSupport)
+ return static_cast<MUnifiedEditor::MClipboardSupport*>(this);
+ return 0;
+ }
+
+ void InsertTextL(TInt aPos, const TDesC& aText,
+ const TDesC* aStyle,
+ const TTmCharFormatLayer* aCharFormat,
+ const RTmParFormatLayer* aParFormat)
+ {
+ TTestAttributes attr;
+ attr.iStyle = aStyle? (TInt8)Style(*aStyle) : (TInt8)-1;
+ if (aCharFormat)
+ CharLayerToAttr(attr, *aCharFormat);
+ if (aParFormat)
+ ParLayerToAttr(attr, *aParFormat);
+ iText->InsertL(aPos * sizeof(TText), aText.Ptr(), aText.Length() * sizeof(TText));
+ iAttrs->InsertL(aPos, attr, aText.Length());
+ CUndoTestPicture* nullPic = 0;
+ iPics->InsertL(aPos, nullPic, aText.Length());
+ }
+ void DeleteTextL(TInt aPos, TInt aLength)
+ {
+ iText->Delete(aPos * sizeof(TText), aLength * sizeof(TText));
+ iAttrs->Delete(aPos, aLength);
+ for (int i = aPos; i != aPos + aLength; ++i)
+ delete iPics->At(i);
+ iPics->Delete(aPos, aLength);
+ }
+ void SetBaseFormatL(const TTmCharFormat& aCharFormat,const RTmParFormat& aParFormat)
+ {
+ CharFormatToAttr(iBase, aCharFormat);
+ ParFormatToAttr(iBase, aParFormat);
+ }
+ void SetCharFormatL(TInt aPos,TInt aLength,const TTmCharFormatLayer& aFormat)
+ {
+ TInt end = aPos + aLength;
+ if (DocumentLength() < end)
+ end = DocumentLength();
+ for (; aPos < end; ++aPos)
+ CharLayerToAttr(iAttrs->At(aPos), aFormat);
+ }
+ void SetParFormatL(TInt aPos,TInt aLength,const RTmParFormatLayer& aFormat)
+ {
+ TInt end = aPos + aLength;
+ if (DocumentLength() < end)
+ end = DocumentLength();
+ for (; aPos < end; ++aPos)
+ ParLayerToAttr(iAttrs->At(aPos), aFormat);
+ }
+ void DeleteCharFormatL(TInt aPos,TInt aLength)
+ {
+ TInt end = aPos + aLength;
+ if (DocumentLength() < end)
+ end = DocumentLength();
+ for (; aPos < end; ++aPos)
+ iAttrs->At(aPos).iCharFlags = 0;
+ }
+ void DeleteParFormatL(TInt aPos,TInt aLength)
+ {
+ TInt end = aPos + aLength;
+ if (DocumentLength() < end)
+ end = DocumentLength();
+ for (; aPos < end; ++aPos)
+ iAttrs->At(aPos).iParFlags = 0;
+ }
+ TInt CreateStyleL(const RTmStyle& aStyle)
+ {
+ TInt styleNo = Style(aStyle.iName);
+ if (0 <= styleNo)
+ return KErrAlreadyExists;
+ TTestAttributes newAttr;
+ CharLayerToAttr(newAttr, aStyle.iCharFormat);
+ ParLayerToAttr(newAttr, aStyle.iParFormat);
+ DoAddStyle(aStyle.iName, newAttr);
+ return KErrNone;
+ }
+ TInt ChangeStyleL(const RTmStyle& aStyle)
+ {
+ TInt styleNo = Style(aStyle.iName);
+ if (styleNo < 0)
+ return KErrNotFound;
+ iStyles[styleNo] = TTestAttributes();
+ CharLayerToAttr(iStyles[styleNo], aStyle.iCharFormat);
+ ParLayerToAttr(iStyles[styleNo], aStyle.iParFormat);
+ return KErrNone;
+ }
+ TInt SetStyleL(TInt aPos, TInt aLength, const TDesC& aName)
+ {
+ TInt styleNo(-1);
+ if (aName.Length())
+ {
+ styleNo = Style(aName);
+ if (styleNo < 0)
+ return KErrNotFound;
+ }
+ TInt end = aPos + aLength;
+ for (; aPos < end; ++aPos)
+ iAttrs->At(aPos).iStyle = (TInt8)styleNo;
+ return KErrNone;
+ }
+ TInt RenameStyleL(const TDesC& aOldName, const TDesC& aNewName)
+ {
+ TInt oldNo = Style(aOldName);
+ if (oldNo < 0)
+ return KErrNotFound;
+ TTestAttributes temp = iStyles[oldNo];
+ TInt newNo = InsertStylePos(aNewName);
+ if (oldNo < newNo)
+ --newNo;
+ ReassignStyles(oldNo, newNo);
+ iStyles[newNo] = temp;
+ iStyleNames[newNo] = aNewName;
+ return KErrNone;
+ }
+ TInt DeleteStyleL(const TDesC& aName)
+ {
+ TInt n = Style(aName);
+ if (n < 0)
+ return KErrNotFound;
+ DoDeleteStyle(n);
+ return KErrNone;
+ }
+ void InsertPictureL(TInt aPos, const TPictureHeader& aPictureIn)
+ {
+ TBuf<1> picChar(1);
+ picChar[0] = CEditableText::EPictureCharacter;
+ InsertTextL(aPos, picChar, 0, 0, 0);
+ iPics->At(aPos) = static_cast<CUndoTestPicture*>(aPictureIn.iPicture.AsPtr());
+ }
+ void DropPictureL(TInt aPos)
+ {
+ TPtrC ptr;
+ GetText(aPos, ptr);
+ if (ptr[0] == CEditableText::EPictureCharacter)
+ {
+ iPics->At(aPos) = 0;
+ DeleteTextL(aPos, 1);
+ }
+ }
+ void Picture(TInt aPos, TPictureHeader& aPictureOut) const
+ {
+ CPicture* pic = iPics->At(aPos);
+ aPictureOut.iPictureType = KUidXzePictureType;
+ aPictureOut.iPicture = pic;
+ }
+ TInt DocumentLength() const
+ {
+ return iText->Size() / sizeof(TText);
+ }
+ void GetText(TInt aPos, TPtrC& aText) const
+ {
+ iText->Compress();
+ if (DocumentLength() <= aPos)
+ aPos = DocumentLength();
+ TPtr8 ptr = iText->Ptr(aPos * sizeof(TText));
+ aText.Set((TText*)ptr.Ptr(), ptr.Length()/sizeof(TText));
+ }
+ void GetBaseFormatL(TTmCharFormat& aCharFormat, RTmParFormat& aParFormat) const
+ {
+ AttrToCharFormat(aCharFormat, iBase);
+ AttrToParFormat(aParFormat, iBase);
+ }
+ void GetCharFormat(TInt aPos, TFormatLevel aLevel,
+ TTmCharFormatLayer& aFormat, TInt& aRunLength) const
+ {
+ TInt length = DocumentLength();
+ if (length <= aPos)
+ {
+ aRunLength = 0;
+ return;
+ }
+ TTestAttributes attr = iAttrs->At(aPos);
+ if (aLevel == ESpecific)
+ {
+ AttrToCharLayer(aFormat, attr);
+ }
+ else
+ {
+ AttrToCharLayer(aFormat, iBase);
+ MergeAttrToCharLayer(aFormat, attr);
+ }
+ TInt pos = aPos + 1;
+ while (pos < length && attr == iAttrs->At(pos))
+ ++pos;
+ aRunLength = pos - aPos;
+ }
+ void GetParFormatL(TInt aPos, TFormatLevel aLevel,
+ RTmParFormatLayer& aFormat, TInt& aRunLength) const
+ {
+ TInt length = DocumentLength();
+ if (length <= aPos)
+ {
+ aRunLength = 0;
+ return;
+ }
+ TTestAttributes attr = iAttrs->At(aPos);
+ if (aLevel == ESpecific)
+ {
+ AttrToParLayer(aFormat, attr);
+ }
+ else
+ {
+ AttrToParLayer(aFormat, iBase);
+ MergeAttrToParLayer(aFormat, attr);
+ }
+ TInt pos = aPos + 1;
+ while (pos < length && attr == iAttrs->At(pos))
+ ++pos;
+ aRunLength = pos - aPos;
+ }
+ TInt StyleCount() const { return iNumStyles; }
+ void GetStyle(TInt aPos, TPtrC& aName, TInt& aRunLength) const
+ {
+ TInt length = DocumentLength();
+ if (aPos < 0 || length <= aPos)
+ {
+ aName.Set(iStyleNames[0].Ptr(), 0);
+ aRunLength = 0;
+ return;
+ }
+ TInt styleNo = iAttrs->At(aPos).iStyle;
+ if (styleNo < 0)
+ aName.Set(iStyleNames[0].Ptr(), 0);
+ else
+ aName.Set(iStyleNames[styleNo]);
+ TInt pos = aPos + 1;
+ while (pos < length && iAttrs->At(pos).iStyle == styleNo)
+ ++pos;
+ aRunLength = pos - aPos;
+ return;
+ }
+ TInt GetStyleByNameL(const TDesC& aName, RTmStyle& aStyle) const
+ {
+ return GetStyleByIndexL(Style(aName), aStyle);
+ }
+ TInt GetStyleByIndexL(TInt aIndex, RTmStyle& aStyle) const
+ {
+ if (aIndex < 0 || iNumStyles <= aIndex)
+ return KErrNotFound;
+ aStyle.iName = iStyleNames[aIndex];
+ AttrToParLayer(aStyle.iParFormat, iStyles[aIndex]);
+ AttrToCharLayer(aStyle.iCharFormat, iStyles[aIndex]);
+ return KErrNone;
+ }
+ void CopyToStoreL(CStreamStore& aStore, CStreamDictionary& aDictionary,
+ TInt aPos, TInt aLength) const
+ {
+ ASSERT(aPos + aLength <= DocumentLength());
+ if (aLength <= 0)
+ return;
+ RStoreWriteStream stream;
+ TStreamId id = stream.CreateLC(aStore);
+ stream.WriteInt32L(aLength);
+ RBufReadStream input_stream(*iText, aPos * sizeof(TText));
+ TMemoryStreamUnicodeSource source(input_stream);
+ TUnicodeCompressor c;
+ c.CompressL(stream, source, KMaxTInt, aLength);
+ input_stream.Close();
+ stream.CommitL();
+ aDictionary.AssignL(KClipboardUidTypePlainText, id);
+ CleanupStack::PopAndDestroy(); // close stream
+
+ // now write out formatting in our own bizarre format
+ //...
+ // in actual fact this probably wouldn't test that much, so I won't
+ // bother right now.
+ }
+ void PasteFromStoreL(const CStreamStore& aStore,
+ const CStreamDictionary& aDictionary, TInt aPos)
+ {
+ ASSERT(aPos <= DocumentLength());
+ TStreamId id = aDictionary.At(KClipboardUidTypePlainText);
+ RStoreReadStream stream;
+ stream.OpenLC(aStore, id);
+ TInt length = stream.ReadInt32L();
+ RBufWriteStream bufferStream;
+ bufferStream.Insert(*iText, aPos * sizeof(TText));
+ TMemoryStreamUnicodeSink sink(bufferStream);
+ TUnicodeExpander e;
+ e.ExpandL(sink, stream, length);
+ bufferStream.CommitL();
+ bufferStream.Close();
+ CleanupStack::PopAndDestroy(); // close stream
+
+ // and if we get round to adding some formatting to the copy method,
+ // then we should deal with it here also
+ //...
+ // but not today. Just add the appropriate spaces into all the structures.
+ TTestAttributes attr;
+ iAttrs->InsertL(aPos, attr, length);
+ CUndoTestPicture* nullPic = 0;
+ iPics->InsertL(aPos, nullPic, length);
+ }
+ };
+
+CLogger& operator<<(CLogger& log, CTestEditor& ed) { ed.Print(log); return log; }
+
+// 1 - CCommandStack test
+TInt ExecuteStackL(CCommandStack& a)
+ {
+ while (a.Top())
+ {
+ CSingleCommand* single = a.Top()->Single();
+ if (!single)
+ {
+ test.Printf(_L("CCommandStack : stack unexpectedly contained batches"));
+ a.Reset();
+ return 1;
+ }
+ single->ExecuteL();
+ delete single;
+ a.Pop();
+ }
+ return 0;
+ }
+TInt CheckLog(CCheckingLogger& a)
+ {
+ if (a.Passed())
+ return 0;
+ test.Printf(_L("CCommandStack... : log failed"));
+ return 1;
+ }
+TInt CheckTop(CCommandStack& aStack, CCommand* aTop)
+ {
+ if (aStack.Top() != aTop)
+ {
+ test.Printf(_L("CCommandStack : unexpected item at top of stack"));
+ return 1;
+ }
+ return 0;
+ }
+TInt CheckCount(CCommandStack& aStack, TInt aExpectedCount)
+ {
+ if (aStack.Count() != aExpectedCount)
+ {
+ test.Printf(_L("CCommandStack : stack an unexpected size"));
+ return 1;
+ }
+ return 0;
+ }
+TInt CheckPop(CCommandStack& aStack)
+ {
+ CCommand* check = aStack.Top();
+ if (aStack.Pop() != check)
+ {
+ test.Printf(_L("CCommandStack : Pop() does not match Top()"));
+ return 1;
+ }
+ return 0;
+ }
+void AddStuffL(CCommandStack& aStack, TInt* aTarget, CLogger* aLog)
+ {
+ TInt startCount = aStack.Count();
+ CheckTop(aStack, 0);
+ aStack.PrepareToPushL(1);
+ CheckCount(aStack, startCount);
+ CheckTop(aStack, 0);
+ CheckCount(aStack, startCount);
+ CCommand* temp = CCommandIncProto::NewL(aTarget, aLog);
+ aStack.Push(temp);
+ CheckCount(aStack, startCount + 1);
+ CheckTop(aStack, temp);
+ aStack.PrepareToPushL(2);
+ CheckCount(aStack, startCount + 1);
+ CheckTop(aStack, temp);
+ CheckCount(aStack, startCount + 1);
+ CheckTop(aStack, temp);
+ aStack.PrepareToPushL(1);
+ aStack.PrepareToPushL(3);
+ CheckCount(aStack, startCount + 1);
+ CheckTop(aStack, temp);
+ temp = CCommandDecProto::NewL(aTarget, aLog);
+ CheckCount(aStack, startCount + 1);
+ aStack.Push(temp);
+ CheckCount(aStack, startCount + 2);
+ CheckTop(aStack, temp);
+ CheckTop(aStack, temp);
+ CheckCount(aStack, startCount + 2);
+ CheckTop(aStack, temp);
+ temp = CCommandIncProto::NewL(aTarget, aLog);
+ aStack.Push(temp);
+ CheckTop(aStack, temp);
+ CheckCount(aStack, startCount + 3);
+ aStack.PrepareToPushL(1);
+ CheckTop(aStack, temp);
+ aStack.PrepareToPushL(2);
+ CheckTop(aStack, temp);
+ temp = CCommandNegProto::NewL(aTarget, aLog);
+ CheckCount(aStack, startCount + 3);
+ aStack.Push(temp);
+ CheckCount(aStack, startCount + 4);
+ CheckTop(aStack, temp);
+ CheckCount(aStack, startCount + 4);
+ CheckTop(aStack, temp);
+ temp = CCommandIncProto::NewL(aTarget, aLog);
+ CheckCount(aStack, startCount + 4);
+ aStack.Push(temp);
+ CheckTop(aStack, temp);
+ CheckCount(aStack, startCount + 5);
+ }
+void TestCCommandStackL()
+ {
+ __UHEAP_MARK;
+ TInt target;
+ CCheckingLogger* log = new(ELeave) CCheckingLogger;
+
+ CCommandStack* stack = CCommandStack::NewL();
+
+ AddStuffL(*stack, &target, log);
+
+ log->SetCheckString(_L("inc<>neg<>inc<>dec<>inc<>"));
+ ExecuteStackL(*stack);
+ CheckLog(*log);
+
+ CheckCount(*stack, 0);
+ CCommand* temp = CCommandIncProto::NewL(&target, log);
+ CheckTop(*stack, 0);
+ stack->PrepareToPushL(1);
+ CheckCount(*stack, 0);
+ CheckTop(*stack, 0);
+ CheckCount(*stack, 0);
+ stack->Push(temp);
+ CheckCount(*stack, 1);
+ stack->PrepareToPushL(1);
+ CheckCount(*stack, 1);
+ CCommand* next = CCommandDecProto::NewL(&target, log);
+ stack->Push(next);
+ CheckCount(*stack, 2);
+ stack->PrepareToPushL(1);
+ CheckPop(*stack);
+ stack->PrepareToPushL(1);
+ CheckCount(*stack, 1);
+ CheckTop(*stack, temp);
+ CheckCount(*stack, 1);
+ stack->Push(next);
+ stack->PrepareToPushL(1);
+ CheckCount(*stack, 2);
+ CheckCount(*stack, 2);
+ CheckPop(*stack);
+ CheckCount(*stack, 1);
+ CheckTop(*stack, temp);
+ delete next;
+
+ stack->Reset();
+ CheckCount(*stack, 0);
+
+ AddStuffL(*stack, &target, log);
+ stack->PruneTo(3);
+ CheckCount(*stack, 3);
+ log->SetCheckString(_L("inc<>neg<>inc<>"));
+ ExecuteStackL(*stack);
+ CheckLog(*log);
+
+ AddStuffL(*stack, &target, log);
+ stack->PrepareToPushL(1);
+ CheckCount(*stack, 5);
+ stack->PruneTo(2);
+ CheckCount(*stack, 2);
+ log->SetCheckString(_L("inc<>neg<>"));
+ ExecuteStackL(*stack);
+ CheckLog(*log);
+
+ delete stack;
+ delete log;
+
+ __UHEAP_MARKENDC(0);
+ }
+
+// 2 - CBatchCommand test
+void ExecuteBatchL(CBatchCommand& a)
+ {
+ while (a.Top())
+ {
+ CSingleCommand* single = a.Top();
+ single->ExecuteL();
+ if (a.Pop() != single)
+ {
+ test.Printf(_L("CBatchCommand : Pop() didn't match Top()"));
+ test(0);
+ }
+ delete single;
+ }
+ test(1);
+ }
+void CheckTop(CBatchCommand& aBatch, CCommand* aTop)
+ {
+ if (aBatch.Top() != aTop)
+ {
+ test.Printf(_L("CCommandBatch : unexpected item at top of stack"));
+ test(0);
+ }
+ test(1);
+ }
+void TestCBatchCommandL()
+ {
+ __UHEAP_MARK;
+ TInt target = 0;
+ CCheckingLogger* log = new(ELeave) CCheckingLogger;
+
+ CBatchCommand* batch = CBatchCommand::NewL();
+
+ CBatchCommand* b1 = CBatchCommand::NewL();
+ CBatchCommand* b2 = CBatchCommand::NewL();
+ CBatchCommand* b3 = CBatchCommand::NewL();
+
+ CCommand* s1 = CCommandIncProto::NewL(&target, log);
+ CCommand* s2 = CCommandDecProto::NewL(&target, log);
+ CCommand* s3 = CCommandNegProto::NewL(&target, log);
+ CCommand* s4 = CCommandIncProto::NewL(&target, log);
+ CCommand* s5 = CCommandDecProto::NewL(&target, log);
+ CCommand* s6 = CCommandNegProto::NewL(&target, log);
+ CCommand* s7 = CCommandIncProto::NewL(&target, log);
+ CCommand* s8 = CCommandDecProto::NewL(&target, log);
+ CCommand* s9 = CCommandNegProto::NewL(&target, log);
+
+ b2->PrepareToPushL(s4);
+ b2->Push(s4);
+ b2->PrepareToPushL(s8);
+ b2->Push(s8);
+ b2->PrepareToPushL(s2);
+ b2->PrepareToPushL(s2);
+ b2->Push(s2);
+
+ b3->PrepareToPushL(s3);
+ b3->PrepareToPushL(s9);
+ b3->Push(s9);
+ b3->PrepareToPushL(s3);
+ b3->Push(s3);
+ b3->PrepareToPushL(s7);
+ b3->Push(s7);
+
+ b1->PrepareToPushL(s6);
+ b1->Push(s6);
+ b1->PrepareToPushL(s5);
+ b1->Push(s5);
+ b1->PrepareToPushL(b3);
+ b1->Push(b3);
+ b1->PrepareToPushL(b1);
+ b1->PrepareToPushL(s1);
+ b1->PrepareToPushL(s1);
+ b1->PrepareToPushL(b2);
+
+ batch->PrepareToPushL(b2);
+ batch->Push(b2);
+ batch->PrepareToPushL(s1);
+ batch->PrepareToPushL(s1);
+ batch->PrepareToPushL(b1);
+ batch->Push(b1);
+ batch->PrepareToPushL(s1);
+ batch->Push(s1);
+
+ CheckTop(*batch, s1);
+ batch->Pop();
+ CheckTop(*batch, s7);
+ batch->PrepareToPushL(s1);
+ CheckTop(*batch, s7);
+ batch->Push(s1);
+ CheckTop(*batch, s1);
+ batch->PrepareToPushL(s1);
+ CheckTop(*batch, s1);
+ batch->Pop();
+ CheckTop(*batch, s7);
+ batch->Pop();
+ CheckTop(*batch, s3);
+ batch->Pop();
+ CheckTop(*batch, s9);
+ batch->Pop();
+ CheckTop(*batch, s5);
+ batch->Pop();
+ CheckTop(*batch, s6);
+ batch->PrepareToPushL(s5);
+ CheckTop(*batch, s6);
+ batch->Push(s5);
+ CheckTop(*batch, s5);
+ b3 = CBatchCommand::NewL();
+ b3->PrepareToPushL(s9);
+ CheckTop(*b3, 0);
+ b3->Push(s9);
+ CheckTop(*b3, s9);
+ b3->PrepareToPushL(s3);
+ CheckTop(*b3, s9);
+ b3->Push(s3);
+ CheckTop(*b3, s3);
+ b3->PrepareToPushL(s7);
+ CheckTop(*b3, s3);
+ b3->Push(s7);
+ CheckTop(*b3, s7);
+ batch->PrepareToPushL(b3);
+ CheckTop(*batch, s5);
+ batch->Push(b3);
+ CheckTop(*batch, s7);
+ batch->PrepareToPushL(s1);
+ batch->Push(s1);
+
+ log->SetCheckString(_L("inc<>inc<>neg<>neg<>dec<>neg<>dec<>dec<>inc<>"));
+ ExecuteBatchL(*batch);
+ CheckLog(*log);
+
+ delete log;
+ delete batch;
+
+ __UHEAP_MARKENDC(0);
+ }
+
+// 3 - CCommandHistory test
+void ExecuteHistoryL(CCommandHistory& aHistory, CLogger& aLog)
+ {
+ while (aHistory.Top())
+ {
+ if (aHistory.Top()->Single())
+ {
+ aHistory.Top()->Single()->ExecuteL();
+ }
+ else
+ {
+ CBatchCommand* batch = aHistory.Top()->Batch();
+ test(batch != 0);
+ aLog << _L("batch{");
+ ExecuteBatchL(*batch);
+ aLog << _L("}");
+ }
+ delete aHistory.Pop();
+ }
+ }
+void TestCCommandHistoryL()
+ {
+ __UHEAP_MARK;
+
+ CCommandHistory* history = CCommandHistory::NewL();
+ CCheckingLogger* log = new(ELeave) CCheckingLogger;
+ TInt target;
+
+ CCommand* p;
+ history->SetMaxItems(5);
+ p = CCommandDecProto::NewL(&target, log);
+ history->PrepareToAddCommandL(p);
+ history->AddCommand(p);
+ p = CCommandIncProto::NewL(&target, log);
+ history->PrepareToAddCommandL(p);
+ history->AddCommand(p);
+ p = CCommandDecProto::NewL(&target, log);
+ history->PrepareToAddCommandL(p);
+ history->AddCommand(p);
+ p = CCommandNegProto::NewL(&target, log);
+ history->PrepareToAddCommandL(p);
+ history->AddCommand(p);
+ history->BeginBatchLC();
+ p = CCommandIncProto::NewL(&target, log);
+ history->PrepareToAddCommandL(p);
+ history->AddCommand(p);
+ p = CCommandDecProto::NewL(&target, log);
+ history->PrepareToAddCommandL(p);
+ history->AddCommand(p);
+ p = CCommandNegProto::NewL(&target, log);
+ history->PrepareToAddCommandL(p);
+ history->AddCommand(p);
+ CleanupStack::PopAndDestroy();
+ p = CCommandDecProto::NewL(&target, log);
+ history->PrepareToAddCommandL(p);
+ history->AddCommand(p);
+ CBatchCommand* batch = CBatchCommand::NewL();
+ p = CCommandDecProto::NewL(&target, log);
+ batch->PrepareToPushL(p);
+ batch->Push(p);
+ p = CCommandNegProto::NewL(&target, log);
+ batch->PrepareToPushL(p);
+ batch->Push(p);
+ p = CCommandIncProto::NewL(&target, log);
+ batch->PrepareToPushL(p);
+ batch->Push(p);
+ history->PrepareToAddCommandL(batch);
+ history->AddCommand(batch);
+ p = CCommandNegProto::NewL(&target, log);
+ history->PrepareToAddCommandL(p);
+ history->AddCommand(p);
+
+ log->SetCheckString(_L("neg<>batch{inc<>neg<>dec<>}dec<>batch{neg<>dec<>inc<>}neg<>"));
+ ExecuteHistoryL(*history, *log);
+ CheckLog(*log);
+
+ delete log;
+ delete history;
+
+ __UHEAP_MARKENDC(0);
+ }
+
+// 4 - CCommandManager test
+void TestCanUndo(const CCommandManager& aMan)
+ {
+ if (aMan.CanUndo())
+ {
+ test(1);
+ return;
+ }
+ test.Printf(_L("CCommandManager : unexpectedly could not undo"));
+ test(0);
+ }
+void TestCanRedo(const CCommandManager& aMan)
+ {
+ if (aMan.CanRedo())
+ {
+ test(1);
+ return;
+ }
+ test.Printf(_L("CCommandManager : unexpectedly could not redo"));
+ test(0);
+ }
+void TestCannotUndo(const CCommandManager& aMan)
+ {
+ if (!aMan.CanUndo())
+ {
+ test(1);
+ return;
+ }
+ test.Printf(_L("CCommandManager : unexpectedly could undo"));
+ test(0);
+ }
+void TestCannotRedo(const CCommandManager& aMan)
+ {
+ if (!aMan.CanRedo())
+ {
+ test(1);
+ return;
+ }
+ test.Printf(_L("CCommandManager : unexpectedly could undo"));
+ test(0);
+ }
+void SetUpTestL(CCommandManager& aMan, CSingleCommand& aCommand, TInt* aTarget, CLogger* aLogger)
+ {
+ CCommandIncProto* inc = CCommandIncProto::NewL(aTarget, aLogger);
+ CleanupStack::PushL(inc);
+ CCommandNegProto* neg = CCommandNegProto::NewL(aTarget, aLogger);
+ CleanupStack::PushL(neg);
+ CCommandDecProto* dec = CCommandDecProto::NewL(aTarget, aLogger);
+ CleanupStack::PushL(dec);
+
+ aMan.ExecuteL(*inc);
+ aMan.BeginBatchLC();
+ aMan.ExecuteL(*neg);
+ aMan.ExecuteL(aCommand);
+ aMan.ExecuteL(*dec);
+ CleanupStack::PopAndDestroy(); // close batch
+ aMan.ExecuteL(*neg);
+ aMan.UndoL();
+
+ CleanupStack::PopAndDestroy(dec);
+ CleanupStack::PopAndDestroy(neg);
+ CleanupStack::PopAndDestroy(inc);
+ }
+TInt CheckErrorCode(TInt aErr, TInt aExpected)
+ {
+ if (aErr == aExpected)
+ return 0;
+ if (aErr == KErrNone)
+ test.Printf(_L("CCommandManager : no leave where one was expected"));
+ else
+ test.Printf(_L("CCommandManager : unexpected leave code"));
+ return 1;
+ }
+void TestCCommandManagerL()
+ {
+ __UHEAP_MARK;
+
+ CCommandManager* manager = CCommandManager::NewL();
+ CCheckingLogger* log = new(ELeave) CCheckingLogger;
+ TInt target = 0;
+ CRefuserGatekeeper* refuser = new(ELeave) CRefuserGatekeeper;
+ CPermitterGatekeeper* permitter = new(ELeave) CPermitterGatekeeper;
+ CMemoryReclaimGatekeeper* reclaimer = new(ELeave) CMemoryReclaimGatekeeper;
+
+ TestCannotUndo(*manager);
+ TestCannotRedo(*manager);
+
+ CCommandIncProto* inc = CCommandIncProto::NewL(&target, log);
+ CCommandDecProto* dec = CCommandDecProto::NewL(&target, log);
+ CCommandNegProto* neg = CCommandNegProto::NewL(&target, log);
+
+ log->SetCheckString(_L("inc<>neg<>inc<>dec<>neg<>negate<1>"));
+ SetUpTestL(*manager, *inc, &target, log);
+ CheckLog(*log);
+ TestCanUndo(*manager);
+ TestCanRedo(*manager);
+ log->SetCheckString(_L("offset<0>negate<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCanUndo(*manager);
+ TestCanRedo(*manager);
+ log->SetCheckString(_L("offset<-1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ TestCanRedo(*manager);
+ log->SetCheckString(_L("offset<1>"));
+ manager->RedoL();
+ CheckLog(*log);
+ TestCanUndo(*manager);
+ TestCanRedo(*manager);
+ log->SetCheckString(_L("negate<1>offset<0>"));
+ manager->RedoL();
+ CheckLog(*log);
+ TestCanUndo(*manager);
+ TestCanRedo(*manager);
+ log->SetCheckString(_L("negate<1>"));
+ manager->RedoL();
+ CheckLog(*log);
+ TestCanUndo(*manager);
+ TestCannotRedo(*manager);
+ log->SetCheckString(_L("negate<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCanUndo(*manager);
+ TestCanRedo(*manager);
+ log->SetCheckString(_L("inc<>"));
+ manager->ExecuteL(*inc);
+ CheckLog(*log);
+ TestCanUndo(*manager);
+ TestCannotRedo(*manager);
+ log->SetCheckString(_L("offset<-1>negate<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCanUndo(*manager);
+ TestCanRedo(*manager);
+ log->SetCheckString(_L("negate<1>offset<1>"));
+ manager->RedoL();
+ CheckLog(*log);
+ TestCanUndo(*manager);
+ TestCannotRedo(*manager);
+
+ manager->ResetUndo();
+ TestCannotUndo(*manager);
+ TestCannotRedo(*manager);
+
+ // test coalescence
+
+ log->SetCheckString(_L("inc<>inc<>inc<>inc<>inc<>inc<>"));
+
+ manager->ExecuteL(*inc);
+ manager->ExecuteL(*inc);
+ manager->BeginBatchLC();
+ manager->ExecuteL(*inc);
+ manager->ExecuteL(*inc);
+ CleanupStack::PopAndDestroy(); // close batch
+ manager->ExecuteL(*inc);
+ manager->ExecuteL(*inc);
+ CheckLog(*log);
+
+ log->SetCheckString(_L("offset<-4>offset<-2>"));
+ manager->UndoL();
+ manager->UndoL();
+ CheckLog(*log);
+
+ log->SetCheckString(_L("offset<2>offset<4>"));
+ manager->RedoL();
+ manager->RedoL();
+ TestCannotRedo(*manager);
+ CheckLog(*log);
+
+ manager->ResetUndo();
+ TestCannotUndo(*manager);
+ TestCannotRedo(*manager);
+
+ // test command with batch inverse
+ log->SetCheckString(_L("inc<>decneg<>inc<>"));
+ CCommandDecThenNegProto* dnp = CCommandDecThenNegProto::NewL(&target, log);
+ manager->ExecuteL(*inc);
+ manager->ExecuteL(*dnp);
+ manager->ExecuteL(*inc);
+ CheckLog(*log);
+ delete dnp;
+ log->SetCheckString(_L("offset<-1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ log->SetCheckString(_L("negate<1>offset<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<-1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ manager->ResetUndo();
+
+ // Test case when undo is not supported
+ // 1. execution is permitted
+ log->SetCheckString(_L("inc<>neg<>noinvfail.noinv<>dec<>neg<>negate<1>"));
+ CCommandCannotInvert* noInv = CCommandCannotInvert::NewL(log);
+ SetUpTestL(*manager, *noInv, &target, log);
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ log->SetCheckString(_L("negate<1>"));
+ manager->RedoL();
+ CheckLog(*log);
+ TestCannotRedo(*manager);
+ manager->ResetUndo();
+
+ //2. execution is supressed
+ manager->SetGatekeeper(refuser);
+ log->SetCheckString(_L("inc<>neg<>noinvfail.dec<>neg<>negate<1>"));
+ SetUpTestL(*manager, *noInv, &target, log);
+ CheckLog(*log);
+ delete noInv;
+ log->SetCheckString(_L("offset<1>negate<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<-1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ manager->ResetUndo();
+ manager->SetGatekeeper(0);
+
+ // Test case when execution fails (with returned error code)
+ CCommandCannotDo* noDo = CCommandCannotDo::NewL(log);
+ log->SetCheckString(_L("inc<>neg<>nodo<>dec<>neg<>negate<1>"));
+ SetUpTestL(*manager, *noDo, &target, log);
+ delete noDo;
+ log->SetCheckString(_L("offset<1>negate<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<-1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ manager->ResetUndo();
+
+ // Test case when inversion fails (not inversion is reported as impossible)
+ // 1. when execution is permitted
+ manager->SetGatekeeper(permitter);
+ log->SetCheckString(_L("inc<>neg<>noinvfail.leaveinv<>dec<>neg<>negate<1>"));
+ CCommandLeavesInvert* leaveInv = CCommandLeavesInvert::NewL(log);
+ SetUpTestL(*manager, *leaveInv, &target, log);
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ log->SetCheckString(_L("negate<1>"));
+ manager->RedoL();
+ CheckLog(*log);
+ TestCannotRedo(*manager);
+ manager->ResetUndo();
+
+ // 2. when execution is supressed
+ manager->SetGatekeeper(refuser);
+ log->SetCheckString(_L("inc<>neg<>noinvfail.dec<>neg<>negate<1>"));
+ leaveInv->iFail = ETrue;
+ TRAPD(err, SetUpTestL(*manager, *leaveInv, &target, log));
+ CheckErrorCode(err, KErrNone);
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<1>negate<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<-1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ manager->ResetUndo();
+
+ // 3. when execution is terminated by leaving
+ manager->SetGatekeeper(0);
+ log->SetCheckString(_L("inc<>neg<>noinvfail."));
+ leaveInv->iFail = ETrue;
+ TRAP(err, SetUpTestL(*manager, *leaveInv, &target, log));
+ CheckErrorCode(err, KErrNotFound);
+ CheckLog(*log);
+ delete leaveInv;
+ log->SetCheckString(_L("negate<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<-1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ manager->ResetUndo();
+
+ // Test case when inversion runs out of memory
+ // 1. when execution is permitted with no undo
+ manager->SetGatekeeper(permitter);
+ log->SetCheckString(_L("inc<>neg<>nomemfailadd.nomem<>dec<>neg<>negate<1>"));
+ CCommandNoMemory* noMem = CCommandNoMemory::NewL(log);
+ noMem->iFailExecute = EFalse;
+ SetUpTestL(*manager, *noMem, &target, log);
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ log->SetCheckString(_L("negate<1>"));
+ manager->RedoL();
+ CheckLog(*log);
+ TestCannotRedo(*manager);
+ manager->ResetUndo();
+
+ // 2. when execution is supressed
+ manager->SetGatekeeper(refuser);
+ log->SetCheckString(_L("inc<>neg<>nomemfailadd.dec<>neg<>negate<1>"));
+ TRAP(err, SetUpTestL(*manager, *noMem, &target, log));
+ CheckErrorCode(err, KErrNone);
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<1>negate<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<-1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ manager->ResetUndo();
+ manager->SetGatekeeper(0);
+
+ // 3. when memory is reclaimed
+ reclaimer->iTarget = noMem;
+ manager->SetGatekeeper(reclaimer);
+ log->SetCheckString(_L("inc<>neg<>nomemfailadd.nomemfailinv.nomem<>dec<>neg<>negate<1>"));
+ TRAP(err, SetUpTestL(*manager, *noMem, &target, log));
+ CheckErrorCode(err, KErrNone);
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<1>negate<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<-1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ manager->ResetUndo();
+ manager->SetGatekeeper(0);
+
+ // Test when execution runs out of memory
+ // 1. with no reclaimation
+ noMem->iFailAddToLast = EFalse;
+ noMem->iFailInvert = EFalse;
+ noMem->iFailExecute = ETrue;
+ noMem->iLogExecuteFailed= ETrue;
+ log->SetCheckString(_L("inc<>neg<>nomemfailexe."));
+ TRAP(err, SetUpTestL(*manager, *noMem, &target, log));
+ CheckErrorCode(err, KErrNoMemory);
+ CheckLog(*log);
+ TestCannotRedo(*manager);
+ log->SetCheckString(_L("negate<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<-1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ manager->ResetUndo();
+ // 2. with reclaimation
+ noMem->iFailAddToLast = EFalse;
+ noMem->iFailInvert = EFalse;
+ noMem->iFailExecute = ETrue;
+ noMem->iLogExecuteFailed= ETrue;
+ reclaimer->iTarget = noMem;
+ manager->SetGatekeeper(reclaimer);
+ log->SetCheckString(_L("inc<>neg<>nomemfailexe.nomem<>dec<>neg<>negate<1>"));
+ TRAP(err, SetUpTestL(*manager, *noMem, &target, log));
+ CheckErrorCode(err, KErrNone);
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<1>negate<1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ log->SetCheckString(_L("offset<-1>"));
+ manager->UndoL();
+ CheckLog(*log);
+ TestCannotUndo(*manager);
+ manager->ResetUndo();
+ manager->SetGatekeeper(0);
+ delete noMem;
+
+ delete inc;
+ delete dec;
+ delete neg;
+ delete reclaimer;
+ delete refuser;
+ delete permitter;
+ delete log;
+ manager->Release();
+
+ __UHEAP_MARKENDC(0);
+ }
+
+//
+//
+// Tests involving CTestEditor
+//
+//
+
+void CheckEditorLog(CCheckingLogger& a)
+ {
+ if (a.Passed())
+ {
+ test(1);
+ return;
+ }
+ test.Printf(_L("EditorUndo : log failed"));
+ test(0);
+ }
+
+void TestPlainText(CTestEditor& aTestEditor, MUnifiedEditor& aUndoEditor,
+ CCommandManager& aCommandManager)
+ {
+ CCheckingLogger* check = new(ELeave) CCheckingLogger;
+ CStoringLogger* log = new(ELeave) CStoringLogger;
+
+ //
+ // general inserting and deleting text
+ //
+ aUndoEditor.InsertTextL(0, _L("Hello world!"), 0, 0, 0);
+
+ aCommandManager.ResetUndo();
+
+ aTestEditor.Print(*log);
+ HBufC* helloWorldLog = log->GetStore();
+
+ check->SetCheckString(*helloWorldLog);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+ aUndoEditor.InsertTextL(5, _L(" lovely"), 0, 0, 0);
+ aTestEditor.Print(*log);
+ HBufC* helloLovelyWorldLog = log->GetStore();
+ aUndoEditor.DeleteTextL(10, 8);
+ aTestEditor.Print(*log);
+ HBufC* helloLoveLog = log->GetStore();
+ aCommandManager.UndoL();
+ check->SetCheckString(*helloLovelyWorldLog);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+ aCommandManager.UndoL();
+ check->SetCheckString(*helloWorldLog);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+ aCommandManager.RedoL();
+ check->SetCheckString(*helloLovelyWorldLog);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+ aCommandManager.RedoL();
+ check->SetCheckString(*helloLoveLog);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+ aCommandManager.UndoL();
+ check->SetCheckString(*helloLovelyWorldLog);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+ aCommandManager.UndoL();
+ check->SetCheckString(*helloWorldLog);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aUndoEditor.InsertTextL(6, _L("w"), 0, 0, 0);
+ aUndoEditor.InsertTextL(7, _L("h"), 0, 0, 0);
+ aUndoEditor.InsertTextL(8, _L("at's"), 0, 0, 0);
+ aUndoEditor.InsertTextL(12, _L(" "), 0, 0, 0);
+ aUndoEditor.InsertTextL(13, _L("w"), 0, 0, 0);
+ aUndoEditor.InsertTextL(14, _L("i"), 0, 0, 0);
+ aUndoEditor.InsertTextL(6, _L("there "), 0, 0, 0);
+ aUndoEditor.InsertTextL(21, _L("t"), 0, 0, 0);
+ aUndoEditor.InsertTextL(22, _L("h"), 0, 0, 0);
+ aUndoEditor.InsertTextL(23, _L(" "), 0, 0, 0);
+ aTestEditor.Print(*log);
+ HBufC* textLog0 = log->GetStore();
+ aUndoEditor.InsertTextL(24, _L("the"), 0, 0, 0); // first of next
+ aUndoEditor.InsertTextL(27, _L(" "), 0, 0, 0);
+ aUndoEditor.InsertTextL(28, _L("d "), 0, 0, 0);
+ aUndoEditor.InsertTextL(28, _L("ol"), 0, 0, 0);
+ aTestEditor.Print(*log);
+ HBufC* textLog1 = log->GetStore();
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*textLog0);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*helloWorldLog);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ check->SetCheckString(*textLog0);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ check->SetCheckString(*textLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ // check coalescence of insertions
+ aTestEditor.AlterGranularityL(5);
+ aUndoEditor.DeleteTextL(22, 1);
+ aUndoEditor.DeleteTextL(21, 1);
+ aUndoEditor.DeleteTextL(20, 1);
+ aUndoEditor.DeleteTextL(19, 1);
+ aUndoEditor.DeleteTextL(18, 1);
+ aUndoEditor.DeleteTextL(18, 1);
+ aUndoEditor.DeleteTextL(15, 3); // this will coalesce
+ aUndoEditor.DeleteTextL(6, 9); // this won't, as it does not fit in one command
+ aTestEditor.Print(*log);
+ HBufC* delLog0 = log->GetStore();
+ aUndoEditor.DeleteTextL(4, 1);
+ aTestEditor.Print(*log);
+ HBufC* delLog1 = log->GetStore();
+ aUndoEditor.DeleteTextL(8, 2);
+ aUndoEditor.DeleteTextL(8, 1); // should coalesce
+ aUndoEditor.DeleteTextL(8, 1); // should coalesce
+ aTestEditor.Print(*log);
+ HBufC* delLog3 = log->GetStore();
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*delLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*delLog0);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ aCommandManager.UndoL();
+ check->SetCheckString(*textLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ aCommandManager.RedoL();
+ check->SetCheckString(*delLog0);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ check->SetCheckString(*delLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ check->SetCheckString(*delLog3);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*delLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*delLog0);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ aCommandManager.UndoL();
+ check->SetCheckString(*textLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ aCommandManager.UndoL();
+ check->SetCheckString(*helloWorldLog);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.ResetUndo();
+ delete delLog0;
+ delete delLog1;
+ delete delLog3;
+
+ // Check adding large amounts of text
+ aTestEditor.AlterGranularityL(32);
+ aUndoEditor.InsertTextL(0, _L("123456789"), 0, 0, 0);
+ aUndoEditor.InsertTextL(0, _L("223456789"), 0, 0, 0);
+ aTestEditor.Print(*log);
+ HBufC* largeLog0 = log->GetStore();
+ aUndoEditor.InsertTextL(0, _L("3234567890"), 0, 0, 0);
+ aUndoEditor.InsertTextL(0, _L("4234567890"), 0, 0, 0);
+ aTestEditor.Print(*log);
+ HBufC* largeLog1 = log->GetStore();
+ aUndoEditor.InsertTextL(0, _L("523456789"), 0, 0, 0);
+ aTestEditor.Print(*log);
+ HBufC* largeLog2 = log->GetStore();
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*largeLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*largeLog0);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*helloWorldLog);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ check->SetCheckString(*largeLog0);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ check->SetCheckString(*largeLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ check->SetCheckString(*largeLog2);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*largeLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*largeLog0);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*helloWorldLog);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ aCommandManager.RedoL();
+ aCommandManager.RedoL();
+
+ // test copy and paste
+ MUnifiedEditor::MClipboardSupport* ci = aUndoEditor.ClipboardSupport();
+ ASSERT(ci);
+
+ CBufStore* clipboardBuffer = CBufStore::NewL(100);
+ CStreamDictionary* clipboardDictionary = CStreamDictionary::NewL();
+
+ ci->CopyToStoreL(*clipboardBuffer, *clipboardDictionary, 5, 40);
+ aTestEditor.Print(*log);
+ HBufC* clipLog0 = log->GetStore();
+ ci->PasteFromStoreL(*clipboardBuffer, *clipboardDictionary, 2);
+ aTestEditor.Print(*log);
+ HBufC* clipLog1 = log->GetStore();
+ ci->PasteFromStoreL(*clipboardBuffer, *clipboardDictionary, 55);
+ aTestEditor.Print(*log);
+ HBufC* clipLog2 = log->GetStore();
+ ci->PasteFromStoreL(*clipboardBuffer, *clipboardDictionary, 23);
+ aTestEditor.Print(*log);
+ HBufC* clipLog3 = log->GetStore();
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*clipLog2);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*clipLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*clipLog0);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ check->SetCheckString(*clipLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ check->SetCheckString(*clipLog2);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.RedoL();
+ check->SetCheckString(*clipLog3);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*clipLog2);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*clipLog1);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ aCommandManager.UndoL();
+ check->SetCheckString(*clipLog0);
+ aTestEditor.Print(*check);
+ CheckEditorLog(*check);
+
+ delete clipLog0;
+ delete clipLog1;
+ delete clipLog2;
+ delete clipLog3;
+ delete clipboardDictionary;
+ delete clipboardBuffer;
+
+ delete textLog0;
+ delete textLog1;
+
+ delete largeLog0;
+ delete largeLog1;
+ delete largeLog2;
+
+ delete helloWorldLog;
+ delete helloLovelyWorldLog;
+ delete helloLoveLog;
+ delete log;
+ delete check;
+ }
+
+// This class merely splits the test function into little functions
+// to help out the MW compiler
+class TestEditorUndo
+ {
+ CCheckingLogger* check;
+ CStoringLogger* log;
+ CTestEditor* testEd;
+ CCommandManager* manager;
+ CEditorPlainTextWithUndo* plainEd;
+ CEditorWithUndo* ed;
+ TTmCharFormatMask charBMask;
+ TTmCharFormatMask charIMask;
+ TTmCharFormatMask charBIMask;
+ TOpenFontFaceAttribBase attrib;
+ TTmCharFormat charB;
+ TTmCharFormat charIB;
+ TTmCharFormat charI;
+ TTmParFormatMask parTMask;
+ TTmParFormatMask parNMask;
+ TTmParFormatMask parTNMask;
+ RTmParFormat par0;
+ RTmParFormat parT;
+ RTmParFormat parN;
+ RTmParFormat parTN;
+ TTmCharFormatLayer charLayer;
+ RTmParFormatLayer parLayer;
+ RTmStyle style1;
+ RTmStyle style2;
+ HBufC* charLog0;
+ HBufC* charLog1;
+ HBufC* charLog2;
+ HBufC* charLog3;
+ HBufC* textLog0;
+ HBufC* textLog1;
+ HBufC* textLog2;
+ HBufC* textLog3;
+ HBufC* parLog0;
+ HBufC* parLog1;
+ HBufC* parLog2;
+ HBufC* parLog3;
+ HBufC* delLog0;
+ HBufC* delLog1;
+ HBufC* delLog2;
+ HBufC* delLog3;
+ HBufC* styleLog1;
+ HBufC* styleLog2;
+ HBufC* styleLog3;
+ HBufC* styleLog4;
+ HBufC* styleLog5;
+ HBufC* styleLog6;
+ HBufC* styleLog7;
+ HBufC* styleLog8;
+ HBufC* styleLog9;
+ HBufC* styleLog10;
+ HBufC* styleLog11;
+ HBufC* styleLog12;
+ HBufC* styleLog13;
+ HBufC* picLog0;
+ HBufC* picLog1;
+ HBufC* picLog2;
+ HBufC* picLog3;
+ HBufC* picLog4;
+ HBufC* picLog5;
+ HBufC* bookMarkLog0;
+ HBufC* bookMarkLog1;
+ HBufC* bookMarkLog2;
+ HBufC* bookMarkLog3;
+ HBufC* bookMarkLog4;
+ HBufC* bookMarkLog5;
+public:
+ void Test1L();
+ void Test2L();
+ void Test3L();
+ void Test4L();
+ void Test5L();
+ void Test6L();
+ void Test7L();
+ void Test8L();
+ };
+
+void TestEditorUndo::Test1L()
+ {
+ check = new(ELeave) CCheckingLogger;
+ log = new(ELeave) CStoringLogger;
+ testEd = CTestEditor::NewL();
+ manager = CCommandManager::NewL();
+ plainEd = CEditorPlainTextWithUndo::NewL(*testEd, manager);
+
+ TestPlainText(*testEd, *plainEd, *manager);
+ ed = CEditorWithUndo::NewL(*testEd, manager);
+ testEd->DeleteTextL(0, testEd->DocumentLength());
+ manager->ResetUndo();
+
+ delete plainEd;
+ plainEd = 0;
+
+ TestPlainText(*testEd, *ed, *manager);
+ manager->Release();
+ }
+
+void TestEditorUndo::Test2L()
+ {
+ // char and par formats
+ charBMask.iFlags = TTmCharFormatMask::EBold;
+ charIMask.iFlags = TTmCharFormatMask::EItalic;
+ charBIMask.iFlags = TTmCharFormatMask::EItalic | TTmCharFormatMask::EBold;
+ attrib.SetBold(ETrue);
+ charB.iFontSpec.SetAttrib(attrib);
+ attrib.SetItalic(ETrue);
+ charIB.iFontSpec.SetAttrib(attrib);
+ attrib.SetBold(EFalse);
+ charI.iFontSpec.SetAttrib(attrib);
+
+ parTMask.iFlags = TTmParFormatMask::EKeepTogether;
+ parNMask.iFlags = TTmParFormatMask::EKeepWithNext;
+ parTNMask.iFlags = TTmParFormatMask::EKeepTogether | TTmParFormatMask::EKeepWithNext;
+ parT.iFlags = RTmParFormat::EKeepTogether;
+ parN.iFlags = RTmParFormat::EKeepWithNext;
+ parTN.iFlags = RTmParFormat::EKeepWithNext | RTmParFormat::EKeepTogether;
+
+ charLayer.iFormat = charB;
+ charLayer.iMask = charBMask;
+ ed->SetCharFormatL(0, 5, charLayer);
+ testEd->Print(*log);
+ charLog0 = log->GetStore();
+
+ charLayer.iFormat = charI;
+ charLayer.iMask = charIMask;
+ ed->SetCharFormatL(3, 9, charLayer);
+ testEd->Print(*log);
+ charLog1 = log->GetStore();
+
+ charLayer.iFormat = charB;
+ charLayer.iMask = charBIMask;
+ ed->SetCharFormatL(2, 5, charLayer);
+ testEd->Print(*log);
+ charLog2 = log->GetStore();
+
+ ed->DeleteCharFormatL(1, 10);
+ testEd->Print(*log);
+ charLog3 = log->GetStore();
+
+ ed->UndoL();
+ check->SetCheckString(*charLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*charLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*charLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*charLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*charLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*charLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ parLayer.iMask = parTMask;
+ parLayer.iFormat.CopyL(parT);
+ ed->SetParFormatL(5, 7, parLayer);
+ testEd->Print(*log);
+ parLog0 = log->GetStore();
+
+ parLayer.iMask = parTNMask;
+ parLayer.iFormat.CopyL(parN);
+ ed->SetParFormatL(0, 7, parLayer);
+ testEd->Print(*log);
+ parLog1 = log->GetStore();
+
+ ed->DeleteParFormatL(4, 4);
+ testEd->Print(*log);
+ parLog2 = log->GetStore();
+
+ parLayer.iMask = parNMask;
+ parLayer.iFormat.CopyL(parN);
+ ed->SetParFormatL(3, 6, parLayer);
+ testEd->Print(*log);
+ parLog3 = log->GetStore();
+
+ ed->UndoL();
+ check->SetCheckString(*parLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*parLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*parLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*charLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*parLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*parLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*parLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*parLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ }
+
+void TestEditorUndo::Test3L()
+ {
+ // check coalescence of deletions
+ charLayer.iMask = charIMask;
+ charLayer.iFormat = charI;
+ parLayer.iMask = parNMask;
+ parLayer.iFormat.CopyL(parN);
+ ed->InsertTextL(6, _L("w"), 0, &charLayer, &parLayer);
+ ed->InsertTextL(7, _L("h"), 0, &charLayer, &parLayer);
+ ed->InsertTextL(8, _L("at's"), 0, &charLayer, &parLayer);
+ ed->InsertTextL(12, _L(" "), 0, &charLayer, &parLayer);
+ ed->InsertTextL(13, _L("w"), 0, &charLayer, &parLayer);
+ ed->InsertTextL(14, _L("i"), 0, &charLayer, &parLayer);
+ ed->InsertTextL(6, _L("there "), 0, &charLayer, &parLayer);
+ ed->InsertTextL(21, _L("t"), 0, &charLayer, &parLayer);
+ ed->InsertTextL(22, _L("h"), 0, &charLayer, &parLayer);
+ ed->InsertTextL(23, _L(" "), 0, &charLayer, &parLayer);
+ testEd->Print(*log);
+ textLog0 = log->GetStore();
+ ed->InsertTextL(24, _L("the"), 0, &charLayer, &parLayer); // first of next?
+ ed->InsertTextL(27, _L(" "), 0, &charLayer, &parLayer);
+ testEd->Print(*log);
+ textLog1 = log->GetStore();
+ charLayer.iMask = charBIMask;
+ ed->InsertTextL(28, _L("ol"), 0, &charLayer, &parLayer);
+ testEd->Print(*log);
+ textLog2 = log->GetStore();
+ parLayer.iMask = parTNMask;
+ ed->InsertTextL(30, _L("d "), 0, &charLayer, &parLayer);
+ testEd->Print(*log);
+ textLog3 = log->GetStore();
+
+ ed->UndoL();
+ check->SetCheckString(*textLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*parLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*textLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*textLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ ed->ResetUndo();
+ }
+
+void TestEditorUndo::Test4L()
+ {
+ // check coalescence of insertions
+ testEd->AlterGranularityL(5);
+ ed->DeleteTextL(22, 1);
+ ed->DeleteTextL(21, 1);
+ ed->DeleteTextL(20, 1);
+ ed->DeleteTextL(19, 1);
+ ed->DeleteTextL(18, 1);
+ ed->DeleteTextL(18, 1);
+ ed->DeleteTextL(15, 3); // this will coalesce
+ ed->DeleteTextL(6, 9); // this won't, as it does not fit in one command
+ testEd->Print(*log);
+ delLog0 = log->GetStore();
+ ed->DeleteTextL(4, 1);
+ testEd->Print(*log);
+ delLog1 = log->GetStore();
+ ed->DeleteTextL(8, 2);
+ ed->DeleteTextL(8, 1); // should coalesce
+ testEd->Print(*log);
+ delLog2 = log->GetStore();
+ ed->DeleteTextL(8, 1); // should fail to coalesce
+ testEd->Print(*log);
+ delLog3 = log->GetStore();
+
+ ed->UndoL();
+ check->SetCheckString(*delLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*delLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*delLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ ed->UndoL();
+ check->SetCheckString(*textLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ ed->RedoL();
+ check->SetCheckString(*delLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*delLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*delLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*delLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*delLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*delLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*delLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ ed->UndoL();
+ check->SetCheckString(*textLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ ed->ResetUndo();
+ delete delLog0;
+ delete delLog1;
+ delete delLog2;
+ delete delLog3;
+ }
+
+void TestEditorUndo::Test5L()
+ {
+ // Check adding large amounts of text
+ testEd->AlterGranularityL(32);
+ ed->InsertTextL(0, _L("123456789"), 0, 0, 0);
+ ed->InsertTextL(0, _L("223456789"), 0, 0, 0);
+ testEd->Print(*log);
+ delete textLog0;
+ textLog0 = log->GetStore();
+ ed->InsertTextL(0, _L("3234567890"), 0, 0, 0);
+ ed->InsertTextL(0, _L("4234567890"), 0, 0, 0);
+ testEd->Print(*log);
+ delete textLog1;
+ textLog1 = log->GetStore();
+ ed->InsertTextL(0, _L("523456789"), 0, 0, 0);
+ testEd->Print(*log);
+ delete textLog2;
+ textLog2 = log->GetStore();
+
+ ed->UndoL();
+ check->SetCheckString(*textLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*textLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*textLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*textLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*textLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*textLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*textLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*textLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*textLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ }
+
+void TestEditorUndo::Test6L()
+ {
+ // test style manipulation
+ style1.iName = _L("author");
+ style2.iName = _L("title");
+ style2.iNextStyleName = _L("author");
+ style1.iCharFormat.iFormat = charI;
+ style1.iCharFormat.iMask = charIMask;
+ style1.iParFormat.iFormat.CopyL(parT);
+ style1.iParFormat.iMask = parTNMask;
+ style2.iCharFormat.iFormat = charB;
+ style2.iCharFormat.iMask = charBIMask;
+ style2.iParFormat.iFormat.CopyL(parN);
+ style2.iParFormat.iMask = parNMask;
+
+ ed->StyleSupport()->CreateStyleL(style1);
+ testEd->Print(*log);
+ styleLog1 = log->GetStore();
+ TInt retval = ed->StyleSupport()->SetStyleL(1, 3, _L("author"));
+ testEd->Print(*log);
+ styleLog2 = log->GetStore();
+ if (retval != KErrNone)
+ {
+ test.Printf(_L("EditorUndo : apply style failed"));
+ test(0);
+ }
+ TPtrC testStyleName;
+ TInt testStyleRunLength;
+ ed->StyleSupport()->GetStyle(1, testStyleName, testStyleRunLength);
+ if (testStyleRunLength != 3 || testStyleName != style1.iName)
+ {
+ test.Printf(_L("EditorUndo : apply style failed"));
+ test(0);
+ }
+ ed->InsertTextL(5, _L(","), &style1.iName, 0, 0);
+ testEd->Print(*log);
+ styleLog3 = log->GetStore();
+ ed->StyleSupport()->CreateStyleL(style2);
+ testEd->Print(*log);
+ styleLog4 = log->GetStore();
+ ed->StyleSupport()->SetStyleL(2, 7, _L("title"));
+ testEd->Print(*log);
+ styleLog5 = log->GetStore();
+ ed->StyleSupport()->SetStyleL(10, 4, _L("title"));
+ testEd->Print(*log);
+ styleLog6 = log->GetStore();
+ ed->StyleSupport()->SetStyleL(8, 4, _L("author"));
+ testEd->Print(*log);
+ styleLog7 = log->GetStore();
+ style1.iCharFormat.iFormat = charB;
+ style1.iCharFormat.iMask = charBMask;
+ ed->StyleSupport()->ChangeStyleL(style1);
+ testEd->Print(*log);
+ styleLog8 = log->GetStore();
+ ed->StyleSupport()->RenameStyleL(_L("author"), _L("version"));
+ style1.iName = _L("version");
+ testEd->Print(*log);
+ styleLog9 = log->GetStore();
+ retval = ed->StyleSupport()->SetStyleL(10, 1, _L("version"));
+ testEd->Print(*log);
+ styleLog10 = log->GetStore();
+ if (retval != KErrNone)
+ {
+ test.Printf(_L("EditorUndo : rename style failed"));
+ test(0);
+ }
+ ed->StyleSupport()->GetStyle(1, testStyleName, testStyleRunLength);
+ if (testStyleRunLength != 1 || testStyleName != style1.iName)
+ {
+ test.Printf(_L("EditorUndo : rename or apply style failed"));
+ test(0);
+ }
+ ed->StyleSupport()->RenameStyleL(_L("title"), _L("zip"));
+ style2.iName = _L("zip");
+ testEd->Print(*log);
+ styleLog11 = log->GetStore();
+ ed->StyleSupport()->SetStyleL(0, 6, _L("zip"));
+ testEd->Print(*log);
+ styleLog12 = log->GetStore();
+ ed->StyleSupport()->DeleteStyleL(_L("zip"));
+ testEd->Print(*log);
+ styleLog13 = log->GetStore();
+ ed->InsertTextL(0, _L("Well "), &style1.iName, 0, 0);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog13);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog12);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog11);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog10);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog9);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog8);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog7);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog6);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog5);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog4);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*styleLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*textLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog4);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog5);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog6);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog7);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog8);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog9);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog10);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog11);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog12);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*styleLog13);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ // probably need some more style tests that test the full range of
+ // attributes that a style may have.
+ //...
+
+ delete textLog0;
+ delete textLog1;
+ delete textLog2;
+ delete parLog0;
+ delete parLog1;
+ delete parLog2;
+ delete parLog3;
+ delete charLog0;
+ delete charLog1;
+ delete charLog2;
+ delete charLog3;
+ delete styleLog1;
+ delete styleLog2;
+ delete styleLog3;
+ delete styleLog4;
+ delete styleLog5;
+ delete styleLog6;
+ delete styleLog7;
+ delete styleLog8;
+ delete styleLog9;
+ delete styleLog10;
+ delete styleLog11;
+ delete styleLog12;
+ delete styleLog13;
+
+ delete textLog3;
+ }
+
+void TestEditorUndo::Test7L()
+ {
+ // test picture manipulation
+ TPictureHeader pic;
+ pic.iPictureType = KUidXzePictureType;
+ testEd->Print(*log);
+ picLog0 = log->GetStore();
+ pic.iPicture = new (ELeave) CUndoTestPicture('A');
+ ed->PictureSupport()->InsertPictureL(5, pic);
+ testEd->Print(*log);
+ picLog1 = log->GetStore();
+ pic.iPicture = new (ELeave) CUndoTestPicture('B');
+ ed->PictureSupport()->InsertPictureL(8, pic);
+ testEd->Print(*log);
+ picLog2 = log->GetStore();
+ pic.iPicture = new (ELeave) CUndoTestPicture('C');
+ ed->PictureSupport()->InsertPictureL(9, pic);
+ testEd->Print(*log);
+ picLog3 = log->GetStore();
+ pic.iPicture = new (ELeave) CUndoTestPicture('D');
+ ed->PictureSupport()->InsertPictureL(12, pic);
+ ed->StyleSupport()->SetStyleL(6, 2, style1.iName);
+ ed->SetCharFormatL(8, 3, charLayer);
+ ed->SetParFormatL(7, 7, parLayer);
+ testEd->Print(*log);
+ picLog4 = log->GetStore();
+ ed->DeleteTextL(5, 8);
+ testEd->Print(*log);
+ picLog5 = log->GetStore();
+
+ ed->UndoL();
+ check->SetCheckString(*picLog4);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ ed->UndoL();
+ ed->UndoL();
+ ed->UndoL();
+ check->SetCheckString(*picLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*picLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*picLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->UndoL();
+ check->SetCheckString(*picLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*picLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*picLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*picLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ ed->RedoL();
+ ed->RedoL();
+ ed->RedoL();
+ check->SetCheckString(*picLog4);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ ed->RedoL();
+ check->SetCheckString(*picLog5);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+
+ style1.Close();
+ style2.Close();
+ parLayer.Close();
+ par0.Close();
+ parT.Close();
+ parN.Close();
+ parTN.Close();
+ delete picLog0;
+ delete picLog1;
+ delete picLog2;
+ delete picLog3;
+ delete picLog4;
+ delete picLog5;
+ }
+
+void TestEditorUndo::Test8L()
+ {
+ // test bookmarking
+ for (TInt i = 0; i != 7; ++i)
+ {
+ testEd->Reset();
+ ed->ResetUndo();
+ if (i == 0)
+ manager->SetBookmark();
+ testEd->Print(*log);
+ bookMarkLog0 = log->GetStore();
+ ed->InsertTextL(0, _L("Hallo"), 0, 0, 0); // hallo
+ if (i == 1)
+ manager->SetBookmark();
+ testEd->Print(*log);
+ bookMarkLog1 = log->GetStore();
+ ed->DeleteTextL(2, 1); // halo
+ if (i == 2)
+ manager->SetBookmark();
+ testEd->Print(*log);
+ bookMarkLog2 = log->GetStore();
+ manager->BeginBatchLC();
+ ed->DeleteTextL(3, 1); // hal
+ ed->InsertTextL(3, _L("t, who goes there?"), 0, 0, 0); // halt, who goes there?
+ if (i == 3)
+ manager->SetBookmark(); // should not get set
+ ed->DeleteTextL(9, 5); // halt, who there?
+ CleanupStack::PopAndDestroy();
+ if (i == 4)
+ manager->SetBookmark();
+ testEd->Print(*log);
+ bookMarkLog3 = log->GetStore();
+ ed->InsertTextL(0, _L("Oi"), 0, 0, 0);
+ if (i == 5)
+ manager->SetBookmark();
+ testEd->Print(*log);
+ bookMarkLog4 = log->GetStore();
+ ed->InsertTextL(2, _L("! "), 0, 0, 0);
+ testEd->Print(*log);
+ bookMarkLog5 = log->GetStore();
+ if (i == 6)
+ manager->SetBookmark();
+
+ ed->UndoL();
+ // coalescence should have happenned unless there is a bookmark
+ // in the way.
+ if (i == 5)
+ {
+ test(manager->IsAtBookmark());
+ check->SetCheckString(*bookMarkLog4);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ ed->UndoL();
+ }
+ if (i == 4)
+ test(manager->IsAtBookmark());
+ else
+ test(!manager->IsAtBookmark());
+ check->SetCheckString(*bookMarkLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ ed->UndoL();
+ if (i == 2)
+ test(manager->IsAtBookmark());
+ else
+ test(!manager->IsAtBookmark());
+ check->SetCheckString(*bookMarkLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ ed->UndoL();
+ if (i == 1)
+ test(manager->IsAtBookmark());
+ else
+ test(!manager->IsAtBookmark());
+ check->SetCheckString(*bookMarkLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ ed->UndoL();
+ if (i == 0)
+ test(manager->IsAtBookmark());
+ else
+ test(!manager->IsAtBookmark());
+ check->SetCheckString(*bookMarkLog0);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ test(!ed->CanUndo());
+ ed->RedoL();
+ if (i == 1)
+ test(manager->IsAtBookmark());
+ else
+ test(!manager->IsAtBookmark());
+ check->SetCheckString(*bookMarkLog1);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ ed->RedoL();
+ if (i == 2)
+ test(manager->IsAtBookmark());
+ else
+ test(!manager->IsAtBookmark());
+ check->SetCheckString(*bookMarkLog2);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ ed->RedoL();
+ if (i == 4)
+ test(manager->IsAtBookmark());
+ else
+ test(!manager->IsAtBookmark());
+ check->SetCheckString(*bookMarkLog3);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ ed->RedoL();
+ if (i == 5)
+ {
+ test(manager->IsAtBookmark());
+ check->SetCheckString(*bookMarkLog4);
+ testEd->Print(*check);
+ CheckEditorLog(*check);
+ ed->RedoL();
+ }
+ test(!ed->CanRedo());
+ if (i == 6)
+ test(manager->IsAtBookmark());
+ else
+ test(!manager->IsAtBookmark());
+
+ delete bookMarkLog0;
+ delete bookMarkLog1;
+ delete bookMarkLog2;
+ delete bookMarkLog3;
+ delete bookMarkLog4;
+ delete bookMarkLog5;
+ }
+
+ delete ed;
+ delete testEd;
+ delete log;
+ delete check;
+ }
+
+void TestEditorUndoL()
+ {
+ __UHEAP_MARK;
+
+ TestEditorUndo t;
+ t.Test1L();
+ t.Test2L();
+ t.Test3L();
+ t.Test4L();
+ t.Test5L();
+ t.Test6L();
+ t.Test7L();
+ t.Test8L();
+
+ __UHEAP_MARKENDC(0);
+ }
+// integration of command manager with multiple editors
+void TestMultipleEditorsL()
+ {
+ __UHEAP_MARK;
+
+ CCheckingLogger* check = new(ELeave) CCheckingLogger;
+ CStoringLogger* log = new(ELeave) CStoringLogger;
+
+ CTestEditor* testEd0 = CTestEditor::NewL();
+ CTestEditor* testEd1 = CTestEditor::NewL();
+ CTestEditor* testEd2 = CTestEditor::NewL();
+ CTestEditor* testEd3 = CTestEditor::NewL();
+ CCommandManager* manager = CCommandManager::NewL();
+
+ CEditorPlainTextWithUndo* ed0 =
+ CEditorPlainTextWithUndo::NewL(*testEd0, manager);
+ CEditorWithUndo* ed1 = CEditorWithUndo::NewL(*testEd1, manager);
+ CEditorPlainTextWithUndo* ed2 =
+ CEditorPlainTextWithUndo::NewL(*testEd2, manager);
+ CEditorWithUndo* ed3 = CEditorWithUndo::NewL(*testEd3, manager);
+ manager->Release();
+
+ // Testing the API's of CEditorPlainTextWithUndo
+ TTmCharFormatMask charBIMask;
+ charBIMask.iFlags = TTmCharFormatMask::EItalic | TTmCharFormatMask::EBold;
+ TOpenFontFaceAttribBase attrib;
+ TTmCharFormat charB;
+ attrib.SetBold(ETrue);
+ charB.iFontSpec.SetAttrib(attrib);
+ TTmCharFormatLayer charLayer;
+ charLayer.iFormat = charB;
+ charLayer.iMask = charBIMask;
+ TTmParFormatMask parTMask;
+ parTMask.iFlags = TTmParFormatMask::EKeepTogether;
+ RTmParFormat parT;
+ parT.iFlags = RTmParFormat::EKeepTogether;
+ RTmParFormatLayer parLayer;
+ parLayer.iMask = parTMask;
+
+ //Setting the base, character and paragraph format and then inserting the text
+ ed0->SetBaseFormatL(charB,parT);
+ ed0->SetCharFormatL(0, 1, charLayer);
+ ed0->SetParFormatL(0, 1, parLayer);
+
+ // The main thing to check is that no commands coalesce that have
+ // different targets which would if their targets matched. The
+ // commands that can coalesce are Delete Text, Delete Plain Text,
+ // Insert Text, Insert Plain Text, Delete Character Format, Delete
+ // Paragraph Format.
+ ed0->InsertTextL(0, _L("ab"), 0, 0, 0);
+ testEd0->Print(*log);
+ HBufC* log00 = log->GetStore();
+ ed2->InsertTextL(0, _L("cd"), 0, 0, 0);
+ testEd2->Print(*log);
+ HBufC* log20 = log->GetStore();
+ ed1->InsertTextL(0, _L("ef"), 0, 0, 0);
+ testEd1->Print(*log);
+ HBufC* log10 = log->GetStore();
+ ed3->InsertTextL(0, _L("gh"), 0, 0, 0);
+ testEd3->Print(*log);
+ HBufC* log30 = log->GetStore();
+
+ manager->UndoL();
+ check->SetCheckString(*log10);
+ testEd1->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->UndoL();
+ check->SetCheckString(*log20);
+ testEd2->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->UndoL();
+ check->SetCheckString(*log00);
+ testEd0->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->UndoL();
+ TestCannotUndo(*manager);
+
+ manager->RedoL();
+ check->SetCheckString(*log00);
+ testEd0->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->RedoL();
+ check->SetCheckString(*log20);
+ testEd2->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->RedoL();
+ check->SetCheckString(*log10);
+ testEd1->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->RedoL();
+ check->SetCheckString(*log30);
+ testEd3->Print(*check);
+ CheckEditorLog(*check);
+ TestCannotRedo(*manager);
+
+ ed0->DeleteTextL(1, 1);
+ testEd0->Print(*log);
+ HBufC* log01 = log->GetStore();
+ ed2->DeleteTextL(0, 1);
+ testEd2->Print(*log);
+ HBufC* log21 = log->GetStore();
+ ed3->DeleteTextL(0, 1);
+ testEd3->Print(*log);
+ HBufC* log31 = log->GetStore();
+ ed1->DeleteTextL(0, 1);
+ testEd1->Print(*log);
+ HBufC* log11 = log->GetStore();
+
+ manager->UndoL();
+ check->SetCheckString(*log31);
+ testEd3->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->UndoL();
+ check->SetCheckString(*log21);
+ testEd2->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->UndoL();
+ check->SetCheckString(*log01);
+ testEd0->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->UndoL();
+ check->SetCheckString(*log30);
+ testEd3->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->RedoL();
+ check->SetCheckString(*log01);
+ testEd0->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->RedoL();
+ check->SetCheckString(*log21);
+ testEd2->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->RedoL();
+ check->SetCheckString(*log31);
+ testEd3->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->RedoL();
+ check->SetCheckString(*log11);
+ testEd1->Print(*check);
+ CheckEditorLog(*check);
+ TestCannotRedo(*manager);
+
+ parLayer.iFormat.CopyL(parT);
+
+ //Getting the base format to check if it is set accordingly
+ TTmCharFormat charB1;
+ RTmParFormat parT1;
+ ed0->GetBaseFormatL(charB1,parT1);
+ test(charB1==charB);
+ test(parT1==parT);
+
+ //Getting the character format
+ TTmCharFormatLayer charLayer1;
+ MUnifiedEditor::TFormatLevel level=MUnifiedEditor::EEffective;
+ TInt runLen=10;
+ ed0->GetCharFormat(0,level,charLayer1,runLen);
+
+ //Getting the paragraph format
+ RTmParFormatLayer parLayer1;
+ ed0->GetParFormatL(0,level,parLayer1,runLen);
+
+ //Getting the text
+ TPtrC text;
+ ed0->GetText(0,text);
+ test(text==_L("a"));
+
+ //Deleting the formating
+ ed0->DeleteCharFormatL(0,1);
+ ed0->DeleteParFormatL(0,1);
+
+ // To test CEditorCommandSetBaseFormat class
+ // SetBaseFormatL calls CEditorCommandSetBaseFormatProto::CreateInverseL() which in turn calls CEditorCommandSetBaseFormat::NewL().
+ ed1->SetBaseFormatL(charB,parT);
+ ed1->SetCharFormatL(0, 1, charLayer);
+
+ testEd1->Print(*log);
+ HBufC* log12 = log->GetStore();
+ ed3->SetCharFormatL(0, 1 ,charLayer);
+ testEd3->Print(*log);
+ HBufC* log32 = log->GetStore();
+ ed3->SetParFormatL(0, 1, parLayer);
+ testEd3->Print(*log);
+ HBufC* log33 = log->GetStore();
+ ed1->SetParFormatL(0, 1, parLayer);
+ testEd1->Print(*log);
+ HBufC* log13 = log->GetStore();
+
+ manager->UndoL();
+ check->SetCheckString(*log33);
+ testEd3->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->UndoL();
+ check->SetCheckString(*log32);
+ testEd3->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->UndoL();
+ check->SetCheckString(*log12);
+ testEd1->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->RedoL();
+ check->SetCheckString(*log32);
+ testEd3->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->RedoL();
+ check->SetCheckString(*log33);
+ testEd3->Print(*check);
+ CheckEditorLog(*check);
+
+ manager->RedoL();
+ check->SetCheckString(*log13);
+ testEd1->Print(*check);
+ CheckEditorLog(*check);
+
+ parLayer.Close();
+ parT.Close();
+ delete log00;
+ delete log10;
+ delete log20;
+ delete log30;
+ delete log01;
+ delete log11;
+ delete log21;
+ delete log31;
+ delete log12;
+ delete log13;
+ delete log32;
+ delete log33;
+ manager->ResetUndo();
+ delete ed0;
+ delete ed1;
+ delete ed2;
+ delete ed3;
+ delete testEd0;
+ delete testEd1;
+ delete testEd2;
+ delete testEd3;
+ delete log;
+ delete check;
+
+ __UHEAP_MARKENDC(0);
+ }
+
+//
+//
+// Main
+//
+//
+
+void RunTests()
+ {
+ __UHEAP_MARK;
+
+ test.Title();
+ test.Start(_L("@SYMTestCaseID:SYSLIB-FORM-LEGACY-UNDO-0001 Undo System Tests: "));
+
+ // test of general undo system components
+ TestCCommandStackL();
+ TestCBatchCommandL();
+ TestCCommandHistoryL();
+ TestCCommandManagerL();
+
+ // test of editor undo components
+ TestEditorUndoL();
+
+ // test that command manager and multiple editors integrate correctly
+ TestMultipleEditorsL();
+
+ test.End();
+ test.Close();
+
+ __UHEAP_MARKENDC(0);
+ }
+
+TInt E32Main()
+ {
+ TrapCleanup = CTrapCleanup::New();
+ TRAPD(err, RunTests());
+ test(err == KErrNone);
+ delete TrapCleanup;
+ return 0;
+ }