editor/libeditor/base/SplitElementTxn.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:c885c8020616
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include <stdio.h> // for printf
7
8 #include "SplitElementTxn.h"
9 #include "nsAString.h"
10 #include "nsDebug.h" // for NS_ASSERTION, etc
11 #include "nsEditor.h" // for nsEditor
12 #include "nsError.h" // for NS_ERROR_NOT_INITIALIZED, etc
13 #include "nsIDOMCharacterData.h" // for nsIDOMCharacterData
14 #include "nsIDOMNode.h" // for nsIDOMNode
15 #include "nsIEditor.h" // for nsEditor::DebugDumpContent, etc
16 #include "nsISelection.h" // for nsISelection
17 #include "nsISupportsUtils.h" // for NS_ADDREF
18
19 // note that aEditor is not refcounted
20 SplitElementTxn::SplitElementTxn()
21 : EditTxn()
22 {
23 }
24
25 NS_IMPL_CYCLE_COLLECTION_INHERITED(SplitElementTxn, EditTxn,
26 mParent,
27 mNewLeftNode)
28
29 NS_IMPL_ADDREF_INHERITED(SplitElementTxn, EditTxn)
30 NS_IMPL_RELEASE_INHERITED(SplitElementTxn, EditTxn)
31 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SplitElementTxn)
32 NS_INTERFACE_MAP_END_INHERITING(EditTxn)
33
34 NS_IMETHODIMP SplitElementTxn::Init(nsEditor *aEditor,
35 nsIDOMNode *aNode,
36 int32_t aOffset)
37 {
38 NS_ASSERTION(aEditor && aNode, "bad args");
39 if (!aEditor || !aNode) { return NS_ERROR_NOT_INITIALIZED; }
40
41 mEditor = aEditor;
42 mExistingRightNode = do_QueryInterface(aNode);
43 mOffset = aOffset;
44 return NS_OK;
45 }
46
47 NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
48 {
49 NS_ASSERTION(mExistingRightNode && mEditor, "bad state");
50 if (!mExistingRightNode || !mEditor) { return NS_ERROR_NOT_INITIALIZED; }
51
52 // create a new node
53 nsresult result = mExistingRightNode->CloneNode(false, 1, getter_AddRefs(mNewLeftNode));
54 NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewLeftNode)), "could not create element.");
55 NS_ENSURE_SUCCESS(result, result);
56 NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NULL_POINTER);
57 mEditor->MarkNodeDirty(mExistingRightNode);
58
59 // get the parent node
60 result = mExistingRightNode->GetParentNode(getter_AddRefs(mParent));
61 NS_ENSURE_SUCCESS(result, result);
62 NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER);
63
64 // insert the new node
65 result = mEditor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent);
66 if (mNewLeftNode) {
67 bool bAdjustSelection;
68 mEditor->ShouldTxnSetSelection(&bAdjustSelection);
69 if (bAdjustSelection)
70 {
71 nsCOMPtr<nsISelection> selection;
72 result = mEditor->GetSelection(getter_AddRefs(selection));
73 NS_ENSURE_SUCCESS(result, result);
74 NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
75 result = selection->Collapse(mNewLeftNode, mOffset);
76 }
77 else
78 {
79 // do nothing - dom range gravity will adjust selection
80 }
81 }
82 return result;
83 }
84
85 NS_IMETHODIMP SplitElementTxn::UndoTransaction(void)
86 {
87 NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state");
88 if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) {
89 return NS_ERROR_NOT_INITIALIZED;
90 }
91
92 // this assumes Do inserted the new node in front of the prior existing node
93 nsCOMPtr<nsINode> rightNode = do_QueryInterface(mExistingRightNode);
94 nsCOMPtr<nsINode> leftNode = do_QueryInterface(mNewLeftNode);
95 nsCOMPtr<nsINode> parent = do_QueryInterface(mParent);
96 NS_ENSURE_TRUE(rightNode && leftNode && parent, NS_ERROR_FAILURE);
97 return mEditor->JoinNodesImpl(rightNode, leftNode, parent);
98 }
99
100 /* redo cannot simply resplit the right node, because subsequent transactions
101 * on the redo stack may depend on the left node existing in its previous state.
102 */
103 NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
104 {
105 NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state");
106 if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) {
107 return NS_ERROR_NOT_INITIALIZED;
108 }
109
110 nsresult result;
111 nsCOMPtr<nsIDOMNode>resultNode;
112 // first, massage the existing node so it is in its post-split state
113 nsCOMPtr<nsIDOMCharacterData>rightNodeAsText = do_QueryInterface(mExistingRightNode);
114 if (rightNodeAsText)
115 {
116 nsresult result = rightNodeAsText->DeleteData(0, mOffset);
117 NS_ENSURE_SUCCESS(result, result);
118 }
119 else
120 {
121 nsCOMPtr<nsIDOMNode>child;
122 nsCOMPtr<nsIDOMNode>nextSibling;
123 result = mExistingRightNode->GetFirstChild(getter_AddRefs(child));
124 int32_t i;
125 for (i=0; i<mOffset; i++)
126 {
127 if (NS_FAILED(result)) {return result;}
128 if (!child) {return NS_ERROR_NULL_POINTER;}
129 child->GetNextSibling(getter_AddRefs(nextSibling));
130 result = mExistingRightNode->RemoveChild(child, getter_AddRefs(resultNode));
131 if (NS_SUCCEEDED(result))
132 {
133 result = mNewLeftNode->AppendChild(child, getter_AddRefs(resultNode));
134 }
135 child = do_QueryInterface(nextSibling);
136 }
137 }
138 // second, re-insert the left node into the tree
139 result = mParent->InsertBefore(mNewLeftNode, mExistingRightNode, getter_AddRefs(resultNode));
140 return result;
141 }
142
143
144 NS_IMETHODIMP SplitElementTxn::GetTxnDescription(nsAString& aString)
145 {
146 aString.AssignLiteral("SplitElementTxn");
147 return NS_OK;
148 }
149
150 NS_IMETHODIMP SplitElementTxn::GetNewNode(nsIDOMNode **aNewNode)
151 {
152 NS_ENSURE_TRUE(aNewNode, NS_ERROR_NULL_POINTER);
153 NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NOT_INITIALIZED);
154 *aNewNode = mNewLeftNode;
155 NS_ADDREF(*aNewNode);
156 return NS_OK;
157 }

mercurial