|
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 "InsertTextTxn.h" |
|
9 #include "nsAString.h" |
|
10 #include "nsDebug.h" // for NS_ASSERTION, etc |
|
11 #include "nsError.h" // for NS_OK, etc |
|
12 #include "nsIDOMCharacterData.h" // for nsIDOMCharacterData |
|
13 #include "nsIEditor.h" // for nsIEditor |
|
14 #include "nsISelection.h" // for nsISelection |
|
15 #include "nsISupportsUtils.h" // for NS_ADDREF_THIS, NS_RELEASE |
|
16 #include "nsITransaction.h" // for nsITransaction |
|
17 |
|
18 InsertTextTxn::InsertTextTxn() |
|
19 : EditTxn() |
|
20 { |
|
21 } |
|
22 |
|
23 NS_IMPL_CYCLE_COLLECTION_INHERITED(InsertTextTxn, EditTxn, |
|
24 mElement) |
|
25 |
|
26 NS_IMPL_ADDREF_INHERITED(InsertTextTxn, EditTxn) |
|
27 NS_IMPL_RELEASE_INHERITED(InsertTextTxn, EditTxn) |
|
28 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertTextTxn) |
|
29 if (aIID.Equals(InsertTextTxn::GetCID())) { |
|
30 *aInstancePtr = (void*)(InsertTextTxn*)this; |
|
31 NS_ADDREF_THIS(); |
|
32 return NS_OK; |
|
33 } else |
|
34 NS_INTERFACE_MAP_END_INHERITING(EditTxn) |
|
35 |
|
36 NS_IMETHODIMP InsertTextTxn::Init(nsIDOMCharacterData *aElement, |
|
37 uint32_t aOffset, |
|
38 const nsAString &aStringToInsert, |
|
39 nsIEditor *aEditor) |
|
40 { |
|
41 #if 0 |
|
42 nsAutoString text; |
|
43 aElement->GetData(text); |
|
44 printf("InsertTextTxn: Offset to insert at = %d. Text of the node to insert into:\n", aOffset); |
|
45 wprintf(text.get()); |
|
46 printf("\n"); |
|
47 #endif |
|
48 |
|
49 NS_ASSERTION(aElement && aEditor, "bad args"); |
|
50 NS_ENSURE_TRUE(aElement && aEditor, NS_ERROR_NULL_POINTER); |
|
51 |
|
52 mElement = do_QueryInterface(aElement); |
|
53 mOffset = aOffset; |
|
54 mStringToInsert = aStringToInsert; |
|
55 mEditor = aEditor; |
|
56 return NS_OK; |
|
57 } |
|
58 |
|
59 NS_IMETHODIMP InsertTextTxn::DoTransaction(void) |
|
60 { |
|
61 NS_ASSERTION(mElement && mEditor, "bad state"); |
|
62 if (!mElement || !mEditor) { return NS_ERROR_NOT_INITIALIZED; } |
|
63 |
|
64 nsresult result = mElement->InsertData(mOffset, mStringToInsert); |
|
65 NS_ENSURE_SUCCESS(result, result); |
|
66 |
|
67 // only set selection to insertion point if editor gives permission |
|
68 bool bAdjustSelection; |
|
69 mEditor->ShouldTxnSetSelection(&bAdjustSelection); |
|
70 if (bAdjustSelection) |
|
71 { |
|
72 nsCOMPtr<nsISelection> selection; |
|
73 result = mEditor->GetSelection(getter_AddRefs(selection)); |
|
74 NS_ENSURE_SUCCESS(result, result); |
|
75 NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER); |
|
76 result = selection->Collapse(mElement, mOffset+mStringToInsert.Length()); |
|
77 NS_ASSERTION((NS_SUCCEEDED(result)), "selection could not be collapsed after insert."); |
|
78 } |
|
79 else |
|
80 { |
|
81 // do nothing - dom range gravity will adjust selection |
|
82 } |
|
83 |
|
84 return result; |
|
85 } |
|
86 |
|
87 NS_IMETHODIMP InsertTextTxn::UndoTransaction(void) |
|
88 { |
|
89 NS_ASSERTION(mElement && mEditor, "bad state"); |
|
90 if (!mElement || !mEditor) { return NS_ERROR_NOT_INITIALIZED; } |
|
91 |
|
92 uint32_t length = mStringToInsert.Length(); |
|
93 return mElement->DeleteData(mOffset, length); |
|
94 } |
|
95 |
|
96 NS_IMETHODIMP InsertTextTxn::Merge(nsITransaction *aTransaction, bool *aDidMerge) |
|
97 { |
|
98 // set out param default value |
|
99 if (aDidMerge) |
|
100 *aDidMerge = false; |
|
101 nsresult result = NS_OK; |
|
102 if (aDidMerge && aTransaction) |
|
103 { |
|
104 // if aTransaction is a InsertTextTxn, and if the selection hasn't changed, |
|
105 // then absorb it |
|
106 InsertTextTxn *otherInsTxn = nullptr; |
|
107 aTransaction->QueryInterface(InsertTextTxn::GetCID(), (void **)&otherInsTxn); |
|
108 if (otherInsTxn) |
|
109 { |
|
110 if (IsSequentialInsert(otherInsTxn)) |
|
111 { |
|
112 nsAutoString otherData; |
|
113 otherInsTxn->GetData(otherData); |
|
114 mStringToInsert += otherData; |
|
115 *aDidMerge = true; |
|
116 } |
|
117 NS_RELEASE(otherInsTxn); |
|
118 } |
|
119 } |
|
120 return result; |
|
121 } |
|
122 |
|
123 NS_IMETHODIMP InsertTextTxn::GetTxnDescription(nsAString& aString) |
|
124 { |
|
125 aString.AssignLiteral("InsertTextTxn: "); |
|
126 aString += mStringToInsert; |
|
127 return NS_OK; |
|
128 } |
|
129 |
|
130 /* ============ protected methods ================== */ |
|
131 |
|
132 NS_IMETHODIMP InsertTextTxn::GetData(nsString& aResult) |
|
133 { |
|
134 aResult = mStringToInsert; |
|
135 return NS_OK; |
|
136 } |
|
137 |
|
138 bool InsertTextTxn::IsSequentialInsert(InsertTextTxn *aOtherTxn) |
|
139 { |
|
140 NS_ASSERTION(aOtherTxn, "null param"); |
|
141 if (aOtherTxn && aOtherTxn->mElement == mElement) |
|
142 { |
|
143 // here, we need to compare offsets. |
|
144 int32_t length = mStringToInsert.Length(); |
|
145 if (aOtherTxn->mOffset == (mOffset + length)) |
|
146 return true; |
|
147 } |
|
148 return false; |
|
149 } |