editor/composer/src/nsComposerCommandsUpdater.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 *
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "mozilla/mozalloc.h" // for operator new
michael@0 8 #include "nsAString.h"
michael@0 9 #include "nsComponentManagerUtils.h" // for do_CreateInstance
michael@0 10 #include "nsComposerCommandsUpdater.h"
michael@0 11 #include "nsDebug.h" // for NS_ENSURE_TRUE, etc
michael@0 12 #include "nsError.h" // for NS_OK, NS_ERROR_FAILURE, etc
michael@0 13 #include "nsICommandManager.h" // for nsICommandManager
michael@0 14 #include "nsID.h" // for NS_GET_IID, etc
michael@0 15 #include "nsIDOMWindow.h" // for nsIDOMWindow
michael@0 16 #include "nsIDocShell.h" // for nsIDocShell
michael@0 17 #include "nsIInterfaceRequestorUtils.h" // for do_GetInterface
michael@0 18 #include "nsISelection.h" // for nsISelection
michael@0 19 #include "nsITransactionManager.h" // for nsITransactionManager
michael@0 20 #include "nsLiteralString.h" // for NS_LITERAL_STRING
michael@0 21 #include "nsPICommandUpdater.h" // for nsPICommandUpdater
michael@0 22 #include "nsPIDOMWindow.h" // for nsPIDOMWindow
michael@0 23
michael@0 24 class nsIDOMDocument;
michael@0 25 class nsITransaction;
michael@0 26
michael@0 27 nsComposerCommandsUpdater::nsComposerCommandsUpdater()
michael@0 28 : mDirtyState(eStateUninitialized)
michael@0 29 , mSelectionCollapsed(eStateUninitialized)
michael@0 30 , mFirstDoOfFirstUndo(true)
michael@0 31 {
michael@0 32 }
michael@0 33
michael@0 34 nsComposerCommandsUpdater::~nsComposerCommandsUpdater()
michael@0 35 {
michael@0 36 // cancel any outstanding update timer
michael@0 37 if (mUpdateTimer)
michael@0 38 {
michael@0 39 mUpdateTimer->Cancel();
michael@0 40 }
michael@0 41 }
michael@0 42
michael@0 43 NS_IMPL_ISUPPORTS(nsComposerCommandsUpdater, nsISelectionListener,
michael@0 44 nsIDocumentStateListener, nsITransactionListener, nsITimerCallback)
michael@0 45
michael@0 46 #if 0
michael@0 47 #pragma mark -
michael@0 48 #endif
michael@0 49
michael@0 50 NS_IMETHODIMP
michael@0 51 nsComposerCommandsUpdater::NotifyDocumentCreated()
michael@0 52 {
michael@0 53 // Trigger an nsIObserve notification that the document has been created
michael@0 54 UpdateOneCommand("obs_documentCreated");
michael@0 55 return NS_OK;
michael@0 56 }
michael@0 57
michael@0 58 NS_IMETHODIMP
michael@0 59 nsComposerCommandsUpdater::NotifyDocumentWillBeDestroyed()
michael@0 60 {
michael@0 61 // cancel any outstanding update timer
michael@0 62 if (mUpdateTimer)
michael@0 63 {
michael@0 64 mUpdateTimer->Cancel();
michael@0 65 mUpdateTimer = nullptr;
michael@0 66 }
michael@0 67
michael@0 68 // We can't call this right now; it is too late in some cases and the window
michael@0 69 // is already partially destructed (e.g. JS objects may be gone).
michael@0 70 #if 0
michael@0 71 // Trigger an nsIObserve notification that the document will be destroyed
michael@0 72 UpdateOneCommand("obs_documentWillBeDestroyed");
michael@0 73 #endif
michael@0 74 return NS_OK;
michael@0 75 }
michael@0 76
michael@0 77
michael@0 78 NS_IMETHODIMP
michael@0 79 nsComposerCommandsUpdater::NotifyDocumentStateChanged(bool aNowDirty)
michael@0 80 {
michael@0 81 // update document modified. We should have some other notifications for this too.
michael@0 82 return UpdateDirtyState(aNowDirty);
michael@0 83 }
michael@0 84
michael@0 85 NS_IMETHODIMP
michael@0 86 nsComposerCommandsUpdater::NotifySelectionChanged(nsIDOMDocument *,
michael@0 87 nsISelection *, int16_t)
michael@0 88 {
michael@0 89 return PrimeUpdateTimer();
michael@0 90 }
michael@0 91
michael@0 92 #if 0
michael@0 93 #pragma mark -
michael@0 94 #endif
michael@0 95
michael@0 96 NS_IMETHODIMP
michael@0 97 nsComposerCommandsUpdater::WillDo(nsITransactionManager *aManager,
michael@0 98 nsITransaction *aTransaction, bool *aInterrupt)
michael@0 99 {
michael@0 100 *aInterrupt = false;
michael@0 101 return NS_OK;
michael@0 102 }
michael@0 103
michael@0 104 NS_IMETHODIMP
michael@0 105 nsComposerCommandsUpdater::DidDo(nsITransactionManager *aManager,
michael@0 106 nsITransaction *aTransaction, nsresult aDoResult)
michael@0 107 {
michael@0 108 // only need to update if the status of the Undo menu item changes.
michael@0 109 int32_t undoCount;
michael@0 110 aManager->GetNumberOfUndoItems(&undoCount);
michael@0 111 if (undoCount == 1)
michael@0 112 {
michael@0 113 if (mFirstDoOfFirstUndo)
michael@0 114 UpdateCommandGroup(NS_LITERAL_STRING("undo"));
michael@0 115 mFirstDoOfFirstUndo = false;
michael@0 116 }
michael@0 117
michael@0 118 return NS_OK;
michael@0 119 }
michael@0 120
michael@0 121 NS_IMETHODIMP
michael@0 122 nsComposerCommandsUpdater::WillUndo(nsITransactionManager *aManager,
michael@0 123 nsITransaction *aTransaction,
michael@0 124 bool *aInterrupt)
michael@0 125 {
michael@0 126 *aInterrupt = false;
michael@0 127 return NS_OK;
michael@0 128 }
michael@0 129
michael@0 130 NS_IMETHODIMP
michael@0 131 nsComposerCommandsUpdater::DidUndo(nsITransactionManager *aManager,
michael@0 132 nsITransaction *aTransaction,
michael@0 133 nsresult aUndoResult)
michael@0 134 {
michael@0 135 int32_t undoCount;
michael@0 136 aManager->GetNumberOfUndoItems(&undoCount);
michael@0 137 if (undoCount == 0)
michael@0 138 mFirstDoOfFirstUndo = true; // reset the state for the next do
michael@0 139
michael@0 140 UpdateCommandGroup(NS_LITERAL_STRING("undo"));
michael@0 141 return NS_OK;
michael@0 142 }
michael@0 143
michael@0 144 NS_IMETHODIMP
michael@0 145 nsComposerCommandsUpdater::WillRedo(nsITransactionManager *aManager,
michael@0 146 nsITransaction *aTransaction,
michael@0 147 bool *aInterrupt)
michael@0 148 {
michael@0 149 *aInterrupt = false;
michael@0 150 return NS_OK;
michael@0 151 }
michael@0 152
michael@0 153 NS_IMETHODIMP
michael@0 154 nsComposerCommandsUpdater::DidRedo(nsITransactionManager *aManager,
michael@0 155 nsITransaction *aTransaction,
michael@0 156 nsresult aRedoResult)
michael@0 157 {
michael@0 158 UpdateCommandGroup(NS_LITERAL_STRING("undo"));
michael@0 159 return NS_OK;
michael@0 160 }
michael@0 161
michael@0 162 NS_IMETHODIMP
michael@0 163 nsComposerCommandsUpdater::WillBeginBatch(nsITransactionManager *aManager,
michael@0 164 bool *aInterrupt)
michael@0 165 {
michael@0 166 *aInterrupt = false;
michael@0 167 return NS_OK;
michael@0 168 }
michael@0 169
michael@0 170 NS_IMETHODIMP
michael@0 171 nsComposerCommandsUpdater::DidBeginBatch(nsITransactionManager *aManager,
michael@0 172 nsresult aResult)
michael@0 173 {
michael@0 174 return NS_OK;
michael@0 175 }
michael@0 176
michael@0 177 NS_IMETHODIMP
michael@0 178 nsComposerCommandsUpdater::WillEndBatch(nsITransactionManager *aManager,
michael@0 179 bool *aInterrupt)
michael@0 180 {
michael@0 181 *aInterrupt = false;
michael@0 182 return NS_OK;
michael@0 183 }
michael@0 184
michael@0 185 NS_IMETHODIMP
michael@0 186 nsComposerCommandsUpdater::DidEndBatch(nsITransactionManager *aManager,
michael@0 187 nsresult aResult)
michael@0 188 {
michael@0 189 return NS_OK;
michael@0 190 }
michael@0 191
michael@0 192 NS_IMETHODIMP
michael@0 193 nsComposerCommandsUpdater::WillMerge(nsITransactionManager *aManager,
michael@0 194 nsITransaction *aTopTransaction,
michael@0 195 nsITransaction *aTransactionToMerge,
michael@0 196 bool *aInterrupt)
michael@0 197 {
michael@0 198 *aInterrupt = false;
michael@0 199 return NS_OK;
michael@0 200 }
michael@0 201
michael@0 202 NS_IMETHODIMP
michael@0 203 nsComposerCommandsUpdater::DidMerge(nsITransactionManager *aManager,
michael@0 204 nsITransaction *aTopTransaction,
michael@0 205 nsITransaction *aTransactionToMerge,
michael@0 206 bool aDidMerge, nsresult aMergeResult)
michael@0 207 {
michael@0 208 return NS_OK;
michael@0 209 }
michael@0 210
michael@0 211 #if 0
michael@0 212 #pragma mark -
michael@0 213 #endif
michael@0 214
michael@0 215 nsresult
michael@0 216 nsComposerCommandsUpdater::Init(nsIDOMWindow* aDOMWindow)
michael@0 217 {
michael@0 218 NS_ENSURE_ARG(aDOMWindow);
michael@0 219 mDOMWindow = do_GetWeakReference(aDOMWindow);
michael@0 220
michael@0 221 nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aDOMWindow));
michael@0 222 if (window)
michael@0 223 {
michael@0 224 mDocShell = do_GetWeakReference(window->GetDocShell());
michael@0 225 }
michael@0 226 return NS_OK;
michael@0 227 }
michael@0 228
michael@0 229 nsresult
michael@0 230 nsComposerCommandsUpdater::PrimeUpdateTimer()
michael@0 231 {
michael@0 232 if (!mUpdateTimer)
michael@0 233 {
michael@0 234 nsresult rv = NS_OK;
michael@0 235 mUpdateTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
michael@0 236 NS_ENSURE_SUCCESS(rv, rv);
michael@0 237 }
michael@0 238
michael@0 239 const uint32_t kUpdateTimerDelay = 150;
michael@0 240 return mUpdateTimer->InitWithCallback(static_cast<nsITimerCallback*>(this),
michael@0 241 kUpdateTimerDelay,
michael@0 242 nsITimer::TYPE_ONE_SHOT);
michael@0 243 }
michael@0 244
michael@0 245
michael@0 246 void nsComposerCommandsUpdater::TimerCallback()
michael@0 247 {
michael@0 248 // if the selection state has changed, update stuff
michael@0 249 bool isCollapsed = SelectionIsCollapsed();
michael@0 250 if (static_cast<int8_t>(isCollapsed) != mSelectionCollapsed)
michael@0 251 {
michael@0 252 UpdateCommandGroup(NS_LITERAL_STRING("select"));
michael@0 253 mSelectionCollapsed = isCollapsed;
michael@0 254 }
michael@0 255
michael@0 256 // isn't this redundant with the UpdateCommandGroup above?
michael@0 257 // can we just nuke the above call? or create a meta command group?
michael@0 258 UpdateCommandGroup(NS_LITERAL_STRING("style"));
michael@0 259 }
michael@0 260
michael@0 261 nsresult
michael@0 262 nsComposerCommandsUpdater::UpdateDirtyState(bool aNowDirty)
michael@0 263 {
michael@0 264 if (mDirtyState != static_cast<int8_t>(aNowDirty))
michael@0 265 {
michael@0 266 UpdateCommandGroup(NS_LITERAL_STRING("save"));
michael@0 267 UpdateCommandGroup(NS_LITERAL_STRING("undo"));
michael@0 268 mDirtyState = aNowDirty;
michael@0 269 }
michael@0 270
michael@0 271 return NS_OK;
michael@0 272 }
michael@0 273
michael@0 274 nsresult
michael@0 275 nsComposerCommandsUpdater::UpdateCommandGroup(const nsAString& aCommandGroup)
michael@0 276 {
michael@0 277 nsCOMPtr<nsPICommandUpdater> commandUpdater = GetCommandUpdater();
michael@0 278 NS_ENSURE_TRUE(commandUpdater, NS_ERROR_FAILURE);
michael@0 279
michael@0 280
michael@0 281 // This hardcoded list of commands is temporary.
michael@0 282 // This code should use nsIControllerCommandGroup.
michael@0 283 if (aCommandGroup.EqualsLiteral("undo"))
michael@0 284 {
michael@0 285 commandUpdater->CommandStatusChanged("cmd_undo");
michael@0 286 commandUpdater->CommandStatusChanged("cmd_redo");
michael@0 287 }
michael@0 288 else if (aCommandGroup.EqualsLiteral("select") ||
michael@0 289 aCommandGroup.EqualsLiteral("style"))
michael@0 290 {
michael@0 291 commandUpdater->CommandStatusChanged("cmd_bold");
michael@0 292 commandUpdater->CommandStatusChanged("cmd_italic");
michael@0 293 commandUpdater->CommandStatusChanged("cmd_underline");
michael@0 294 commandUpdater->CommandStatusChanged("cmd_tt");
michael@0 295
michael@0 296 commandUpdater->CommandStatusChanged("cmd_strikethrough");
michael@0 297 commandUpdater->CommandStatusChanged("cmd_superscript");
michael@0 298 commandUpdater->CommandStatusChanged("cmd_subscript");
michael@0 299 commandUpdater->CommandStatusChanged("cmd_nobreak");
michael@0 300
michael@0 301 commandUpdater->CommandStatusChanged("cmd_em");
michael@0 302 commandUpdater->CommandStatusChanged("cmd_strong");
michael@0 303 commandUpdater->CommandStatusChanged("cmd_cite");
michael@0 304 commandUpdater->CommandStatusChanged("cmd_abbr");
michael@0 305 commandUpdater->CommandStatusChanged("cmd_acronym");
michael@0 306 commandUpdater->CommandStatusChanged("cmd_code");
michael@0 307 commandUpdater->CommandStatusChanged("cmd_samp");
michael@0 308 commandUpdater->CommandStatusChanged("cmd_var");
michael@0 309
michael@0 310 commandUpdater->CommandStatusChanged("cmd_increaseFont");
michael@0 311 commandUpdater->CommandStatusChanged("cmd_decreaseFont");
michael@0 312
michael@0 313 commandUpdater->CommandStatusChanged("cmd_paragraphState");
michael@0 314 commandUpdater->CommandStatusChanged("cmd_fontFace");
michael@0 315 commandUpdater->CommandStatusChanged("cmd_fontColor");
michael@0 316 commandUpdater->CommandStatusChanged("cmd_backgroundColor");
michael@0 317 commandUpdater->CommandStatusChanged("cmd_highlight");
michael@0 318 }
michael@0 319 else if (aCommandGroup.EqualsLiteral("save"))
michael@0 320 {
michael@0 321 // save commands (most are not in C++)
michael@0 322 commandUpdater->CommandStatusChanged("cmd_setDocumentModified");
michael@0 323 commandUpdater->CommandStatusChanged("cmd_save");
michael@0 324 }
michael@0 325 return NS_OK;
michael@0 326 }
michael@0 327
michael@0 328 nsresult
michael@0 329 nsComposerCommandsUpdater::UpdateOneCommand(const char *aCommand)
michael@0 330 {
michael@0 331 nsCOMPtr<nsPICommandUpdater> commandUpdater = GetCommandUpdater();
michael@0 332 NS_ENSURE_TRUE(commandUpdater, NS_ERROR_FAILURE);
michael@0 333
michael@0 334 commandUpdater->CommandStatusChanged(aCommand);
michael@0 335
michael@0 336 return NS_OK;
michael@0 337 }
michael@0 338
michael@0 339 bool
michael@0 340 nsComposerCommandsUpdater::SelectionIsCollapsed()
michael@0 341 {
michael@0 342 nsCOMPtr<nsIDOMWindow> domWindow = do_QueryReferent(mDOMWindow);
michael@0 343 NS_ENSURE_TRUE(domWindow, true);
michael@0 344
michael@0 345 nsCOMPtr<nsISelection> domSelection;
michael@0 346 if (NS_SUCCEEDED(domWindow->GetSelection(getter_AddRefs(domSelection))) && domSelection)
michael@0 347 {
michael@0 348 bool selectionCollapsed = false;
michael@0 349 domSelection->GetIsCollapsed(&selectionCollapsed);
michael@0 350 return selectionCollapsed;
michael@0 351 }
michael@0 352
michael@0 353 NS_WARNING("nsComposerCommandsUpdater::SelectionIsCollapsed - no domSelection");
michael@0 354
michael@0 355 return false;
michael@0 356 }
michael@0 357
michael@0 358 already_AddRefed<nsPICommandUpdater>
michael@0 359 nsComposerCommandsUpdater::GetCommandUpdater()
michael@0 360 {
michael@0 361 nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
michael@0 362 NS_ENSURE_TRUE(docShell, nullptr);
michael@0 363 nsCOMPtr<nsICommandManager> manager = do_GetInterface(docShell);
michael@0 364 nsCOMPtr<nsPICommandUpdater> updater = do_QueryInterface(manager);
michael@0 365 return updater.forget();
michael@0 366 }
michael@0 367
michael@0 368 #if 0
michael@0 369 #pragma mark -
michael@0 370 #endif
michael@0 371
michael@0 372 nsresult
michael@0 373 nsComposerCommandsUpdater::Notify(nsITimer *timer)
michael@0 374 {
michael@0 375 NS_ASSERTION(timer == mUpdateTimer.get(), "Hey, this ain't my timer!");
michael@0 376 TimerCallback();
michael@0 377 return NS_OK;
michael@0 378 }
michael@0 379
michael@0 380 #if 0
michael@0 381 #pragma mark -
michael@0 382 #endif
michael@0 383
michael@0 384
michael@0 385 nsresult
michael@0 386 NS_NewComposerCommandsUpdater(nsISelectionListener** aInstancePtrResult)
michael@0 387 {
michael@0 388 nsComposerCommandsUpdater* newThang = new nsComposerCommandsUpdater;
michael@0 389 NS_ENSURE_TRUE(newThang, NS_ERROR_OUT_OF_MEMORY);
michael@0 390
michael@0 391 return newThang->QueryInterface(NS_GET_IID(nsISelectionListener),
michael@0 392 (void **)aInstancePtrResult);
michael@0 393 }

mercurial