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/. */
6 #include "ReplaceTextTransaction.h"
8 #include "HTMLEditUtils.h"
10 #include "mozilla/Logging.h"
11 #include "mozilla/OwningNonNull.h"
12 #include "mozilla/ToString.h"
18 std::ostream
& operator<<(std::ostream
& aStream
,
19 const ReplaceTextTransaction
& aTransaction
) {
20 aStream
<< "{ mTextNode=" << aTransaction
.mTextNode
.get();
21 if (aTransaction
.mTextNode
) {
22 aStream
<< " (" << *aTransaction
.mTextNode
<< ")";
24 aStream
<< ", mStringToInsert=\""
25 << NS_ConvertUTF16toUTF8(aTransaction
.mStringToInsert
).get() << "\""
26 << ", mStringToBeReplaced=\""
27 << NS_ConvertUTF16toUTF8(aTransaction
.mStringToBeReplaced
).get()
28 << "\", mOffset=" << aTransaction
.mOffset
29 << ", mEditorBase=" << aTransaction
.mEditorBase
.get() << " }";
33 NS_IMPL_CYCLE_COLLECTION_INHERITED(ReplaceTextTransaction
, EditTransactionBase
,
34 mEditorBase
, mTextNode
)
36 NS_IMPL_ADDREF_INHERITED(ReplaceTextTransaction
, EditTransactionBase
)
37 NS_IMPL_RELEASE_INHERITED(ReplaceTextTransaction
, EditTransactionBase
)
38 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReplaceTextTransaction
)
39 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase
)
41 NS_IMETHODIMP
ReplaceTextTransaction::DoTransaction() {
42 MOZ_LOG(GetLogModule(), LogLevel::Info
,
43 ("%p ReplaceTextTransaction::%s this=%s", this, __FUNCTION__
,
44 ToString(*this).c_str()));
46 if (NS_WARN_IF(!mEditorBase
) || NS_WARN_IF(!mTextNode
) ||
47 NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(*mTextNode
))) {
48 return NS_ERROR_NOT_AVAILABLE
;
51 OwningNonNull
<EditorBase
> editorBase
= *mEditorBase
;
52 OwningNonNull
<Text
> textNode
= *mTextNode
;
55 editorBase
->DoReplaceText(textNode
, mOffset
, mStringToBeReplaced
.Length(),
56 mStringToInsert
, error
);
58 NS_WARNING("EditorBase::DoReplaceText() failed");
59 return error
.StealNSResult();
61 // XXX What should we do if mutation event listener changed the node?
62 editorBase
->RangeUpdaterRef().SelAdjReplaceText(textNode
, mOffset
,
63 mStringToBeReplaced
.Length(),
64 mStringToInsert
.Length());
66 if (!editorBase
->AllowsTransactionsToChangeSelection()) {
70 // XXX Should we stop setting selection when mutation event listener
71 // modifies the text node?
72 RefPtr
<Selection
> selection
= editorBase
->GetSelection();
73 if (NS_WARN_IF(!selection
)) {
74 return NS_ERROR_FAILURE
;
76 DebugOnly
<nsresult
> rvIgnored
= selection
->CollapseInLimiter(
77 textNode
, mOffset
+ mStringToInsert
.Length());
78 if (NS_WARN_IF(editorBase
->Destroyed())) {
79 return NS_ERROR_EDITOR_DESTROYED
;
81 NS_ASSERTION(NS_SUCCEEDED(rvIgnored
),
82 "Selection::CollapseInLimiter() failed, but ignored");
86 NS_IMETHODIMP
ReplaceTextTransaction::UndoTransaction() {
87 MOZ_LOG(GetLogModule(), LogLevel::Info
,
88 ("%p ReplaceTextTransaction::%s this=%s", this, __FUNCTION__
,
89 ToString(*this).c_str()));
91 if (NS_WARN_IF(!mEditorBase
) || NS_WARN_IF(!mTextNode
) ||
92 NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(*mTextNode
))) {
93 return NS_ERROR_NOT_AVAILABLE
;
97 nsAutoString insertedString
;
98 mTextNode
->SubstringData(mOffset
, mStringToInsert
.Length(), insertedString
,
100 if (error
.Failed()) {
101 NS_WARNING("CharacterData::SubstringData() failed");
102 return error
.StealNSResult();
104 if (insertedString
!= mStringToInsert
) {
106 "ReplaceTextTransaction::UndoTransaction() did nothing due to "
111 OwningNonNull
<EditorBase
> editorBase
= *mEditorBase
;
112 OwningNonNull
<Text
> textNode
= *mTextNode
;
114 editorBase
->DoReplaceText(textNode
, mOffset
, mStringToInsert
.Length(),
115 mStringToBeReplaced
, error
);
116 if (error
.Failed()) {
117 NS_WARNING("EditorBase::DoReplaceText() failed");
118 return error
.StealNSResult();
120 // XXX What should we do if mutation event listener changed the node?
121 editorBase
->RangeUpdaterRef().SelAdjReplaceText(textNode
, mOffset
,
122 mStringToInsert
.Length(),
123 mStringToBeReplaced
.Length());
125 if (!editorBase
->AllowsTransactionsToChangeSelection()) {
129 // XXX Should we stop setting selection when mutation event listener
130 // modifies the text node?
131 RefPtr
<Selection
> selection
= editorBase
->GetSelection();
132 if (NS_WARN_IF(!selection
)) {
133 return NS_ERROR_FAILURE
;
135 DebugOnly
<nsresult
> rvIgnored
= selection
->CollapseInLimiter(
136 textNode
, mOffset
+ mStringToBeReplaced
.Length());
137 if (NS_WARN_IF(editorBase
->Destroyed())) {
138 return NS_ERROR_EDITOR_DESTROYED
;
140 NS_ASSERTION(NS_SUCCEEDED(rvIgnored
),
141 "Selection::CollapseInLimiter() failed, but ignored");
145 NS_IMETHODIMP
ReplaceTextTransaction::RedoTransaction() {
146 MOZ_LOG(GetLogModule(), LogLevel::Info
,
147 ("%p ReplaceTextTransaction::%s this=%s", this, __FUNCTION__
,
148 ToString(*this).c_str()));
150 if (NS_WARN_IF(!mEditorBase
) || NS_WARN_IF(!mTextNode
) ||
151 NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(*mTextNode
))) {
152 return NS_ERROR_NOT_AVAILABLE
;
156 nsAutoString undoneString
;
157 mTextNode
->SubstringData(mOffset
, mStringToBeReplaced
.Length(), undoneString
,
159 if (error
.Failed()) {
160 NS_WARNING("CharacterData::SubstringData() failed");
161 return error
.StealNSResult();
163 if (undoneString
!= mStringToBeReplaced
) {
165 "ReplaceTextTransaction::RedoTransaction() did nothing due to "
170 OwningNonNull
<EditorBase
> editorBase
= *mEditorBase
;
171 OwningNonNull
<Text
> textNode
= *mTextNode
;
173 editorBase
->DoReplaceText(textNode
, mOffset
, mStringToBeReplaced
.Length(),
174 mStringToInsert
, error
);
175 if (error
.Failed()) {
176 NS_WARNING("EditorBase::DoReplaceText() failed");
177 return error
.StealNSResult();
179 // XXX What should we do if mutation event listener changed the node?
180 editorBase
->RangeUpdaterRef().SelAdjReplaceText(textNode
, mOffset
,
181 mStringToBeReplaced
.Length(),
182 mStringToInsert
.Length());
184 if (!editorBase
->AllowsTransactionsToChangeSelection()) {
188 // XXX Should we stop setting selection when mutation event listener
189 // modifies the text node?
190 RefPtr
<Selection
> selection
= editorBase
->GetSelection();
191 if (NS_WARN_IF(!selection
)) {
192 return NS_ERROR_FAILURE
;
194 DebugOnly
<nsresult
> rvIgnored
= selection
->CollapseInLimiter(
195 textNode
, mOffset
+ mStringToInsert
.Length());
196 if (NS_WARN_IF(editorBase
->Destroyed())) {
197 return NS_ERROR_EDITOR_DESTROYED
;
199 NS_ASSERTION(NS_SUCCEEDED(rvIgnored
),
200 "Selection::CollapseInLimiter() failed, but ignored");
204 } // namespace mozilla