michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include // for printf michael@0: michael@0: #include "JoinElementTxn.h" michael@0: #include "nsAString.h" michael@0: #include "nsDebug.h" // for NS_ASSERTION, etc michael@0: #include "nsEditor.h" // for nsEditor michael@0: #include "nsError.h" // for NS_ERROR_NULL_POINTER, etc michael@0: #include "nsIDOMCharacterData.h" // for nsIDOMCharacterData michael@0: #include "nsIEditor.h" // for nsEditor::IsModifiableNode michael@0: #include "nsINode.h" // for nsINode michael@0: #include "nsISupportsImpl.h" // for EditTxn::QueryInterface, etc michael@0: michael@0: JoinElementTxn::JoinElementTxn() michael@0: : EditTxn() michael@0: { michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinElementTxn, EditTxn, michael@0: mLeftNode, michael@0: mRightNode, michael@0: mParent) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JoinElementTxn) michael@0: NS_INTERFACE_MAP_END_INHERITING(EditTxn) michael@0: michael@0: NS_IMETHODIMP JoinElementTxn::Init(nsEditor *aEditor, michael@0: nsIDOMNode *aLeftNode, michael@0: nsIDOMNode *aRightNode) michael@0: { michael@0: NS_PRECONDITION((aEditor && aLeftNode && aRightNode), "null arg"); michael@0: if (!aEditor || !aLeftNode || !aRightNode) { return NS_ERROR_NULL_POINTER; } michael@0: mEditor = aEditor; michael@0: mLeftNode = do_QueryInterface(aLeftNode); michael@0: nsCOMPtrleftParent; michael@0: nsresult result = mLeftNode->GetParentNode(getter_AddRefs(leftParent)); michael@0: NS_ENSURE_SUCCESS(result, result); michael@0: if (!mEditor->IsModifiableNode(leftParent)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: mRightNode = do_QueryInterface(aRightNode); michael@0: mOffset = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // After DoTransaction() and RedoTransaction(), the left node is removed from the content tree and right node remains. michael@0: NS_IMETHODIMP JoinElementTxn::DoTransaction(void) michael@0: { michael@0: NS_PRECONDITION((mEditor && mLeftNode && mRightNode), "null arg"); michael@0: if (!mEditor || !mLeftNode || !mRightNode) { return NS_ERROR_NOT_INITIALIZED; } michael@0: michael@0: // get the parent node michael@0: nsCOMPtr leftParent; michael@0: mLeftNode->GetParentNode(getter_AddRefs(leftParent)); michael@0: NS_ENSURE_TRUE(leftParent, NS_ERROR_NULL_POINTER); michael@0: michael@0: // verify that mLeftNode and mRightNode have the same parent michael@0: nsCOMPtr rightParent; michael@0: mRightNode->GetParentNode(getter_AddRefs(rightParent)); michael@0: NS_ENSURE_TRUE(rightParent, NS_ERROR_NULL_POINTER); michael@0: michael@0: if (leftParent != rightParent) { michael@0: NS_ASSERTION(false, "2 nodes do not have same parent"); michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: // set this instance mParent. michael@0: // Other methods will see a non-null mParent and know all is well michael@0: mParent = leftParent; michael@0: nsCOMPtr leftNode = do_QueryInterface(mLeftNode); michael@0: nsCOMPtr rightNode = do_QueryInterface(mRightNode); michael@0: nsCOMPtr parent = do_QueryInterface(mParent); michael@0: NS_ENSURE_TRUE(leftNode && rightNode && parent, NS_ERROR_FAILURE); michael@0: mOffset = leftNode->Length(); michael@0: michael@0: return mEditor->JoinNodesImpl(rightNode, leftNode, parent); michael@0: } michael@0: michael@0: //XXX: what if instead of split, we just deleted the unneeded children of mRight michael@0: // and re-inserted mLeft? michael@0: NS_IMETHODIMP JoinElementTxn::UndoTransaction(void) michael@0: { michael@0: NS_ASSERTION(mRightNode && mLeftNode && mParent, "bad state"); michael@0: if (!mRightNode || !mLeftNode || !mParent) { return NS_ERROR_NOT_INITIALIZED; } michael@0: nsresult result; michael@0: nsCOMPtrresultNode; michael@0: // first, massage the existing node so it is in its post-split state michael@0: nsCOMPtrrightNodeAsText = do_QueryInterface(mRightNode); michael@0: if (rightNodeAsText) michael@0: { michael@0: result = rightNodeAsText->DeleteData(0, mOffset); michael@0: } michael@0: else michael@0: { michael@0: nsCOMPtrchild; michael@0: result = mRightNode->GetFirstChild(getter_AddRefs(child)); michael@0: nsCOMPtrnextSibling; michael@0: uint32_t i; michael@0: for (i=0; iGetNextSibling(getter_AddRefs(nextSibling)); michael@0: result = mLeftNode->AppendChild(child, getter_AddRefs(resultNode)); michael@0: child = do_QueryInterface(nextSibling); michael@0: } michael@0: } michael@0: // second, re-insert the left node into the tree michael@0: result = mParent->InsertBefore(mLeftNode, mRightNode, getter_AddRefs(resultNode)); michael@0: return result; michael@0: michael@0: } michael@0: michael@0: NS_IMETHODIMP JoinElementTxn::GetTxnDescription(nsAString& aString) michael@0: { michael@0: aString.AssignLiteral("JoinElementTxn"); michael@0: return NS_OK; michael@0: }