diff -r 000000000000 -r 1fb32624e06b textrendering/textformatting/undo/UndoSystemImpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/textrendering/textformatting/undo/UndoSystemImpl.cpp Tue Feb 02 02:02:46 2010 +0200 @@ -0,0 +1,324 @@ +/* +* Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include "UndoSystemImpl.h" +#include "AssertFileAndLine.h" + +using namespace UndoSystem; + +namespace UndoSystemImpl +{ +const TInt KCommandStackGranularity = 10; +_LIT(KUndoPanic, "Undo System"); +} + +using namespace UndoSystemImpl; + + +void UndoSystem::Panic(TPanicCode aCode) + { + User::Panic(KUndoPanic, aCode); + } + +///////////////////// +// // +// CCommandStack // +// // +///////////////////// + +CCommandStack::CCommandStack() : iEnd(0), iBookmark(0) {} + +CCommandStack::~CCommandStack() + { + if (iStack) + { + Reset(); + delete iStack; + } + } + +void CCommandStack::ConstructL() + { + iStack = new(ELeave) CArrayFixSeg(KCommandStackGranularity); + } + +CCommandStack* CCommandStack::NewL() + { + CCommandStack* r = new(ELeave) CCommandStack(); + CleanupStack::PushL(r); + r->ConstructL(); + CleanupStack::Pop(r); + return r; + } + +TInt CCommandStack::Count() const + { + ASSERT(iEnd <= iStack->Count()); + return iEnd; + } + +void CCommandStack::Reset() + { + PruneTo(0); + iBookmark = -1; + } + +CCommand* CCommandStack::Top() const + { + ASSERT(0 <= iEnd); + ASSERT(iEnd <= iStack->Count()); + return iEnd == 0? 0 : iStack->At(iEnd - 1); + } + +CCommand* CCommandStack::Pop() + { + ASSERT(iEnd <= iStack->Count()); + CCommand* top = Top(); + __ASSERT_ALWAYS(top, UndoSystem::Panic(KCommandStackUnderflow)); + TInt numSlots = iStack->Count() - iEnd + 1; + ASSERT(numSlots <= iStack->Count()); + iStack->Delete(iStack->Count() - numSlots, numSlots); + iEnd = iStack->Count(); + if (iEnd < iBookmark) + iBookmark = -1; + return top; + } + +void CCommandStack::PruneTo(TInt aNumberOfItems) + { + ASSERT(iEnd <= iStack->Count()); + iStack->Delete(iEnd, iStack->Count() - iEnd); + iEnd = iStack->Count(); + if (aNumberOfItems < iEnd) + { + TInt numberToDestroy = iEnd - aNumberOfItems; + for (TInt i = 0; i != numberToDestroy; ++i) + { + delete iStack->At(i); + } + iStack->Delete(0, numberToDestroy); + iStack->Compress(); + iEnd = aNumberOfItems; + iBookmark -= aNumberOfItems; + } + } + +void CCommandStack::PrepareToPushL(TInt aNumberOfItems) + { + iStack->ResizeL(iEnd + aNumberOfItems); + } + +void CCommandStack::Push(CCommand* aCommand) + { + ASSERT(aCommand); + __ASSERT_ALWAYS(iEnd < iStack->Count(), UndoSystem::Panic(KCommandStackPushNotPrepared)); + iStack->At(iEnd) = aCommand; + ++iEnd; + } + +void CCommandStack::Concatenate(CCommandStack& aStack) + { + TInt thisCount = iEnd; + iEnd += aStack.iEnd; + __ASSERT_DEBUG(iEnd <= iStack->Count(), + UndoSystem::Panic(KCommandStackPushNotPrepared)); + for (TInt i = 0; i != aStack.iEnd; ++i, ++thisCount) + iStack->At(thisCount) = (aStack.iStack->At(i)); + aStack.iEnd = 0; + aStack.iStack->Reset(); + } + +void CCommandStack::SetBookmark() + { + iBookmark = iEnd; + } + +TBool CCommandStack::IsAtBookmark() const + { + return iBookmark == iEnd? ETrue : EFalse; + } + +CSingleCommandStack* CSingleCommandStack::NewL() + { + CSingleCommandStack* r = new(ELeave) CSingleCommandStack; + CleanupStack::PushL(r); + r->iStack.ConstructL(); + CleanupStack::Pop(r); + return r; + } + +/////////////////////// +// // +// CCommandHistory // +// // +/////////////////////// + +CCommandHistory::CCommandHistory() + : iMaxItems(KMaxTInt >> 1) + { + } + +CCommandHistory::~CCommandHistory() + { + delete iStack; + } + +void CCommandHistory::ConstructL() + { + iStack = CCommandStack::NewL(); + iCurrent = 0; + } + +CCommandHistory* CCommandHistory::NewL() + { + CCommandHistory* r = new(ELeave) CCommandHistory(); + CleanupStack::PushL(r); + r->ConstructL(); + CleanupStack::Pop(r); + return r; + } + +void CCommandHistory::Prune() + { + if (iMaxItems < iStack->Count()) + iStack->PruneTo(iMaxItems); + } + +void CCommandHistory::SetMaxItems(TInt aMaxItems) + { + ASSERT(0 < aMaxItems); + iMaxItems = aMaxItems; + Prune(); + } + +void CCommandHistory::CloseBatch(void* a) + { + CCommandHistory* aThat = reinterpret_cast(a); + aThat->iCurrent = 0; + if (aThat->iBatchUndoHasBeenWaived) + aThat->Reset(); + } + +void CCommandHistory::DownBatchLevel(void*) {} + +TBool CCommandHistory::IsWithinBatch() const + { + return iCurrent? ETrue : EFalse; + } + +void CCommandHistory::BeginBatchLC() + { + if (iCurrent) + { + CleanupStack::PushL(TCleanupItem(DownBatchLevel, this)); + } + else + { + iStack->PrepareToPushL(1); + iBatchUndoHasBeenWaived = EFalse; + CleanupStack::PushL(TCleanupItem(CloseBatch, this)); + CBatchCommand* batch = CBatchCommand::NewL(); + iCurrent = batch; + iStack->Push(batch); + } + } + +TBool CCommandHistory::UndoHasBeenWaived() const + { + return iCurrent? iBatchUndoHasBeenWaived : EFalse; + } + +void CCommandHistory::SetUndoWaived() + { + iBatchUndoHasBeenWaived = ETrue; + } + +void CCommandHistory::Reset() + { + iStack->Reset(); + iCurrent = 0; + } + +void CCommandHistory::PrepareToAddCommandL(CCommand* aCommand) + { + if (iCurrent) + iCurrent->PrepareToPushL(aCommand); + else + iStack->PrepareToPushL(1); + } + +void CCommandHistory::AddCommand(CCommand* aCommand) + { + if (iCurrent) + iCurrent->Push(aCommand); + else + iStack->Push(aCommand); + if (!iCurrent) + Prune(); + } + +CSingleCommand* CCommandHistory::TopSingleCommand() const + { + CCommand* top = Top(); + + if (!top) + return 0; + + // if the top of the undo stack is an empty batch, then we are starting a new + // batch command and so do not want to combine. Otherwise, if the top is a batch + // with elements, we want to see if we can combine with the top one. + CBatchCommand* batch = top->Batch(); + return batch? batch->Top() : top->Single(); + } + +CCommand* CCommandHistory::Top() const + { + return iStack->Top(); + } + +CCommand* CCommandHistory::Pop() + { + ASSERT(!iCurrent); + return iStack->Pop(); + } + +void CCommandHistory::Clean() + { + ASSERT(!iCurrent); + CCommand* command = Top(); + if (!command) + return; + CBatchCommand* batch = command->Batch(); + if (!batch) + return; + if (batch->IsEmpty()) + { + delete Pop(); + } + } + +void CCommandHistory::SetBookmark() + { + iStack->SetBookmark(); + } + +TBool CCommandHistory::IsAtBookmark() + { + return iStack->IsAtBookmark(); + } +