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"
8 #include "mozilla/EditorBase.h" // mEditorBase
9 #include "mozilla/Logging.h"
10 #include "mozilla/SelectionState.h" // RangeUpdater
11 #include "mozilla/ToString.h"
12 #include "mozilla/dom/Selection.h" // Selection local var
13 #include "mozilla/dom/Text.h" // mTextNode
14 #include "nsAString.h" // nsAString parameter
15 #include "nsDebug.h" // for NS_ASSERTION, etc.
16 #include "nsError.h" // for NS_OK, etc.
17 #include "nsQueryObject.h" // for do_QueryObject
24 already_AddRefed
<InsertTextTransaction
> InsertTextTransaction::Create(
25 EditorBase
& aEditorBase
, const nsAString
& aStringToInsert
,
26 const EditorDOMPointInText
& aPointToInsert
) {
27 MOZ_ASSERT(aPointToInsert
.IsSetAndValid());
28 RefPtr
<InsertTextTransaction
> transaction
=
29 new InsertTextTransaction(aEditorBase
, aStringToInsert
, aPointToInsert
);
30 return transaction
.forget();
33 InsertTextTransaction::InsertTextTransaction(
34 EditorBase
& aEditorBase
, const nsAString
& aStringToInsert
,
35 const EditorDOMPointInText
& aPointToInsert
)
36 : mTextNode(aPointToInsert
.ContainerAsText()),
37 mOffset(aPointToInsert
.Offset()),
38 mStringToInsert(aStringToInsert
),
39 mEditorBase(&aEditorBase
) {}
41 std::ostream
& operator<<(std::ostream
& aStream
,
42 const InsertTextTransaction
& aTransaction
) {
43 aStream
<< "{ mTextNode=" << aTransaction
.mTextNode
.get();
44 if (aTransaction
.mTextNode
) {
45 aStream
<< " (" << *aTransaction
.mTextNode
<< ")";
47 aStream
<< ", mOffset=" << aTransaction
.mOffset
<< ", mStringToInsert=\""
48 << NS_ConvertUTF16toUTF8(aTransaction
.mStringToInsert
).get() << "\""
49 << ", mEditorBase=" << aTransaction
.mEditorBase
.get() << " }";
53 NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTransaction
, EditTransactionBase
,
54 mEditorBase
, mTextNode
)
56 NS_IMPL_ADDREF_INHERITED(InsertTextTransaction
, EditTransactionBase
)
57 NS_IMPL_RELEASE_INHERITED(InsertTextTransaction
, EditTransactionBase
)
58 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertTextTransaction
)
59 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase
)
61 NS_IMETHODIMP
InsertTextTransaction::DoTransaction() {
62 MOZ_LOG(GetLogModule(), LogLevel::Info
,
63 ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__
,
64 ToString(*this).c_str()));
66 if (NS_WARN_IF(!mEditorBase
) || NS_WARN_IF(!mTextNode
)) {
67 return NS_ERROR_NOT_AVAILABLE
;
70 OwningNonNull
<EditorBase
> editorBase
= *mEditorBase
;
71 OwningNonNull
<Text
> textNode
= *mTextNode
;
74 editorBase
->DoInsertText(textNode
, mOffset
, mStringToInsert
, error
);
76 NS_WARNING("EditorBase::DoInsertText() failed");
77 return error
.StealNSResult();
80 // Only set selection to insertion point if editor gives permission
81 if (editorBase
->AllowsTransactionsToChangeSelection()) {
82 RefPtr
<Selection
> selection
= editorBase
->GetSelection();
83 if (NS_WARN_IF(!selection
)) {
84 return NS_ERROR_FAILURE
;
86 DebugOnly
<nsresult
> rvIgnored
= selection
->CollapseInLimiter(
87 textNode
, mOffset
+ mStringToInsert
.Length());
88 NS_ASSERTION(NS_SUCCEEDED(rvIgnored
),
89 "Selection::CollapseInLimiter() failed, but ignored");
91 // Do nothing - DOM Range gravity will adjust selection
93 // XXX Other transactions do not do this but its callers do.
94 // Why do this transaction do this by itself?
95 editorBase
->RangeUpdaterRef().SelAdjInsertText(textNode
, mOffset
,
96 mStringToInsert
.Length());
101 NS_IMETHODIMP
InsertTextTransaction::UndoTransaction() {
102 MOZ_LOG(GetLogModule(), LogLevel::Info
,
103 ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__
,
104 ToString(*this).c_str()));
106 if (NS_WARN_IF(!mEditorBase
) || NS_WARN_IF(!mTextNode
)) {
107 return NS_ERROR_NOT_INITIALIZED
;
109 OwningNonNull
<EditorBase
> editorBase
= *mEditorBase
;
110 OwningNonNull
<Text
> textNode
= *mTextNode
;
112 editorBase
->DoDeleteText(textNode
, mOffset
, mStringToInsert
.Length(), error
);
113 NS_WARNING_ASSERTION(!error
.Failed(), "EditorBase::DoDeleteText() failed");
114 return error
.StealNSResult();
117 NS_IMETHODIMP
InsertTextTransaction::RedoTransaction() {
118 MOZ_LOG(GetLogModule(), LogLevel::Info
,
119 ("%p InsertTextTransaction::%s this=%s", this, __FUNCTION__
,
120 ToString(*this).c_str()));
121 return DoTransaction();
124 NS_IMETHODIMP
InsertTextTransaction::Merge(nsITransaction
* aOtherTransaction
,
126 MOZ_LOG(GetLogModule(), LogLevel::Debug
,
127 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) this=%s", this,
128 __FUNCTION__
, aOtherTransaction
, ToString(*this).c_str()));
130 if (NS_WARN_IF(!aOtherTransaction
) || NS_WARN_IF(!aDidMerge
)) {
131 return NS_ERROR_INVALID_ARG
;
133 // Set out param default value
136 RefPtr
<EditTransactionBase
> otherTransactionBase
=
137 aOtherTransaction
->GetAsEditTransactionBase();
138 if (!otherTransactionBase
) {
140 GetLogModule(), LogLevel::Debug
,
141 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned false",
142 this, __FUNCTION__
, aOtherTransaction
));
146 // If aTransaction is a InsertTextTransaction, and if the selection hasn't
147 // changed, then absorb it.
148 InsertTextTransaction
* otherInsertTextTransaction
=
149 otherTransactionBase
->GetAsInsertTextTransaction();
150 if (!otherInsertTextTransaction
||
151 !IsSequentialInsert(*otherInsertTextTransaction
)) {
153 GetLogModule(), LogLevel::Debug
,
154 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned false",
155 this, __FUNCTION__
, aOtherTransaction
));
159 nsAutoString otherData
;
160 otherInsertTextTransaction
->GetData(otherData
);
161 mStringToInsert
+= otherData
;
163 MOZ_LOG(GetLogModule(), LogLevel::Debug
,
164 ("%p InsertTextTransaction::%s(aOtherTransaction=%p) returned true",
165 this, __FUNCTION__
, aOtherTransaction
));
169 /* ============ private methods ================== */
171 void InsertTextTransaction::GetData(nsString
& aResult
) {
172 aResult
= mStringToInsert
;
175 bool InsertTextTransaction::IsSequentialInsert(
176 InsertTextTransaction
& aOtherTransaction
) {
177 return aOtherTransaction
.mTextNode
== mTextNode
&&
178 aOtherTransaction
.mOffset
== mOffset
+ mStringToInsert
.Length();
181 } // namespace mozilla