textrendering/textformatting/undo/EditorPlainTextCommands.cpp
changeset 0 1fb32624e06b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/textformatting/undo/EditorPlainTextCommands.cpp	Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,428 @@
+/*
+* 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 "EditorPlainTextCommands.h"
+#include "AssertFileAndLine.h"
+#include <txtetext.h>
+#include <txtclipboard.h>
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "txtfmlyr_internal.h"
+#endif
+using namespace UndoSystem;
+
+/////////////////////////
+//					   //
+//	Internal Commands  //
+//					   //
+/////////////////////////
+
+TUid CEditorCommand::FamilyUid() const { return TUid::Uid(KUndoDllUid); }
+
+CEditorCommandInsertTextAndFormat*
+	CEditorCommand::CastToCEditorCommandInsertTextAndFormat() { return 0; }
+CEditorCommandDeleteText*
+	CEditorCommand::CastToCEditorCommandDeleteText() { return 0; }
+CEditorCommandInsertPlainText*
+	CEditorCommand::CastToCEditorCommandInsertPlainText() { return 0; }
+CEditorCommandDeletePlainText*
+	CEditorCommand::CastToCEditorCommandDeletePlainText() { return 0; }
+CEditorCommandDeleteCharFormat*
+	CEditorCommand::CastToCEditorCommandDeleteCharFormat() { return 0; }
+CEditorCommandDeleteParFormat*
+	CEditorCommand::CastToCEditorCommandDeleteParFormat() { return 0; }
+
+/////////////////////////////////
+//							   //
+//	Command coalesce function  //
+//							   //
+/////////////////////////////////
+
+CCommand* UndoSystem::CoalesceL(CCommand* aLeft, CCommand* aRight)
+	{
+	if (!aRight)
+		return aLeft;
+	if (!aLeft)
+		return aRight;
+
+	CleanupStack::PushL(aRight);
+	CBatchCommand* batch = aLeft->Batch();
+	if (batch)
+		{
+		batch->PrepareToPushL(aRight);
+		batch->Push(aRight);
+		CleanupStack::Pop(aRight);
+		return batch;
+		}
+	ASSERT(aLeft->Single());
+	batch = CBatchCommand::NewL();
+	CleanupStack::PushL(batch);
+	batch->PrepareToPushL(aLeft);
+	batch->Push(aLeft);
+	batch->PrepareToPushL(aRight);
+	batch->Push(aRight);
+	CleanupStack::Pop(batch);
+	CleanupStack::Pop(aRight);
+	return batch;
+	}
+
+/**
+ * Command for deleting plain text.
+ *
+ * @internalComponent
+ * @since App-frameworks6.1
+ */
+NONSHARABLE_CLASS(CEditorCommandDeletePlainText) : public CEditorCommand
+	{
+	TEditorDeletePlainTextImpl iImpl;
+
+	CEditorCommandDeletePlainText*
+		CastToCEditorCommandDeletePlainText() { return this; }
+
+	CEditorCommandDeletePlainText(MUnifiedEditor& aTarget,
+		TInt aPos, TInt aLength)
+		: iImpl(aTarget, aPos, aLength) {}
+public:
+	static CEditorCommandDeletePlainText* NewL(TInt aPos,
+		TInt aLength, MUnifiedEditor& aTarget)
+		{
+		return new(ELeave) CEditorCommandDeletePlainText(aTarget, aPos, aLength);
+		}
+
+	CCommand* CreateInverseL() const;
+
+	TInt ExecuteL() const
+		{
+		return iImpl.ExecuteL();
+		}
+
+	// This command can be coalesced with others of the same type
+	TBool CanAdd(TInt aPos, TInt aLength, MUnifiedEditor& aTarget) const
+		{
+		return iImpl.CanAdd(aPos, aLength, aTarget);
+		}
+
+	void Add(TInt aLength)
+		{
+		iImpl.Add(aLength);
+		}
+	};
+
+/**
+ * Command for inserting text in a specified style and format.
+ *
+ * @internalComponent
+ * @since App-frameworks6.1
+ */
+NONSHARABLE_CLASS(CEditorCommandInsertPlainText) : public CEditorCommand
+	{
+	TEditorInsertPlainTextImpl iImpl;
+
+	CEditorCommandInsertPlainText*
+		CastToCEditorCommandInsertPlainText() { return this; }
+	CEditorCommandInsertPlainText(MUnifiedEditor& aTarget, TInt aPos, const TDesC& aText)
+		: iImpl(aTarget, aPos, aText) {}
+public:
+	static CEditorCommandInsertPlainText* NewL(TInt aPos, const TDesC& aText,
+		MUnifiedEditor& aTarget)
+		{
+		return new(ELeave) CEditorCommandInsertPlainText(aTarget, aPos, aText);
+		}
+	/**
+	 * Gets the length specified, but this might entail the use of more than
+	 * one CCommand object.
+	 */
+	static CCommand* NewBatchL(TInt aPos, TInt aLength, MUnifiedEditor& aTarget);
+
+	CCommand* CreateInverseL() const;
+
+	TInt ExecuteL() const
+		{
+		return iImpl.ExecuteL();
+		}
+
+	TBool CanAdd(TInt aPos, const TDesC& aText, MUnifiedEditor& aTarget) const
+		{
+		return iImpl.CanAdd(aPos, aText, aTarget);
+		}
+
+	void Add(TInt aPos, const TDesC& aText)
+		{
+		iImpl.Add(aPos, aText);
+		}
+	};
+
+CCommand* CEditorCommandInsertPlainText::NewBatchL(TInt aPos,
+	TInt aLength, MUnifiedEditor& aTarget)
+	{
+	CCommand* command = 0;
+	TInt end = aPos + aLength;
+	while (aLength)
+		{
+		TPtrC textSegment;
+		aTarget.GetText(end - aLength, textSegment);
+		TInt segLength = textSegment.Length();
+		if (aLength < segLength)
+			segLength = aLength;
+		if (KMaxCharsInSingleCommand < segLength)
+			segLength = KMaxCharsInSingleCommand;
+		CleanupStack::PushL(command);
+		// coverity[double_free]
+		command = CoalesceL(command, CEditorCommandInsertPlainText::NewL(aPos,
+			textSegment.Left(segLength), aTarget));
+		CleanupStack::Pop();
+		aLength -= segLength;
+		}
+	return command;
+	}
+
+CCommand* CEditorCommandInsertPlainText::CreateInverseL() const
+	{
+	return CEditorCommandDeletePlainText::NewL(iImpl.Pos(), iImpl.Text().Length(),
+		iImpl.Target());
+	}
+
+
+CCommand* CEditorCommandDeletePlainText::CreateInverseL() const
+	{
+	return CEditorCommandInsertPlainText::NewBatchL(iImpl.Pos(), iImpl.Length(),
+		iImpl.Target());
+	}
+
+//////////////////////////////////////////
+//										//
+//	CEditorCommandInsertPlainTextProto  //
+//										//
+//////////////////////////////////////////
+
+void CEditorCommandInsertPlainTextProto::Set(TInt aPos, const TDesC& aText)
+	{
+	iPos = aPos;
+	iText = &aText;
+	}
+
+UndoSystem::CCommand* CEditorCommandInsertPlainTextProto::CreateInverseL() const
+	{
+	return CEditorCommandDeletePlainText::NewL(iPos, iText->Length(), iTarget);
+	}
+
+TInt CEditorCommandInsertPlainTextProto::ExecuteL() const
+	{
+	iTarget.InsertTextL(iPos, *iText);
+	return KErrNone;
+	}
+
+TBool CEditorCommandInsertPlainTextProto::PrepareToAddInverseToLastL(
+	CSingleCommand& aLastCommand) const
+	{
+	if (aLastCommand.FamilyUid() != TUid::Uid(KUndoDllUid))
+		return EFalse;
+	CEditorCommandDeletePlainText* last =
+		static_cast<CEditorCommand&>(aLastCommand).CastToCEditorCommandDeletePlainText();
+	if (!last)
+		return EFalse;
+	return last->CanAdd(iPos, iText->Length(), iTarget);
+	}
+
+void CEditorCommandInsertPlainTextProto::AddInverseToLast(CSingleCommand& aLastCommand) const
+	{
+	ASSERT(aLastCommand.FamilyUid() == TUid::Uid(KUndoDllUid));
+	CEditorCommandDeletePlainText* last =
+		static_cast<CEditorCommand&>(aLastCommand).CastToCEditorCommandDeletePlainText();
+	ASSERT(last);
+	last->Add(iText->Length());
+	}
+
+//////////////////////////////////////////
+//										//
+//	CEditorCommandDeletePlainTextProto  //
+//										//
+//////////////////////////////////////////
+
+void CEditorCommandDeletePlainTextProto::Set(TInt aPos, TInt aLength)
+	{
+	iPos = aPos;
+	iLength = aLength;
+	}
+
+CCommand* CEditorCommandDeletePlainTextProto::CreateInverseL() const
+	{
+	return CEditorCommandInsertPlainText::NewBatchL(iPos, iLength, iTarget);
+	}
+
+TInt CEditorCommandDeletePlainTextProto::ExecuteL() const
+	{
+	iTarget.DeleteTextL(iPos, iLength);
+	return KErrNone;
+	}
+
+TBool CEditorCommandDeletePlainTextProto::PrepareToAddInverseToLastL(
+	CSingleCommand& aLastCommand) const
+	{
+	if (iDeletedText.MaxLength() < iLength)
+		return EFalse;
+	if (aLastCommand.FamilyUid() != TUid::Uid(KUndoDllUid))
+		return EFalse;
+	CEditorCommandInsertPlainText* last =
+		static_cast<CEditorCommand&>(aLastCommand).CastToCEditorCommandInsertPlainText();
+	if (!last)
+		return EFalse;
+	TBool result = EFalse;
+	TPtrC textSegment;
+	iTarget.GetText(iPos, textSegment);
+	if (iLength <= textSegment.Length())
+		{
+		result = last->CanAdd(iPos, textSegment.Left(iLength), iTarget);
+		if (result)
+			iDeletedText = textSegment.Left(iLength);
+		}
+	return result;
+	}
+
+void CEditorCommandDeletePlainTextProto::AddInverseToLast(CSingleCommand& aLastCommand) const
+	{
+	ASSERT(aLastCommand.FamilyUid() == TUid::Uid(KUndoDllUid));
+	CEditorCommandInsertPlainText* last =
+		static_cast<CEditorCommand&>(aLastCommand).CastToCEditorCommandInsertPlainText();
+	ASSERT(last);
+	last->Add(iPos, iDeletedText);
+	}
+
+//////////////////////////////////
+//								//
+//	TEditorInsertPlainTextImpl  //
+//								//
+//////////////////////////////////
+
+TInt TEditorInsertPlainTextImpl::ExecuteL(const TDesC* aStyle,
+	const TTmCharFormatLayer* aChar,
+	const RTmParFormatLayer* aPar) const
+	{
+	iTarget.InsertTextL(iPos, iText, aStyle, aChar, aPar);
+	return KErrNone;
+	}
+
+TInt TEditorInsertPlainTextImpl::ExecuteL() const
+	{
+	return ExecuteL(0, 0, 0);
+	}
+
+TInt TEditorInsertPlainTextImpl::CanAdd(TInt aPos, const TDesC& aText, MUnifiedEditor& aTarget) const
+	{
+	if (&aTarget != &iTarget)
+		return EFalse;
+	TInt length = aText.Length();
+	if (KMaxCharsInSingleCommand <= iText.Length() + length)
+		return EFalse;
+	return aPos <= iPos && iPos <= aPos + length;
+	}
+
+void TEditorInsertPlainTextImpl::Add(TInt aPos, const TDesC& aText)
+	{
+	TPtrC left = aText.Left(iPos - aPos);
+	TPtrC right = aText.Mid(iPos - aPos);
+	iText.Insert(0, left);
+	iText.Append(right);
+	iPos = aPos;
+	}
+
+//////////////////////////////////
+//								//
+//	TEditorDeletePlainTextImpl  //
+//								//
+//////////////////////////////////
+
+TInt TEditorDeletePlainTextImpl::ExecuteL() const
+	{
+	iTarget.DeleteTextL(iPos, iLength);
+	return KErrNone;
+	}
+
+TBool TEditorDeletePlainTextImpl::CanAdd(TInt aPos, TInt aLength, MUnifiedEditor& aTarget) const
+	{
+	return &aTarget == &iTarget && iPos <= aPos && aPos <= iLength + iPos
+		&& aLength + iLength <= KMaxCharsInSingleCommand;
+	}
+
+void TEditorDeletePlainTextImpl::Add(TInt aLength)
+	{
+	iLength += aLength;
+	}
+
+/////////////////////////////
+//						   //
+//  TEditorPasteProtoImpl  //
+//						   //
+/////////////////////////////
+
+void TEditorPasteProtoImpl::Set(const CStreamStore& aStore,
+								const CStreamDictionary& aDict,
+								TInt aPos)
+	{
+	iStore = &aStore;
+	iStreamDictionary = &aDict;
+	iPos = aPos;
+	}
+
+void TEditorPasteProtoImpl::OpenPlainTextStreamLC(RStoreReadStream& aStream) const
+	{
+	TStreamId plainTextStream = iStreamDictionary->At(KClipboardUidTypePlainText);
+	if (plainTextStream == KNullStreamId)
+		User::Leave(KErrNotSupported);		// don't know how to undo this
+	aStream.OpenLC(*iStore, plainTextStream);
+	}
+
+TInt TEditorPasteProtoImpl::LengthL() const
+	{
+	RStoreReadStream stream;
+	OpenPlainTextStreamLC(stream);
+	TInt length = stream.ReadInt32L();
+	CleanupStack::PopAndDestroy();
+	return length;
+	}
+
+TInt TEditorPasteProtoImpl::ExecuteL() const
+	{
+	MUnifiedEditor::MClipboardSupport* ci = iTarget.ClipboardSupport();
+	ASSERT(ci);
+	ci->PasteFromStoreL(*iStore, *iStreamDictionary, iPos);
+	return KErrNone;
+	}
+
+/////////////////////////////////////////
+//									   //
+//	CEditorCommandPastePlainTextProto  //
+//									   //
+/////////////////////////////////////////
+
+void CEditorCommandPastePlainTextProto::Set(const CStreamStore& aStore,
+	const CStreamDictionary& aStreamDictionary,
+	TInt aPos)
+	{
+	iImpl.Set(aStore, aStreamDictionary, aPos);
+	}
+
+UndoSystem::CCommand* CEditorCommandPastePlainTextProto::CreateInverseL() const
+	{
+	return CEditorCommandDeletePlainText::NewL(iImpl.Pos(), iImpl.LengthL(), iImpl.Target());
+	}
+
+TInt CEditorCommandPastePlainTextProto::ExecuteL() const
+	{
+	return iImpl.ExecuteL();
+	}