diff -r 000000000000 -r 6474c204b198 editor/libeditor/base/SplitElementTxn.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/libeditor/base/SplitElementTxn.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include // for printf + +#include "SplitElementTxn.h" +#include "nsAString.h" +#include "nsDebug.h" // for NS_ASSERTION, etc +#include "nsEditor.h" // for nsEditor +#include "nsError.h" // for NS_ERROR_NOT_INITIALIZED, etc +#include "nsIDOMCharacterData.h" // for nsIDOMCharacterData +#include "nsIDOMNode.h" // for nsIDOMNode +#include "nsIEditor.h" // for nsEditor::DebugDumpContent, etc +#include "nsISelection.h" // for nsISelection +#include "nsISupportsUtils.h" // for NS_ADDREF + +// note that aEditor is not refcounted +SplitElementTxn::SplitElementTxn() + : EditTxn() +{ +} + +NS_IMPL_CYCLE_COLLECTION_INHERITED(SplitElementTxn, EditTxn, + mParent, + mNewLeftNode) + +NS_IMPL_ADDREF_INHERITED(SplitElementTxn, EditTxn) +NS_IMPL_RELEASE_INHERITED(SplitElementTxn, EditTxn) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SplitElementTxn) +NS_INTERFACE_MAP_END_INHERITING(EditTxn) + +NS_IMETHODIMP SplitElementTxn::Init(nsEditor *aEditor, + nsIDOMNode *aNode, + int32_t aOffset) +{ + NS_ASSERTION(aEditor && aNode, "bad args"); + if (!aEditor || !aNode) { return NS_ERROR_NOT_INITIALIZED; } + + mEditor = aEditor; + mExistingRightNode = do_QueryInterface(aNode); + mOffset = aOffset; + return NS_OK; +} + +NS_IMETHODIMP SplitElementTxn::DoTransaction(void) +{ + NS_ASSERTION(mExistingRightNode && mEditor, "bad state"); + if (!mExistingRightNode || !mEditor) { return NS_ERROR_NOT_INITIALIZED; } + + // create a new node + nsresult result = mExistingRightNode->CloneNode(false, 1, getter_AddRefs(mNewLeftNode)); + NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewLeftNode)), "could not create element."); + NS_ENSURE_SUCCESS(result, result); + NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NULL_POINTER); + mEditor->MarkNodeDirty(mExistingRightNode); + + // get the parent node + result = mExistingRightNode->GetParentNode(getter_AddRefs(mParent)); + NS_ENSURE_SUCCESS(result, result); + NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER); + + // insert the new node + result = mEditor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); + if (mNewLeftNode) { + bool bAdjustSelection; + mEditor->ShouldTxnSetSelection(&bAdjustSelection); + if (bAdjustSelection) + { + nsCOMPtr selection; + result = mEditor->GetSelection(getter_AddRefs(selection)); + NS_ENSURE_SUCCESS(result, result); + NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); + result = selection->Collapse(mNewLeftNode, mOffset); + } + else + { + // do nothing - dom range gravity will adjust selection + } + } + return result; +} + +NS_IMETHODIMP SplitElementTxn::UndoTransaction(void) +{ + NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state"); + if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) { + return NS_ERROR_NOT_INITIALIZED; + } + + // this assumes Do inserted the new node in front of the prior existing node + nsCOMPtr rightNode = do_QueryInterface(mExistingRightNode); + nsCOMPtr leftNode = do_QueryInterface(mNewLeftNode); + nsCOMPtr parent = do_QueryInterface(mParent); + NS_ENSURE_TRUE(rightNode && leftNode && parent, NS_ERROR_FAILURE); + return mEditor->JoinNodesImpl(rightNode, leftNode, parent); +} + +/* redo cannot simply resplit the right node, because subsequent transactions + * on the redo stack may depend on the left node existing in its previous state. + */ +NS_IMETHODIMP SplitElementTxn::RedoTransaction(void) +{ + NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state"); + if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) { + return NS_ERROR_NOT_INITIALIZED; + } + + nsresult result; + nsCOMPtrresultNode; + // first, massage the existing node so it is in its post-split state + nsCOMPtrrightNodeAsText = do_QueryInterface(mExistingRightNode); + if (rightNodeAsText) + { + nsresult result = rightNodeAsText->DeleteData(0, mOffset); + NS_ENSURE_SUCCESS(result, result); + } + else + { + nsCOMPtrchild; + nsCOMPtrnextSibling; + result = mExistingRightNode->GetFirstChild(getter_AddRefs(child)); + int32_t i; + for (i=0; iGetNextSibling(getter_AddRefs(nextSibling)); + result = mExistingRightNode->RemoveChild(child, getter_AddRefs(resultNode)); + if (NS_SUCCEEDED(result)) + { + result = mNewLeftNode->AppendChild(child, getter_AddRefs(resultNode)); + } + child = do_QueryInterface(nextSibling); + } + } + // second, re-insert the left node into the tree + result = mParent->InsertBefore(mNewLeftNode, mExistingRightNode, getter_AddRefs(resultNode)); + return result; +} + + +NS_IMETHODIMP SplitElementTxn::GetTxnDescription(nsAString& aString) +{ + aString.AssignLiteral("SplitElementTxn"); + return NS_OK; +} + +NS_IMETHODIMP SplitElementTxn::GetNewNode(nsIDOMNode **aNewNode) +{ + NS_ENSURE_TRUE(aNewNode, NS_ERROR_NULL_POINTER); + NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NOT_INITIALIZED); + *aNewNode = mNewLeftNode; + NS_ADDREF(*aNewNode); + return NS_OK; +}