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