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 "InsertTextTransaction.h"
9 #include "mozilla/EditorBase.h" // mEditorBase
10 #include "mozilla/Logging.h"
11 #include "mozilla/SelectionState.h" // RangeUpdater
12 #include "mozilla/ToString.h"
13 #include "mozilla/dom/Selection.h" // Selection local var
14 #include "mozilla/dom/Text.h" // mTextNode
16 #include "nsAString.h" // nsAString parameter
17 #include "nsDebug.h" // for NS_ASSERTION, etc.
18 #include "nsError.h" // for NS_OK, etc.
19 #include "nsQueryObject.h" // for do_QueryObject
26 already_AddRefed
<InsertTextTransaction
> InsertTextTransaction::Create(
27 EditorBase
& aEditorBase
, const nsAString
& aStringToInsert
,
28 const EditorDOMPointInText
& aPointToInsert
) {
29 MOZ_ASSERT(aPointToInsert
.IsSetAndValid());
30 RefPtr
<InsertTextTransaction
> transaction
=
31 new InsertTextTransaction(aEditorBase
, aStringToInsert
, aPointToInsert
);
32 return transaction
.forget();
35 InsertTextTransaction::InsertTextTransaction(
36 EditorBase
& aEditorBase
, const nsAString
& aStringToInsert
,
37 const EditorDOMPointInText
& aPointToInsert
)
38 : mTextNode(aPointToInsert
.ContainerAs
<Text
>()),
39 mOffset(aPointToInsert
.Offset()),
40 mStringToInsert(aStringToInsert
),
41 mEditorBase(&aEditorBase
) {}
43 std::ostream
& operator<<(std::ostream
& aStream
,
44 const InsertTextTransaction
& aTransaction
) {
45 aStream
<< "{ mTextNode=" << aTransaction
.mTextNode
.get();
46 if (aTransaction
.mTextNode
) {
47 aStream
<< " (" << *aTransaction
.mTextNode
<< ")";
49 aStream
<< ", mOffset=" << aTransaction
.mOffset
<< ", mStringToInsert=\""
50 << NS_ConvertUTF16toUTF8(aTransaction
.mStringToInsert
).get() << "\""
51 << ", mEditorBase=" << aTransaction
.mEditorBase
.get() << " }";
55 NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTransaction
, EditTransactionBase
,
56 mEditorBase
, mTextNode
)
58 NS_IMPL_ADDREF_INHERITED(InsertTextTransaction
, EditTransactionBase
)
59 NS_IMPL_RELEASE_INHERITED(InsertTextTransaction
, EditTransactionBase
)
60 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertTextTransaction
)
61 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase
)
63 NS_IMETHODIMP
InsertTextTransaction::DoTransaction() {
64 MOZ_LOG(GetLogModule(), LogLevel::Info
,
65 ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__
,
66 ToString(*this).c_str()));
68 if (NS_WARN_IF(!mEditorBase
) || NS_WARN_IF(!mTextNode
)) {
69 return NS_ERROR_NOT_AVAILABLE
;
72 OwningNonNull
<EditorBase
> editorBase
= *mEditorBase
;
73 OwningNonNull
<Text
> textNode
= *mTextNode
;
76 editorBase
->DoInsertText(textNode
, mOffset
, mStringToInsert
, error
);
78 NS_WARNING("EditorBase::DoInsertText() failed");
79 return error
.StealNSResult();
82 editorBase
->RangeUpdaterRef().SelAdjInsertText(textNode
, mOffset
,
83 mStringToInsert
.Length());
87 NS_IMETHODIMP
InsertTextTransaction::UndoTransaction() {
88 MOZ_LOG(GetLogModule(), LogLevel::Info
,
89 ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__
,
90 ToString(*this).c_str()));
92 if (NS_WARN_IF(!mEditorBase
) || NS_WARN_IF(!mTextNode
)) {
93 return NS_ERROR_NOT_INITIALIZED
;
95 OwningNonNull
<EditorBase
> editorBase
= *mEditorBase
;
96 OwningNonNull
<Text
> textNode
= *mTextNode
;
98 editorBase
->DoDeleteText(textNode
, mOffset
, mStringToInsert
.Length(), error
);
99 NS_WARNING_ASSERTION(!error
.Failed(), "EditorBase::DoDeleteText() failed");
100 return error
.StealNSResult();
103 NS_IMETHODIMP
InsertTextTransaction::RedoTransaction() {
104 MOZ_LOG(GetLogModule(), LogLevel::Info
,
105 ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__
,
106 ToString(*this).c_str()));
107 nsresult rv
= DoTransaction();
109 NS_WARNING("InsertTextTransaction::DoTransaction() failed");
112 if (RefPtr
<EditorBase
> editorBase
= mEditorBase
) {
113 nsresult rv
= editorBase
->CollapseSelectionTo(
114 SuggestPointToPutCaret
<EditorRawDOMPoint
>());
115 if (NS_WARN_IF(rv
== NS_ERROR_EDITOR_DESTROYED
)) {
116 return NS_ERROR_EDITOR_DESTROYED
;
118 NS_WARNING_ASSERTION(
120 "EditorBase::CollapseSelectionTo() failed, but ignored");
125 NS_IMETHODIMP
InsertTextTransaction::Merge(nsITransaction
* aOtherTransaction
,
127 MOZ_LOG(GetLogModule(), LogLevel::Debug
,
128 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) this=%s", this,
129 __FUNCTION__
, aOtherTransaction
, ToString(*this).c_str()));
131 if (NS_WARN_IF(!aOtherTransaction
) || NS_WARN_IF(!aDidMerge
)) {
132 return NS_ERROR_INVALID_ARG
;
134 // Set out param default value
137 RefPtr
<EditTransactionBase
> otherTransactionBase
=
138 aOtherTransaction
->GetAsEditTransactionBase();
139 if (!otherTransactionBase
) {
141 GetLogModule(), LogLevel::Debug
,
142 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned false",
143 this, __FUNCTION__
, aOtherTransaction
));
147 // If aTransaction is a InsertTextTransaction, and if the selection hasn't
148 // changed, then absorb it.
149 InsertTextTransaction
* otherInsertTextTransaction
=
150 otherTransactionBase
->GetAsInsertTextTransaction();
151 if (!otherInsertTextTransaction
||
152 !IsSequentialInsert(*otherInsertTextTransaction
)) {
154 GetLogModule(), LogLevel::Debug
,
155 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned false",
156 this, __FUNCTION__
, aOtherTransaction
));
160 mStringToInsert
+= otherInsertTextTransaction
->GetData();
162 MOZ_LOG(GetLogModule(), LogLevel::Debug
,
163 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned true",
164 this, __FUNCTION__
, aOtherTransaction
));
168 /* ============ private methods ================== */
170 bool InsertTextTransaction::IsSequentialInsert(
171 InsertTextTransaction
& aOtherTransaction
) const {
172 return aOtherTransaction
.mTextNode
== mTextNode
&&
173 aOtherTransaction
.mOffset
== mOffset
+ mStringToInsert
.Length();
176 } // namespace mozilla