Line data Source code
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 "SplitNodeTransaction.h"
7 :
8 : #include "mozilla/EditorBase.h" // for EditorBase
9 : #include "mozilla/dom/Selection.h"
10 : #include "nsAString.h"
11 : #include "nsDebug.h" // for NS_ASSERTION, etc.
12 : #include "nsError.h" // for NS_ERROR_NOT_INITIALIZED, etc.
13 : #include "nsIContent.h" // for nsIContent
14 :
15 : namespace mozilla {
16 :
17 : using namespace dom;
18 :
19 0 : SplitNodeTransaction::SplitNodeTransaction(EditorBase& aEditorBase,
20 : nsIContent& aNode,
21 0 : int32_t aOffset)
22 : : mEditorBase(&aEditorBase)
23 : , mExistingRightNode(&aNode)
24 0 : , mOffset(aOffset)
25 : {
26 0 : }
27 :
28 0 : SplitNodeTransaction::~SplitNodeTransaction()
29 : {
30 0 : }
31 :
32 0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(SplitNodeTransaction, EditTransactionBase,
33 : mEditorBase,
34 : mParent,
35 : mNewLeftNode)
36 :
37 0 : NS_IMPL_ADDREF_INHERITED(SplitNodeTransaction, EditTransactionBase)
38 0 : NS_IMPL_RELEASE_INHERITED(SplitNodeTransaction, EditTransactionBase)
39 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SplitNodeTransaction)
40 0 : NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
41 :
42 : NS_IMETHODIMP
43 0 : SplitNodeTransaction::DoTransaction()
44 : {
45 0 : if (NS_WARN_IF(!mEditorBase)) {
46 0 : return NS_ERROR_NOT_INITIALIZED;
47 : }
48 :
49 : // Create a new node
50 0 : ErrorResult rv;
51 : // Don't use .downcast directly because AsContent has an assertion we want
52 0 : nsCOMPtr<nsINode> clone = mExistingRightNode->CloneNode(false, rv);
53 0 : NS_ASSERTION(!rv.Failed() && clone, "Could not create clone");
54 0 : NS_ENSURE_TRUE(!rv.Failed() && clone, rv.StealNSResult());
55 0 : mNewLeftNode = dont_AddRef(clone.forget().take()->AsContent());
56 0 : mEditorBase->MarkNodeDirty(mExistingRightNode->AsDOMNode());
57 :
58 : // Get the parent node
59 0 : mParent = mExistingRightNode->GetParentNode();
60 0 : NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER);
61 :
62 : // Insert the new node
63 0 : rv = mEditorBase->SplitNodeImpl(*mExistingRightNode, mOffset, *mNewLeftNode);
64 0 : if (mEditorBase->GetShouldTxnSetSelection()) {
65 0 : RefPtr<Selection> selection = mEditorBase->GetSelection();
66 0 : NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
67 0 : rv = selection->Collapse(mNewLeftNode, mOffset);
68 : }
69 0 : return rv.StealNSResult();
70 : }
71 :
72 : NS_IMETHODIMP
73 0 : SplitNodeTransaction::UndoTransaction()
74 : {
75 0 : if (NS_WARN_IF(!mEditorBase) ||
76 0 : NS_WARN_IF(!mNewLeftNode) ||
77 0 : NS_WARN_IF(!mParent)) {
78 0 : return NS_ERROR_NOT_INITIALIZED;
79 : }
80 :
81 : // This assumes Do inserted the new node in front of the prior existing node
82 0 : return mEditorBase->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent);
83 : }
84 :
85 : /* Redo cannot simply resplit the right node, because subsequent transactions
86 : * on the redo stack may depend on the left node existing in its previous
87 : * state.
88 : */
89 : NS_IMETHODIMP
90 0 : SplitNodeTransaction::RedoTransaction()
91 : {
92 0 : if (NS_WARN_IF(!mNewLeftNode) ||
93 0 : NS_WARN_IF(!mParent)) {
94 0 : return NS_ERROR_NOT_INITIALIZED;
95 : }
96 :
97 0 : ErrorResult rv;
98 : // First, massage the existing node so it is in its post-split state
99 0 : if (mExistingRightNode->GetAsText()) {
100 0 : rv = mExistingRightNode->GetAsText()->DeleteData(0, mOffset);
101 0 : NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult());
102 : } else {
103 0 : nsCOMPtr<nsIContent> child = mExistingRightNode->GetFirstChild();
104 0 : nsCOMPtr<nsIContent> nextSibling;
105 0 : for (int32_t i=0; i < mOffset; i++) {
106 0 : if (rv.Failed()) {
107 0 : return rv.StealNSResult();
108 : }
109 0 : if (!child) {
110 0 : return NS_ERROR_NULL_POINTER;
111 : }
112 0 : nextSibling = child->GetNextSibling();
113 0 : mExistingRightNode->RemoveChild(*child, rv);
114 0 : if (!rv.Failed()) {
115 0 : mNewLeftNode->AppendChild(*child, rv);
116 : }
117 0 : child = nextSibling;
118 : }
119 : }
120 : // Second, re-insert the left node into the tree
121 0 : nsCOMPtr<nsIContent> refNode = mExistingRightNode;
122 0 : mParent->InsertBefore(*mNewLeftNode, refNode, rv);
123 0 : return rv.StealNSResult();
124 : }
125 :
126 :
127 : NS_IMETHODIMP
128 0 : SplitNodeTransaction::GetTxnDescription(nsAString& aString)
129 : {
130 0 : aString.AssignLiteral("SplitNodeTransaction");
131 0 : return NS_OK;
132 : }
133 :
134 : nsIContent*
135 0 : SplitNodeTransaction::GetNewNode()
136 : {
137 0 : return mNewLeftNode;
138 : }
139 :
140 : } // namespace mozilla
|