1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998-1999
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Pierre Phaneuf <pp@ludusdesign.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "PlaceholderTxn.h"
40 : #include "nsEditor.h"
41 : #include "IMETextTxn.h"
42 : #include "nsGkAtoms.h"
43 :
44 0 : PlaceholderTxn::PlaceholderTxn() : EditAggregateTxn(),
45 : mAbsorb(true),
46 : mForwarding(nsnull),
47 : mIMETextTxn(nsnull),
48 : mCommitted(false),
49 : mStartSel(nsnull),
50 : mEndSel(),
51 0 : mEditor(nsnull)
52 : {
53 0 : }
54 :
55 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(PlaceholderTxn)
56 :
57 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PlaceholderTxn,
58 : EditAggregateTxn)
59 0 : tmp->mStartSel->DoUnlink();
60 0 : tmp->mEndSel.DoUnlink();
61 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
62 :
63 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PlaceholderTxn,
64 : EditAggregateTxn)
65 0 : tmp->mStartSel->DoTraverse(cb);
66 0 : tmp->mEndSel.DoTraverse(cb);
67 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
68 :
69 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PlaceholderTxn)
70 0 : NS_INTERFACE_MAP_ENTRY(nsIAbsorbingTransaction)
71 0 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
72 0 : NS_INTERFACE_MAP_END_INHERITING(EditAggregateTxn)
73 :
74 0 : NS_IMPL_ADDREF_INHERITED(PlaceholderTxn, EditAggregateTxn)
75 0 : NS_IMPL_RELEASE_INHERITED(PlaceholderTxn, EditAggregateTxn)
76 :
77 0 : NS_IMETHODIMP PlaceholderTxn::Init(nsIAtom *aName, nsSelectionState *aSelState, nsIEditor *aEditor)
78 : {
79 0 : NS_ENSURE_TRUE(aEditor && aSelState, NS_ERROR_NULL_POINTER);
80 :
81 0 : mName = aName;
82 0 : mStartSel = aSelState;
83 0 : mEditor = aEditor;
84 0 : return NS_OK;
85 : }
86 :
87 0 : NS_IMETHODIMP PlaceholderTxn::DoTransaction(void)
88 : {
89 0 : return NS_OK;
90 : }
91 :
92 0 : NS_IMETHODIMP PlaceholderTxn::UndoTransaction(void)
93 : {
94 : // undo txns
95 0 : nsresult res = EditAggregateTxn::UndoTransaction();
96 0 : NS_ENSURE_SUCCESS(res, res);
97 :
98 0 : NS_ENSURE_TRUE(mStartSel, NS_ERROR_NULL_POINTER);
99 :
100 : // now restore selection
101 0 : nsCOMPtr<nsISelection> selection;
102 0 : res = mEditor->GetSelection(getter_AddRefs(selection));
103 0 : NS_ENSURE_SUCCESS(res, res);
104 0 : NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
105 0 : return mStartSel->RestoreSelection(selection);
106 : }
107 :
108 :
109 0 : NS_IMETHODIMP PlaceholderTxn::RedoTransaction(void)
110 : {
111 : // redo txns
112 0 : nsresult res = EditAggregateTxn::RedoTransaction();
113 0 : NS_ENSURE_SUCCESS(res, res);
114 :
115 : // now restore selection
116 0 : nsCOMPtr<nsISelection> selection;
117 0 : res = mEditor->GetSelection(getter_AddRefs(selection));
118 0 : NS_ENSURE_SUCCESS(res, res);
119 0 : NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
120 0 : return mEndSel.RestoreSelection(selection);
121 : }
122 :
123 :
124 0 : NS_IMETHODIMP PlaceholderTxn::Merge(nsITransaction *aTransaction, bool *aDidMerge)
125 : {
126 0 : NS_ENSURE_TRUE(aDidMerge && aTransaction, NS_ERROR_NULL_POINTER);
127 :
128 : // set out param default value
129 0 : *aDidMerge=false;
130 :
131 0 : if (mForwarding)
132 : {
133 0 : NS_NOTREACHED("tried to merge into a placeholder that was in forwarding mode!");
134 0 : return NS_ERROR_FAILURE;
135 : }
136 :
137 : // check to see if aTransaction is one of the editor's
138 : // private transactions. If not, we want to avoid merging
139 : // the foreign transaction into our placeholder since we
140 : // don't know what it does.
141 :
142 0 : nsCOMPtr<nsPIEditorTransaction> pTxn = do_QueryInterface(aTransaction);
143 0 : NS_ENSURE_TRUE(pTxn, NS_OK); // it's foreign so just bail!
144 :
145 0 : EditTxn *editTxn = (EditTxn*)aTransaction; //XXX: hack, not safe! need nsIEditTransaction!
146 : // determine if this incoming txn is a placeholder txn
147 0 : nsCOMPtr<nsIAbsorbingTransaction> plcTxn;// = do_QueryInterface(editTxn);
148 : // can't do_QueryInterface() above due to our broken transaction interfaces.
149 : // instead have to brute it below. ugh.
150 0 : editTxn->QueryInterface(NS_GET_IID(nsIAbsorbingTransaction), getter_AddRefs(plcTxn));
151 :
152 : // we are absorbing all txn's if mAbsorb is lit.
153 0 : if (mAbsorb)
154 : {
155 0 : nsRefPtr<IMETextTxn> otherTxn;
156 0 : if (NS_SUCCEEDED(aTransaction->QueryInterface(IMETextTxn::GetCID(), getter_AddRefs(otherTxn))) && otherTxn)
157 : {
158 : // special handling for IMETextTxn's: they need to merge with any previous
159 : // IMETextTxn in this placeholder, if possible.
160 0 : if (!mIMETextTxn)
161 : {
162 : // this is the first IME txn in the placeholder
163 0 : mIMETextTxn =otherTxn;
164 0 : AppendChild(editTxn);
165 : }
166 : else
167 : {
168 : bool didMerge;
169 0 : mIMETextTxn->Merge(otherTxn, &didMerge);
170 0 : if (!didMerge)
171 : {
172 : // it wouldn't merge. Earlier IME txn is already committed and will
173 : // not absorb further IME txns. So just stack this one after it
174 : // and remember it as a candidate for further merges.
175 0 : mIMETextTxn =otherTxn;
176 0 : AppendChild(editTxn);
177 : }
178 : }
179 : }
180 0 : else if (!plcTxn) // see bug 171243: just drop incoming placeholders on the floor.
181 : { // their children will be swallowed by this preexisting one.
182 0 : AppendChild(editTxn);
183 : }
184 0 : *aDidMerge = true;
185 : // RememberEndingSelection();
186 : // efficiency hack: no need to remember selection here, as we haven't yet
187 : // finished the initial batch and we know we will be told when the batch ends.
188 : // we can remeber the selection then.
189 : }
190 : else
191 : { // merge typing or IME or deletion transactions if the selection matches
192 0 : if (((mName.get() == nsGkAtoms::TypingTxnName) ||
193 0 : (mName.get() == nsGkAtoms::IMETxnName) ||
194 0 : (mName.get() == nsGkAtoms::DeleteTxnName))
195 0 : && !mCommitted )
196 : {
197 0 : nsCOMPtr<nsIAbsorbingTransaction> plcTxn;// = do_QueryInterface(editTxn);
198 : // can't do_QueryInterface() above due to our broken transaction interfaces.
199 : // instead have to brute it below. ugh.
200 0 : editTxn->QueryInterface(NS_GET_IID(nsIAbsorbingTransaction), getter_AddRefs(plcTxn));
201 0 : if (plcTxn)
202 : {
203 0 : nsCOMPtr<nsIAtom> atom;
204 0 : plcTxn->GetTxnName(getter_AddRefs(atom));
205 0 : if (atom && (atom == mName))
206 : {
207 : // check if start selection of next placeholder matches
208 : // end selection of this placeholder
209 : bool isSame;
210 0 : plcTxn->StartSelectionEquals(&mEndSel, &isSame);
211 0 : if (isSame)
212 : {
213 0 : mAbsorb = true; // we need to start absorbing again
214 0 : plcTxn->ForwardEndBatchTo(this);
215 : // AppendChild(editTxn);
216 : // see bug 171243: we don't need to merge placeholders
217 : // into placeholders. We just reactivate merging in the pre-existing
218 : // placeholder and drop the new one on the floor. The EndPlaceHolderBatch()
219 : // call on the new placeholder will be forwarded to this older one.
220 0 : RememberEndingSelection();
221 0 : *aDidMerge = true;
222 : }
223 : }
224 : }
225 : }
226 : }
227 0 : return NS_OK;
228 : }
229 :
230 0 : NS_IMETHODIMP PlaceholderTxn::GetTxnDescription(nsAString& aString)
231 : {
232 0 : aString.AssignLiteral("PlaceholderTxn: ");
233 :
234 0 : if (mName)
235 : {
236 0 : nsAutoString name;
237 0 : mName->ToString(name);
238 0 : aString += name;
239 : }
240 :
241 0 : return NS_OK;
242 : }
243 :
244 0 : NS_IMETHODIMP PlaceholderTxn::GetTxnName(nsIAtom **aName)
245 : {
246 0 : return GetName(aName);
247 : }
248 :
249 0 : NS_IMETHODIMP PlaceholderTxn::StartSelectionEquals(nsSelectionState *aSelState, bool *aResult)
250 : {
251 : // determine if starting selection matches the given selection state.
252 : // note that we only care about collapsed selections.
253 0 : NS_ENSURE_TRUE(aResult && aSelState, NS_ERROR_NULL_POINTER);
254 0 : if (!mStartSel->IsCollapsed() || !aSelState->IsCollapsed())
255 : {
256 0 : *aResult = false;
257 0 : return NS_OK;
258 : }
259 0 : *aResult = mStartSel->IsEqual(aSelState);
260 0 : return NS_OK;
261 : }
262 :
263 0 : NS_IMETHODIMP PlaceholderTxn::EndPlaceHolderBatch()
264 : {
265 0 : mAbsorb = false;
266 :
267 0 : if (mForwarding)
268 : {
269 0 : nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryReferent(mForwarding);
270 0 : if (plcTxn) plcTxn->EndPlaceHolderBatch();
271 : }
272 :
273 : // remember our selection state.
274 0 : return RememberEndingSelection();
275 : }
276 :
277 0 : NS_IMETHODIMP PlaceholderTxn::ForwardEndBatchTo(nsIAbsorbingTransaction *aForwardingAddress)
278 : {
279 0 : mForwarding = do_GetWeakReference(aForwardingAddress);
280 0 : return NS_OK;
281 : }
282 :
283 0 : NS_IMETHODIMP PlaceholderTxn::Commit()
284 : {
285 0 : mCommitted = true;
286 0 : return NS_OK;
287 : }
288 :
289 0 : NS_IMETHODIMP PlaceholderTxn::RememberEndingSelection()
290 : {
291 0 : nsCOMPtr<nsISelection> selection;
292 0 : nsresult res = mEditor->GetSelection(getter_AddRefs(selection));
293 0 : NS_ENSURE_SUCCESS(res, res);
294 0 : NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
295 0 : return mEndSel.SaveSelection(selection);
296 4392 : }
297 :
|