1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/editor/libeditor/base/SplitElementTxn.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,157 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include <stdio.h> // for printf 1.10 + 1.11 +#include "SplitElementTxn.h" 1.12 +#include "nsAString.h" 1.13 +#include "nsDebug.h" // for NS_ASSERTION, etc 1.14 +#include "nsEditor.h" // for nsEditor 1.15 +#include "nsError.h" // for NS_ERROR_NOT_INITIALIZED, etc 1.16 +#include "nsIDOMCharacterData.h" // for nsIDOMCharacterData 1.17 +#include "nsIDOMNode.h" // for nsIDOMNode 1.18 +#include "nsIEditor.h" // for nsEditor::DebugDumpContent, etc 1.19 +#include "nsISelection.h" // for nsISelection 1.20 +#include "nsISupportsUtils.h" // for NS_ADDREF 1.21 + 1.22 +// note that aEditor is not refcounted 1.23 +SplitElementTxn::SplitElementTxn() 1.24 + : EditTxn() 1.25 +{ 1.26 +} 1.27 + 1.28 +NS_IMPL_CYCLE_COLLECTION_INHERITED(SplitElementTxn, EditTxn, 1.29 + mParent, 1.30 + mNewLeftNode) 1.31 + 1.32 +NS_IMPL_ADDREF_INHERITED(SplitElementTxn, EditTxn) 1.33 +NS_IMPL_RELEASE_INHERITED(SplitElementTxn, EditTxn) 1.34 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SplitElementTxn) 1.35 +NS_INTERFACE_MAP_END_INHERITING(EditTxn) 1.36 + 1.37 +NS_IMETHODIMP SplitElementTxn::Init(nsEditor *aEditor, 1.38 + nsIDOMNode *aNode, 1.39 + int32_t aOffset) 1.40 +{ 1.41 + NS_ASSERTION(aEditor && aNode, "bad args"); 1.42 + if (!aEditor || !aNode) { return NS_ERROR_NOT_INITIALIZED; } 1.43 + 1.44 + mEditor = aEditor; 1.45 + mExistingRightNode = do_QueryInterface(aNode); 1.46 + mOffset = aOffset; 1.47 + return NS_OK; 1.48 +} 1.49 + 1.50 +NS_IMETHODIMP SplitElementTxn::DoTransaction(void) 1.51 +{ 1.52 + NS_ASSERTION(mExistingRightNode && mEditor, "bad state"); 1.53 + if (!mExistingRightNode || !mEditor) { return NS_ERROR_NOT_INITIALIZED; } 1.54 + 1.55 + // create a new node 1.56 + nsresult result = mExistingRightNode->CloneNode(false, 1, getter_AddRefs(mNewLeftNode)); 1.57 + NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewLeftNode)), "could not create element."); 1.58 + NS_ENSURE_SUCCESS(result, result); 1.59 + NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NULL_POINTER); 1.60 + mEditor->MarkNodeDirty(mExistingRightNode); 1.61 + 1.62 + // get the parent node 1.63 + result = mExistingRightNode->GetParentNode(getter_AddRefs(mParent)); 1.64 + NS_ENSURE_SUCCESS(result, result); 1.65 + NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER); 1.66 + 1.67 + // insert the new node 1.68 + result = mEditor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent); 1.69 + if (mNewLeftNode) { 1.70 + bool bAdjustSelection; 1.71 + mEditor->ShouldTxnSetSelection(&bAdjustSelection); 1.72 + if (bAdjustSelection) 1.73 + { 1.74 + nsCOMPtr<nsISelection> selection; 1.75 + result = mEditor->GetSelection(getter_AddRefs(selection)); 1.76 + NS_ENSURE_SUCCESS(result, result); 1.77 + NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); 1.78 + result = selection->Collapse(mNewLeftNode, mOffset); 1.79 + } 1.80 + else 1.81 + { 1.82 + // do nothing - dom range gravity will adjust selection 1.83 + } 1.84 + } 1.85 + return result; 1.86 +} 1.87 + 1.88 +NS_IMETHODIMP SplitElementTxn::UndoTransaction(void) 1.89 +{ 1.90 + NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state"); 1.91 + if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) { 1.92 + return NS_ERROR_NOT_INITIALIZED; 1.93 + } 1.94 + 1.95 + // this assumes Do inserted the new node in front of the prior existing node 1.96 + nsCOMPtr<nsINode> rightNode = do_QueryInterface(mExistingRightNode); 1.97 + nsCOMPtr<nsINode> leftNode = do_QueryInterface(mNewLeftNode); 1.98 + nsCOMPtr<nsINode> parent = do_QueryInterface(mParent); 1.99 + NS_ENSURE_TRUE(rightNode && leftNode && parent, NS_ERROR_FAILURE); 1.100 + return mEditor->JoinNodesImpl(rightNode, leftNode, parent); 1.101 +} 1.102 + 1.103 +/* redo cannot simply resplit the right node, because subsequent transactions 1.104 + * on the redo stack may depend on the left node existing in its previous state. 1.105 + */ 1.106 +NS_IMETHODIMP SplitElementTxn::RedoTransaction(void) 1.107 +{ 1.108 + NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state"); 1.109 + if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) { 1.110 + return NS_ERROR_NOT_INITIALIZED; 1.111 + } 1.112 + 1.113 + nsresult result; 1.114 + nsCOMPtr<nsIDOMNode>resultNode; 1.115 + // first, massage the existing node so it is in its post-split state 1.116 + nsCOMPtr<nsIDOMCharacterData>rightNodeAsText = do_QueryInterface(mExistingRightNode); 1.117 + if (rightNodeAsText) 1.118 + { 1.119 + nsresult result = rightNodeAsText->DeleteData(0, mOffset); 1.120 + NS_ENSURE_SUCCESS(result, result); 1.121 + } 1.122 + else 1.123 + { 1.124 + nsCOMPtr<nsIDOMNode>child; 1.125 + nsCOMPtr<nsIDOMNode>nextSibling; 1.126 + result = mExistingRightNode->GetFirstChild(getter_AddRefs(child)); 1.127 + int32_t i; 1.128 + for (i=0; i<mOffset; i++) 1.129 + { 1.130 + if (NS_FAILED(result)) {return result;} 1.131 + if (!child) {return NS_ERROR_NULL_POINTER;} 1.132 + child->GetNextSibling(getter_AddRefs(nextSibling)); 1.133 + result = mExistingRightNode->RemoveChild(child, getter_AddRefs(resultNode)); 1.134 + if (NS_SUCCEEDED(result)) 1.135 + { 1.136 + result = mNewLeftNode->AppendChild(child, getter_AddRefs(resultNode)); 1.137 + } 1.138 + child = do_QueryInterface(nextSibling); 1.139 + } 1.140 + } 1.141 + // second, re-insert the left node into the tree 1.142 + result = mParent->InsertBefore(mNewLeftNode, mExistingRightNode, getter_AddRefs(resultNode)); 1.143 + return result; 1.144 +} 1.145 + 1.146 + 1.147 +NS_IMETHODIMP SplitElementTxn::GetTxnDescription(nsAString& aString) 1.148 +{ 1.149 + aString.AssignLiteral("SplitElementTxn"); 1.150 + return NS_OK; 1.151 +} 1.152 + 1.153 +NS_IMETHODIMP SplitElementTxn::GetNewNode(nsIDOMNode **aNewNode) 1.154 +{ 1.155 + NS_ENSURE_TRUE(aNewNode, NS_ERROR_NULL_POINTER); 1.156 + NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NOT_INITIALIZED); 1.157 + *aNewNode = mNewLeftNode; 1.158 + NS_ADDREF(*aNewNode); 1.159 + return NS_OK; 1.160 +}