summaryrefslogtreecommitdiffstats
path: root/editor/composer/nsComposerCommandsUpdater.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/composer/nsComposerCommandsUpdater.cpp')
-rw-r--r--editor/composer/nsComposerCommandsUpdater.cpp381
1 files changed, 381 insertions, 0 deletions
diff --git a/editor/composer/nsComposerCommandsUpdater.cpp b/editor/composer/nsComposerCommandsUpdater.cpp
new file mode 100644
index 000000000..4999f7b92
--- /dev/null
+++ b/editor/composer/nsComposerCommandsUpdater.cpp
@@ -0,0 +1,381 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/mozalloc.h" // for operator new
+#include "nsAString.h"
+#include "nsComponentManagerUtils.h" // for do_CreateInstance
+#include "nsComposerCommandsUpdater.h"
+#include "nsDebug.h" // for NS_ENSURE_TRUE, etc
+#include "nsError.h" // for NS_OK, NS_ERROR_FAILURE, etc
+#include "nsICommandManager.h" // for nsICommandManager
+#include "nsID.h" // for NS_GET_IID, etc
+#include "nsIDOMWindow.h" // for nsIDOMWindow
+#include "nsIDocShell.h" // for nsIDocShell
+#include "nsIInterfaceRequestorUtils.h" // for do_GetInterface
+#include "nsISelection.h" // for nsISelection
+#include "nsITransactionManager.h" // for nsITransactionManager
+#include "nsLiteralString.h" // for NS_LITERAL_STRING
+#include "nsPICommandUpdater.h" // for nsPICommandUpdater
+#include "nsPIDOMWindow.h" // for nsPIDOMWindow
+
+class nsIDOMDocument;
+class nsITransaction;
+
+nsComposerCommandsUpdater::nsComposerCommandsUpdater()
+: mDirtyState(eStateUninitialized)
+, mSelectionCollapsed(eStateUninitialized)
+, mFirstDoOfFirstUndo(true)
+{
+}
+
+nsComposerCommandsUpdater::~nsComposerCommandsUpdater()
+{
+ // cancel any outstanding update timer
+ if (mUpdateTimer) {
+ mUpdateTimer->Cancel();
+ }
+}
+
+NS_IMPL_ISUPPORTS(nsComposerCommandsUpdater, nsISelectionListener,
+ nsIDocumentStateListener, nsITransactionListener, nsITimerCallback)
+
+#if 0
+#pragma mark -
+#endif
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::NotifyDocumentCreated()
+{
+ // Trigger an nsIObserve notification that the document has been created
+ UpdateOneCommand("obs_documentCreated");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::NotifyDocumentWillBeDestroyed()
+{
+ // cancel any outstanding update timer
+ if (mUpdateTimer) {
+ mUpdateTimer->Cancel();
+ mUpdateTimer = nullptr;
+ }
+
+ // We can't call this right now; it is too late in some cases and the window
+ // is already partially destructed (e.g. JS objects may be gone).
+#if 0
+ // Trigger an nsIObserve notification that the document will be destroyed
+ UpdateOneCommand("obs_documentWillBeDestroyed");
+#endif
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::NotifyDocumentStateChanged(bool aNowDirty)
+{
+ // update document modified. We should have some other notifications for this too.
+ return UpdateDirtyState(aNowDirty);
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::NotifySelectionChanged(nsIDOMDocument *,
+ nsISelection *, int16_t)
+{
+ return PrimeUpdateTimer();
+}
+
+#if 0
+#pragma mark -
+#endif
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::WillDo(nsITransactionManager *aManager,
+ nsITransaction *aTransaction, bool *aInterrupt)
+{
+ *aInterrupt = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::DidDo(nsITransactionManager *aManager,
+ nsITransaction *aTransaction, nsresult aDoResult)
+{
+ // only need to update if the status of the Undo menu item changes.
+ int32_t undoCount;
+ aManager->GetNumberOfUndoItems(&undoCount);
+ if (undoCount == 1) {
+ if (mFirstDoOfFirstUndo) {
+ UpdateCommandGroup(NS_LITERAL_STRING("undo"));
+ }
+ mFirstDoOfFirstUndo = false;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::WillUndo(nsITransactionManager *aManager,
+ nsITransaction *aTransaction,
+ bool *aInterrupt)
+{
+ *aInterrupt = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::DidUndo(nsITransactionManager *aManager,
+ nsITransaction *aTransaction,
+ nsresult aUndoResult)
+{
+ int32_t undoCount;
+ aManager->GetNumberOfUndoItems(&undoCount);
+ if (undoCount == 0)
+ mFirstDoOfFirstUndo = true; // reset the state for the next do
+
+ UpdateCommandGroup(NS_LITERAL_STRING("undo"));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::WillRedo(nsITransactionManager *aManager,
+ nsITransaction *aTransaction,
+ bool *aInterrupt)
+{
+ *aInterrupt = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::DidRedo(nsITransactionManager *aManager,
+ nsITransaction *aTransaction,
+ nsresult aRedoResult)
+{
+ UpdateCommandGroup(NS_LITERAL_STRING("undo"));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::WillBeginBatch(nsITransactionManager *aManager,
+ bool *aInterrupt)
+{
+ *aInterrupt = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::DidBeginBatch(nsITransactionManager *aManager,
+ nsresult aResult)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::WillEndBatch(nsITransactionManager *aManager,
+ bool *aInterrupt)
+{
+ *aInterrupt = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::DidEndBatch(nsITransactionManager *aManager,
+ nsresult aResult)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::WillMerge(nsITransactionManager *aManager,
+ nsITransaction *aTopTransaction,
+ nsITransaction *aTransactionToMerge,
+ bool *aInterrupt)
+{
+ *aInterrupt = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsComposerCommandsUpdater::DidMerge(nsITransactionManager *aManager,
+ nsITransaction *aTopTransaction,
+ nsITransaction *aTransactionToMerge,
+ bool aDidMerge, nsresult aMergeResult)
+{
+ return NS_OK;
+}
+
+#if 0
+#pragma mark -
+#endif
+
+nsresult
+nsComposerCommandsUpdater::Init(nsPIDOMWindowOuter* aDOMWindow)
+{
+ NS_ENSURE_ARG(aDOMWindow);
+ mDOMWindow = do_GetWeakReference(aDOMWindow);
+ mDocShell = do_GetWeakReference(aDOMWindow->GetDocShell());
+ return NS_OK;
+}
+
+nsresult
+nsComposerCommandsUpdater::PrimeUpdateTimer()
+{
+ if (!mUpdateTimer) {
+ nsresult rv = NS_OK;
+ mUpdateTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ const uint32_t kUpdateTimerDelay = 150;
+ return mUpdateTimer->InitWithCallback(static_cast<nsITimerCallback*>(this),
+ kUpdateTimerDelay,
+ nsITimer::TYPE_ONE_SHOT);
+}
+
+
+void nsComposerCommandsUpdater::TimerCallback()
+{
+ // if the selection state has changed, update stuff
+ bool isCollapsed = SelectionIsCollapsed();
+ if (static_cast<int8_t>(isCollapsed) != mSelectionCollapsed) {
+ UpdateCommandGroup(NS_LITERAL_STRING("select"));
+ mSelectionCollapsed = isCollapsed;
+ }
+
+ // isn't this redundant with the UpdateCommandGroup above?
+ // can we just nuke the above call? or create a meta command group?
+ UpdateCommandGroup(NS_LITERAL_STRING("style"));
+}
+
+nsresult
+nsComposerCommandsUpdater::UpdateDirtyState(bool aNowDirty)
+{
+ if (mDirtyState != static_cast<int8_t>(aNowDirty)) {
+ UpdateCommandGroup(NS_LITERAL_STRING("save"));
+ UpdateCommandGroup(NS_LITERAL_STRING("undo"));
+ mDirtyState = aNowDirty;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsComposerCommandsUpdater::UpdateCommandGroup(const nsAString& aCommandGroup)
+{
+ nsCOMPtr<nsPICommandUpdater> commandUpdater = GetCommandUpdater();
+ NS_ENSURE_TRUE(commandUpdater, NS_ERROR_FAILURE);
+
+
+ // This hardcoded list of commands is temporary.
+ // This code should use nsIControllerCommandGroup.
+ if (aCommandGroup.EqualsLiteral("undo")) {
+ commandUpdater->CommandStatusChanged("cmd_undo");
+ commandUpdater->CommandStatusChanged("cmd_redo");
+ return NS_OK;
+ }
+
+ if (aCommandGroup.EqualsLiteral("select") ||
+ aCommandGroup.EqualsLiteral("style")) {
+ commandUpdater->CommandStatusChanged("cmd_bold");
+ commandUpdater->CommandStatusChanged("cmd_italic");
+ commandUpdater->CommandStatusChanged("cmd_underline");
+ commandUpdater->CommandStatusChanged("cmd_tt");
+
+ commandUpdater->CommandStatusChanged("cmd_strikethrough");
+ commandUpdater->CommandStatusChanged("cmd_superscript");
+ commandUpdater->CommandStatusChanged("cmd_subscript");
+ commandUpdater->CommandStatusChanged("cmd_nobreak");
+
+ commandUpdater->CommandStatusChanged("cmd_em");
+ commandUpdater->CommandStatusChanged("cmd_strong");
+ commandUpdater->CommandStatusChanged("cmd_cite");
+ commandUpdater->CommandStatusChanged("cmd_abbr");
+ commandUpdater->CommandStatusChanged("cmd_acronym");
+ commandUpdater->CommandStatusChanged("cmd_code");
+ commandUpdater->CommandStatusChanged("cmd_samp");
+ commandUpdater->CommandStatusChanged("cmd_var");
+
+ commandUpdater->CommandStatusChanged("cmd_increaseFont");
+ commandUpdater->CommandStatusChanged("cmd_decreaseFont");
+
+ commandUpdater->CommandStatusChanged("cmd_paragraphState");
+ commandUpdater->CommandStatusChanged("cmd_fontFace");
+ commandUpdater->CommandStatusChanged("cmd_fontColor");
+ commandUpdater->CommandStatusChanged("cmd_backgroundColor");
+ commandUpdater->CommandStatusChanged("cmd_highlight");
+ return NS_OK;
+ }
+
+ if (aCommandGroup.EqualsLiteral("save")) {
+ // save commands (most are not in C++)
+ commandUpdater->CommandStatusChanged("cmd_setDocumentModified");
+ commandUpdater->CommandStatusChanged("cmd_save");
+ return NS_OK;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsComposerCommandsUpdater::UpdateOneCommand(const char *aCommand)
+{
+ nsCOMPtr<nsPICommandUpdater> commandUpdater = GetCommandUpdater();
+ NS_ENSURE_TRUE(commandUpdater, NS_ERROR_FAILURE);
+
+ commandUpdater->CommandStatusChanged(aCommand);
+
+ return NS_OK;
+}
+
+bool
+nsComposerCommandsUpdater::SelectionIsCollapsed()
+{
+ nsCOMPtr<nsPIDOMWindowOuter> domWindow = do_QueryReferent(mDOMWindow);
+ NS_ENSURE_TRUE(domWindow, true);
+
+ nsCOMPtr<nsISelection> domSelection = domWindow->GetSelection();
+ if (NS_WARN_IF(!domSelection)) {
+ return false;
+ }
+
+ bool selectionCollapsed = false;
+ domSelection->GetIsCollapsed(&selectionCollapsed);
+ return selectionCollapsed;
+}
+
+already_AddRefed<nsPICommandUpdater>
+nsComposerCommandsUpdater::GetCommandUpdater()
+{
+ nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
+ NS_ENSURE_TRUE(docShell, nullptr);
+ nsCOMPtr<nsICommandManager> manager = docShell->GetCommandManager();
+ nsCOMPtr<nsPICommandUpdater> updater = do_QueryInterface(manager);
+ return updater.forget();
+}
+
+#if 0
+#pragma mark -
+#endif
+
+nsresult
+nsComposerCommandsUpdater::Notify(nsITimer *timer)
+{
+ NS_ASSERTION(timer == mUpdateTimer.get(), "Hey, this ain't my timer!");
+ TimerCallback();
+ return NS_OK;
+}
+
+#if 0
+#pragma mark -
+#endif
+
+
+nsresult
+NS_NewComposerCommandsUpdater(nsISelectionListener** aInstancePtrResult)
+{
+ RefPtr<nsComposerCommandsUpdater> newThang = new nsComposerCommandsUpdater;
+ newThang.forget(aInstancePtrResult);
+ return NS_OK;
+}