Bug 1247796. Use keyboardFocusIndicatorColor for ActiveBorder system color keyword...
[gecko.git] / editor / libeditor / PlaceholderTxn.cpp
blob3250e5b568a497a53f36dd472de299c966300394
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 "PlaceholderTxn.h"
7 #include "nsEditor.h"
8 #include "IMETextTxn.h"
9 #include "nsGkAtoms.h"
10 #include "mozilla/dom/Selection.h"
11 #include "nsQueryObject.h"
13 using namespace mozilla;
14 using namespace mozilla::dom;
16 PlaceholderTxn::PlaceholderTxn() : EditAggregateTxn(),
17 mAbsorb(true),
18 mForwarding(nullptr),
19 mIMETextTxn(nullptr),
20 mCommitted(false),
21 mStartSel(nullptr),
22 mEndSel(),
23 mEditor(nullptr)
27 PlaceholderTxn::~PlaceholderTxn()
31 NS_IMPL_CYCLE_COLLECTION_CLASS(PlaceholderTxn)
33 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PlaceholderTxn,
34 EditAggregateTxn)
35 tmp->mStartSel->DoUnlink();
36 tmp->mEndSel.DoUnlink();
37 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PlaceholderTxn,
40 EditAggregateTxn)
41 tmp->mStartSel->DoTraverse(cb);
42 tmp->mEndSel.DoTraverse(cb);
43 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
45 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PlaceholderTxn)
46 NS_INTERFACE_MAP_ENTRY(nsIAbsorbingTransaction)
47 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
48 NS_INTERFACE_MAP_END_INHERITING(EditAggregateTxn)
50 NS_IMPL_ADDREF_INHERITED(PlaceholderTxn, EditAggregateTxn)
51 NS_IMPL_RELEASE_INHERITED(PlaceholderTxn, EditAggregateTxn)
53 NS_IMETHODIMP
54 PlaceholderTxn::Init(nsIAtom* aName, nsSelectionState* aSelState,
55 nsEditor* aEditor)
57 NS_ENSURE_TRUE(aEditor && aSelState, NS_ERROR_NULL_POINTER);
59 mName = aName;
60 mStartSel = aSelState;
61 mEditor = aEditor;
62 return NS_OK;
65 NS_IMETHODIMP PlaceholderTxn::DoTransaction(void)
67 return NS_OK;
70 NS_IMETHODIMP PlaceholderTxn::UndoTransaction(void)
72 // undo txns
73 nsresult res = EditAggregateTxn::UndoTransaction();
74 NS_ENSURE_SUCCESS(res, res);
76 NS_ENSURE_TRUE(mStartSel, NS_ERROR_NULL_POINTER);
78 // now restore selection
79 RefPtr<Selection> selection = mEditor->GetSelection();
80 NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
81 return mStartSel->RestoreSelection(selection);
85 NS_IMETHODIMP PlaceholderTxn::RedoTransaction(void)
87 // redo txns
88 nsresult res = EditAggregateTxn::RedoTransaction();
89 NS_ENSURE_SUCCESS(res, res);
91 // now restore selection
92 RefPtr<Selection> selection = mEditor->GetSelection();
93 NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
94 return mEndSel.RestoreSelection(selection);
98 NS_IMETHODIMP PlaceholderTxn::Merge(nsITransaction *aTransaction, bool *aDidMerge)
100 NS_ENSURE_TRUE(aDidMerge && aTransaction, NS_ERROR_NULL_POINTER);
102 // set out param default value
103 *aDidMerge=false;
105 if (mForwarding)
107 NS_NOTREACHED("tried to merge into a placeholder that was in forwarding mode!");
108 return NS_ERROR_FAILURE;
111 // check to see if aTransaction is one of the editor's
112 // private transactions. If not, we want to avoid merging
113 // the foreign transaction into our placeholder since we
114 // don't know what it does.
116 nsCOMPtr<nsPIEditorTransaction> pTxn = do_QueryInterface(aTransaction);
117 NS_ENSURE_TRUE(pTxn, NS_OK); // it's foreign so just bail!
119 EditTxn *editTxn = (EditTxn*)aTransaction; //XXX: hack, not safe! need nsIEditTransaction!
120 // determine if this incoming txn is a placeholder txn
121 nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryObject(editTxn);
123 // we are absorbing all txn's if mAbsorb is lit.
124 if (mAbsorb)
126 RefPtr<IMETextTxn> otherTxn = do_QueryObject(aTransaction);
127 if (otherTxn) {
128 // special handling for IMETextTxn's: they need to merge with any previous
129 // IMETextTxn in this placeholder, if possible.
130 if (!mIMETextTxn)
132 // this is the first IME txn in the placeholder
133 mIMETextTxn =otherTxn;
134 AppendChild(editTxn);
136 else
138 bool didMerge;
139 mIMETextTxn->Merge(otherTxn, &didMerge);
140 if (!didMerge)
142 // it wouldn't merge. Earlier IME txn is already committed and will
143 // not absorb further IME txns. So just stack this one after it
144 // and remember it as a candidate for further merges.
145 mIMETextTxn =otherTxn;
146 AppendChild(editTxn);
150 else if (!plcTxn) // see bug 171243: just drop incoming placeholders on the floor.
151 { // their children will be swallowed by this preexisting one.
152 AppendChild(editTxn);
154 *aDidMerge = true;
155 // RememberEndingSelection();
156 // efficiency hack: no need to remember selection here, as we haven't yet
157 // finished the initial batch and we know we will be told when the batch ends.
158 // we can remeber the selection then.
160 else
161 { // merge typing or IME or deletion transactions if the selection matches
162 if (((mName.get() == nsGkAtoms::TypingTxnName) ||
163 (mName.get() == nsGkAtoms::IMETxnName) ||
164 (mName.get() == nsGkAtoms::DeleteTxnName))
165 && !mCommitted )
167 nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryObject(editTxn);
168 if (plcTxn) {
169 nsCOMPtr<nsIAtom> atom;
170 plcTxn->GetTxnName(getter_AddRefs(atom));
171 if (atom && (atom == mName))
173 // check if start selection of next placeholder matches
174 // end selection of this placeholder
175 bool isSame;
176 plcTxn->StartSelectionEquals(&mEndSel, &isSame);
177 if (isSame)
179 mAbsorb = true; // we need to start absorbing again
180 plcTxn->ForwardEndBatchTo(this);
181 // AppendChild(editTxn);
182 // see bug 171243: we don't need to merge placeholders
183 // into placeholders. We just reactivate merging in the pre-existing
184 // placeholder and drop the new one on the floor. The EndPlaceHolderBatch()
185 // call on the new placeholder will be forwarded to this older one.
186 RememberEndingSelection();
187 *aDidMerge = true;
193 return NS_OK;
196 NS_IMETHODIMP PlaceholderTxn::GetTxnDescription(nsAString& aString)
198 aString.AssignLiteral("PlaceholderTxn: ");
200 if (mName)
202 nsAutoString name;
203 mName->ToString(name);
204 aString += name;
207 return NS_OK;
210 NS_IMETHODIMP PlaceholderTxn::GetTxnName(nsIAtom **aName)
212 return GetName(aName);
215 NS_IMETHODIMP PlaceholderTxn::StartSelectionEquals(nsSelectionState *aSelState, bool *aResult)
217 // determine if starting selection matches the given selection state.
218 // note that we only care about collapsed selections.
219 NS_ENSURE_TRUE(aResult && aSelState, NS_ERROR_NULL_POINTER);
220 if (!mStartSel->IsCollapsed() || !aSelState->IsCollapsed())
222 *aResult = false;
223 return NS_OK;
225 *aResult = mStartSel->IsEqual(aSelState);
226 return NS_OK;
229 NS_IMETHODIMP PlaceholderTxn::EndPlaceHolderBatch()
231 mAbsorb = false;
233 if (mForwarding)
235 nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryReferent(mForwarding);
236 if (plcTxn) plcTxn->EndPlaceHolderBatch();
239 // remember our selection state.
240 return RememberEndingSelection();
243 NS_IMETHODIMP PlaceholderTxn::ForwardEndBatchTo(nsIAbsorbingTransaction *aForwardingAddress)
245 mForwarding = do_GetWeakReference(aForwardingAddress);
246 return NS_OK;
249 NS_IMETHODIMP PlaceholderTxn::Commit()
251 mCommitted = true;
252 return NS_OK;
255 nsresult PlaceholderTxn::RememberEndingSelection()
257 RefPtr<Selection> selection = mEditor->GetSelection();
258 NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
259 mEndSel.SaveSelection(selection);
260 return NS_OK;