Bumping manifests a=b2g-bump
[gecko.git] / editor / composer / nsComposerCommandsUpdater.cpp
blob5edb1b7af0325f8439bf699922b5c198e6593b3f
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/mozalloc.h" // for operator new
8 #include "nsAString.h"
9 #include "nsComponentManagerUtils.h" // for do_CreateInstance
10 #include "nsComposerCommandsUpdater.h"
11 #include "nsDebug.h" // for NS_ENSURE_TRUE, etc
12 #include "nsError.h" // for NS_OK, NS_ERROR_FAILURE, etc
13 #include "nsICommandManager.h" // for nsICommandManager
14 #include "nsID.h" // for NS_GET_IID, etc
15 #include "nsIDOMWindow.h" // for nsIDOMWindow
16 #include "nsIDocShell.h" // for nsIDocShell
17 #include "nsIInterfaceRequestorUtils.h" // for do_GetInterface
18 #include "nsISelection.h" // for nsISelection
19 #include "nsITransactionManager.h" // for nsITransactionManager
20 #include "nsLiteralString.h" // for NS_LITERAL_STRING
21 #include "nsPICommandUpdater.h" // for nsPICommandUpdater
22 #include "nsPIDOMWindow.h" // for nsPIDOMWindow
24 class nsIDOMDocument;
25 class nsITransaction;
27 nsComposerCommandsUpdater::nsComposerCommandsUpdater()
28 : mDirtyState(eStateUninitialized)
29 , mSelectionCollapsed(eStateUninitialized)
30 , mFirstDoOfFirstUndo(true)
34 nsComposerCommandsUpdater::~nsComposerCommandsUpdater()
36 // cancel any outstanding update timer
37 if (mUpdateTimer)
39 mUpdateTimer->Cancel();
43 NS_IMPL_ISUPPORTS(nsComposerCommandsUpdater, nsISelectionListener,
44 nsIDocumentStateListener, nsITransactionListener, nsITimerCallback)
46 #if 0
47 #pragma mark -
48 #endif
50 NS_IMETHODIMP
51 nsComposerCommandsUpdater::NotifyDocumentCreated()
53 // Trigger an nsIObserve notification that the document has been created
54 UpdateOneCommand("obs_documentCreated");
55 return NS_OK;
58 NS_IMETHODIMP
59 nsComposerCommandsUpdater::NotifyDocumentWillBeDestroyed()
61 // cancel any outstanding update timer
62 if (mUpdateTimer)
64 mUpdateTimer->Cancel();
65 mUpdateTimer = nullptr;
68 // We can't call this right now; it is too late in some cases and the window
69 // is already partially destructed (e.g. JS objects may be gone).
70 #if 0
71 // Trigger an nsIObserve notification that the document will be destroyed
72 UpdateOneCommand("obs_documentWillBeDestroyed");
73 #endif
74 return NS_OK;
78 NS_IMETHODIMP
79 nsComposerCommandsUpdater::NotifyDocumentStateChanged(bool aNowDirty)
81 // update document modified. We should have some other notifications for this too.
82 return UpdateDirtyState(aNowDirty);
85 NS_IMETHODIMP
86 nsComposerCommandsUpdater::NotifySelectionChanged(nsIDOMDocument *,
87 nsISelection *, int16_t)
89 return PrimeUpdateTimer();
92 #if 0
93 #pragma mark -
94 #endif
96 NS_IMETHODIMP
97 nsComposerCommandsUpdater::WillDo(nsITransactionManager *aManager,
98 nsITransaction *aTransaction, bool *aInterrupt)
100 *aInterrupt = false;
101 return NS_OK;
104 NS_IMETHODIMP
105 nsComposerCommandsUpdater::DidDo(nsITransactionManager *aManager,
106 nsITransaction *aTransaction, nsresult aDoResult)
108 // only need to update if the status of the Undo menu item changes.
109 int32_t undoCount;
110 aManager->GetNumberOfUndoItems(&undoCount);
111 if (undoCount == 1)
113 if (mFirstDoOfFirstUndo)
114 UpdateCommandGroup(NS_LITERAL_STRING("undo"));
115 mFirstDoOfFirstUndo = false;
118 return NS_OK;
121 NS_IMETHODIMP
122 nsComposerCommandsUpdater::WillUndo(nsITransactionManager *aManager,
123 nsITransaction *aTransaction,
124 bool *aInterrupt)
126 *aInterrupt = false;
127 return NS_OK;
130 NS_IMETHODIMP
131 nsComposerCommandsUpdater::DidUndo(nsITransactionManager *aManager,
132 nsITransaction *aTransaction,
133 nsresult aUndoResult)
135 int32_t undoCount;
136 aManager->GetNumberOfUndoItems(&undoCount);
137 if (undoCount == 0)
138 mFirstDoOfFirstUndo = true; // reset the state for the next do
140 UpdateCommandGroup(NS_LITERAL_STRING("undo"));
141 return NS_OK;
144 NS_IMETHODIMP
145 nsComposerCommandsUpdater::WillRedo(nsITransactionManager *aManager,
146 nsITransaction *aTransaction,
147 bool *aInterrupt)
149 *aInterrupt = false;
150 return NS_OK;
153 NS_IMETHODIMP
154 nsComposerCommandsUpdater::DidRedo(nsITransactionManager *aManager,
155 nsITransaction *aTransaction,
156 nsresult aRedoResult)
158 UpdateCommandGroup(NS_LITERAL_STRING("undo"));
159 return NS_OK;
162 NS_IMETHODIMP
163 nsComposerCommandsUpdater::WillBeginBatch(nsITransactionManager *aManager,
164 bool *aInterrupt)
166 *aInterrupt = false;
167 return NS_OK;
170 NS_IMETHODIMP
171 nsComposerCommandsUpdater::DidBeginBatch(nsITransactionManager *aManager,
172 nsresult aResult)
174 return NS_OK;
177 NS_IMETHODIMP
178 nsComposerCommandsUpdater::WillEndBatch(nsITransactionManager *aManager,
179 bool *aInterrupt)
181 *aInterrupt = false;
182 return NS_OK;
185 NS_IMETHODIMP
186 nsComposerCommandsUpdater::DidEndBatch(nsITransactionManager *aManager,
187 nsresult aResult)
189 return NS_OK;
192 NS_IMETHODIMP
193 nsComposerCommandsUpdater::WillMerge(nsITransactionManager *aManager,
194 nsITransaction *aTopTransaction,
195 nsITransaction *aTransactionToMerge,
196 bool *aInterrupt)
198 *aInterrupt = false;
199 return NS_OK;
202 NS_IMETHODIMP
203 nsComposerCommandsUpdater::DidMerge(nsITransactionManager *aManager,
204 nsITransaction *aTopTransaction,
205 nsITransaction *aTransactionToMerge,
206 bool aDidMerge, nsresult aMergeResult)
208 return NS_OK;
211 #if 0
212 #pragma mark -
213 #endif
215 nsresult
216 nsComposerCommandsUpdater::Init(nsIDOMWindow* aDOMWindow)
218 NS_ENSURE_ARG(aDOMWindow);
219 mDOMWindow = do_GetWeakReference(aDOMWindow);
221 nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aDOMWindow));
222 if (window)
224 mDocShell = do_GetWeakReference(window->GetDocShell());
226 return NS_OK;
229 nsresult
230 nsComposerCommandsUpdater::PrimeUpdateTimer()
232 if (!mUpdateTimer)
234 nsresult rv = NS_OK;
235 mUpdateTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
236 NS_ENSURE_SUCCESS(rv, rv);
239 const uint32_t kUpdateTimerDelay = 150;
240 return mUpdateTimer->InitWithCallback(static_cast<nsITimerCallback*>(this),
241 kUpdateTimerDelay,
242 nsITimer::TYPE_ONE_SHOT);
246 void nsComposerCommandsUpdater::TimerCallback()
248 // if the selection state has changed, update stuff
249 bool isCollapsed = SelectionIsCollapsed();
250 if (static_cast<int8_t>(isCollapsed) != mSelectionCollapsed)
252 UpdateCommandGroup(NS_LITERAL_STRING("select"));
253 mSelectionCollapsed = isCollapsed;
256 // isn't this redundant with the UpdateCommandGroup above?
257 // can we just nuke the above call? or create a meta command group?
258 UpdateCommandGroup(NS_LITERAL_STRING("style"));
261 nsresult
262 nsComposerCommandsUpdater::UpdateDirtyState(bool aNowDirty)
264 if (mDirtyState != static_cast<int8_t>(aNowDirty))
266 UpdateCommandGroup(NS_LITERAL_STRING("save"));
267 UpdateCommandGroup(NS_LITERAL_STRING("undo"));
268 mDirtyState = aNowDirty;
271 return NS_OK;
274 nsresult
275 nsComposerCommandsUpdater::UpdateCommandGroup(const nsAString& aCommandGroup)
277 nsCOMPtr<nsPICommandUpdater> commandUpdater = GetCommandUpdater();
278 NS_ENSURE_TRUE(commandUpdater, NS_ERROR_FAILURE);
281 // This hardcoded list of commands is temporary.
282 // This code should use nsIControllerCommandGroup.
283 if (aCommandGroup.EqualsLiteral("undo"))
285 commandUpdater->CommandStatusChanged("cmd_undo");
286 commandUpdater->CommandStatusChanged("cmd_redo");
288 else if (aCommandGroup.EqualsLiteral("select") ||
289 aCommandGroup.EqualsLiteral("style"))
291 commandUpdater->CommandStatusChanged("cmd_bold");
292 commandUpdater->CommandStatusChanged("cmd_italic");
293 commandUpdater->CommandStatusChanged("cmd_underline");
294 commandUpdater->CommandStatusChanged("cmd_tt");
296 commandUpdater->CommandStatusChanged("cmd_strikethrough");
297 commandUpdater->CommandStatusChanged("cmd_superscript");
298 commandUpdater->CommandStatusChanged("cmd_subscript");
299 commandUpdater->CommandStatusChanged("cmd_nobreak");
301 commandUpdater->CommandStatusChanged("cmd_em");
302 commandUpdater->CommandStatusChanged("cmd_strong");
303 commandUpdater->CommandStatusChanged("cmd_cite");
304 commandUpdater->CommandStatusChanged("cmd_abbr");
305 commandUpdater->CommandStatusChanged("cmd_acronym");
306 commandUpdater->CommandStatusChanged("cmd_code");
307 commandUpdater->CommandStatusChanged("cmd_samp");
308 commandUpdater->CommandStatusChanged("cmd_var");
310 commandUpdater->CommandStatusChanged("cmd_increaseFont");
311 commandUpdater->CommandStatusChanged("cmd_decreaseFont");
313 commandUpdater->CommandStatusChanged("cmd_paragraphState");
314 commandUpdater->CommandStatusChanged("cmd_fontFace");
315 commandUpdater->CommandStatusChanged("cmd_fontColor");
316 commandUpdater->CommandStatusChanged("cmd_backgroundColor");
317 commandUpdater->CommandStatusChanged("cmd_highlight");
319 else if (aCommandGroup.EqualsLiteral("save"))
321 // save commands (most are not in C++)
322 commandUpdater->CommandStatusChanged("cmd_setDocumentModified");
323 commandUpdater->CommandStatusChanged("cmd_save");
325 return NS_OK;
328 nsresult
329 nsComposerCommandsUpdater::UpdateOneCommand(const char *aCommand)
331 nsCOMPtr<nsPICommandUpdater> commandUpdater = GetCommandUpdater();
332 NS_ENSURE_TRUE(commandUpdater, NS_ERROR_FAILURE);
334 commandUpdater->CommandStatusChanged(aCommand);
336 return NS_OK;
339 bool
340 nsComposerCommandsUpdater::SelectionIsCollapsed()
342 nsCOMPtr<nsIDOMWindow> domWindow = do_QueryReferent(mDOMWindow);
343 NS_ENSURE_TRUE(domWindow, true);
345 nsCOMPtr<nsISelection> domSelection;
346 if (NS_SUCCEEDED(domWindow->GetSelection(getter_AddRefs(domSelection))) && domSelection)
348 bool selectionCollapsed = false;
349 domSelection->GetIsCollapsed(&selectionCollapsed);
350 return selectionCollapsed;
353 NS_WARNING("nsComposerCommandsUpdater::SelectionIsCollapsed - no domSelection");
355 return false;
358 already_AddRefed<nsPICommandUpdater>
359 nsComposerCommandsUpdater::GetCommandUpdater()
361 nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
362 NS_ENSURE_TRUE(docShell, nullptr);
363 nsCOMPtr<nsICommandManager> manager = do_GetInterface(docShell);
364 nsCOMPtr<nsPICommandUpdater> updater = do_QueryInterface(manager);
365 return updater.forget();
368 #if 0
369 #pragma mark -
370 #endif
372 nsresult
373 nsComposerCommandsUpdater::Notify(nsITimer *timer)
375 NS_ASSERTION(timer == mUpdateTimer.get(), "Hey, this ain't my timer!");
376 TimerCallback();
377 return NS_OK;
380 #if 0
381 #pragma mark -
382 #endif
385 nsresult
386 NS_NewComposerCommandsUpdater(nsISelectionListener** aInstancePtrResult)
388 nsComposerCommandsUpdater* newThang = new nsComposerCommandsUpdater;
389 NS_ENSURE_TRUE(newThang, NS_ERROR_OUT_OF_MEMORY);
391 return newThang->QueryInterface(NS_GET_IID(nsISelectionListener),
392 (void **)aInstancePtrResult);