Back to index

lightning-sunbird  0.9+nobinonly
mozInlineSpellChecker.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Inline Spellchecker
00016  *
00017  * The Initial Developer of the Original Code is Mozdev Group, Inc.
00018  * Portions created by the Initial Developer are Copyright (C) 2004
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s): Neil Deakin (neil@mozdevgroup.com)
00022  *                 Scott MacGregor (mscott@mozilla.org)
00023  *                 Brett Wilson <brettw@gmail.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #ifndef __mozinlinespellchecker_h__
00040 #define __mozinlinespellchecker_h__
00041 
00042 #include "nsAutoPtr.h"
00043 #include "nsIDOMRange.h"
00044 #include "nsIEditorSpellCheck.h"
00045 #include "nsIEditActionListener.h"
00046 #include "nsIInlineSpellChecker.h"
00047 #include "nsITextServicesDocument.h"
00048 #include "nsIDOMTreeWalker.h"
00049 #include "nsWeakReference.h"
00050 #include "nsIEditor.h"
00051 #include "nsIDOMMouseListener.h"
00052 #include "nsIDOMKeyListener.h"
00053 #include "nsWeakReference.h"
00054 #include "mozISpellI18NUtil.h"
00055 
00056 class nsIDOMDocumentRange;
00057 class nsIDOMMouseEventListener;
00058 class nsIEventQueueService;
00059 class mozInlineSpellWordUtil;
00060 class mozInlineSpellChecker;
00061 class mozInlineSpellResume;
00062 
00063 class mozInlineSpellStatus
00064 {
00065 public:
00066   mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker);
00067 
00068   nsresult InitForEditorChange(PRInt32 aAction,
00069                                nsIDOMNode* aAnchorNode, PRInt32 aAnchorOffset,
00070                                nsIDOMNode* aPreviousNode, PRInt32 aPreviousOffset,
00071                                nsIDOMNode* aStartNode, PRInt32 aStartOffset,
00072                                nsIDOMNode* aEndNode, PRInt32 aEndOffset);
00073   nsresult InitForNavigation(PRBool aForceCheck, PRInt32 aNewPositionOffset,
00074                              nsIDOMNode* aOldAnchorNode, PRInt32 aOldAnchorOffset,
00075                              nsIDOMNode* aNewAnchorNode, PRInt32 aNewAnchorOffset,
00076                              PRBool* aContinue);
00077   nsresult InitForSelection();
00078   nsresult InitForRange(nsIDOMRange* aRange);
00079 
00080   nsresult FinishInitOnEvent(mozInlineSpellWordUtil& aWordUtil);
00081 
00082   nsRefPtr<mozInlineSpellChecker> mSpellChecker;
00083 
00084   // The total number of words checked in this sequence, using this tally tells
00085   // us when to stop. This count is preserved as we continue checking in new
00086   // messages.
00087   PRInt32 mWordCount;
00088 
00089   // what happened?
00090   enum Operation { eOpChange,       // for SpellCheckAfterChange except kOpDeleteSelection
00091                    eOpChangeDelete, // for SpellCheckAfterChange kOpDeleteSelection
00092                    eOpNavigation,   // for HandleNavigationEvent
00093                    eOpSelection,    // re-check all misspelled words
00094                    eOpResume };     // for resuming a previously started check
00095   Operation mOp;
00096 
00097   // Used for events where we have already computed the range to use. It can
00098   // also be NULL in these cases where we need to check the entire range.
00099   nsCOMPtr<nsIDOMRange> mRange;
00100 
00101   // If we happen to know something was inserted, this is that range.
00102   // Can be NULL (this only allows an optimization, so not setting doesn't hurt)
00103   nsCOMPtr<nsIDOMRange> mCreatedRange;
00104 
00105   // Contains the range computed for the current word. Can be NULL.
00106   nsCOMPtr<nsIDOMRange> mNoCheckRange;
00107 
00108   // Indicates the position of the cursor for the event (so we can compute
00109   // mNoCheckRange). It can be NULL if we don't care about the cursor position
00110   // (such as for the intial check of everything).
00111   //
00112   // For mOp == eOpNavigation, this is the NEW position of the cursor
00113   nsCOMPtr<nsIDOMRange> mAnchorRange;
00114 
00115   // -----
00116   // The following members are only for navigation events and are only
00117   // stored for FinishNavigationEvent to initialize the other members.
00118   // -----
00119 
00120   // this is the OLD position of the cursor
00121   nsCOMPtr<nsIDOMRange> mOldNavigationAnchorRange;
00122 
00123   // Set when we should force checking the current word. See
00124   // mozInlineSpellChecker::HandleNavigationEvent for a description of why we
00125   // have this.
00126   PRBool mForceNavigationWordCheck;
00127 
00128   // Contains the offset passed in to HandleNavigationEvent
00129   PRInt32 mNewNavigationPositionOffset;
00130 
00131 protected:
00132   nsresult FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil);
00133 
00134   nsresult FillNoCheckRangeFromAnchor(mozInlineSpellWordUtil& aWordUtil);
00135 
00136   nsresult GetDocumentRange(nsIDOMDocumentRange** aDocRange);
00137   nsresult PositionToCollapsedRange(nsIDOMDocumentRange* aDocRange,
00138                                     nsIDOMNode* aNode, PRInt32 aOffset,
00139                                     nsIDOMRange** aRange);
00140 };
00141 
00142 class mozInlineSpellChecker : public nsIInlineSpellChecker, nsIEditActionListener, nsIDOMMouseListener, nsIDOMKeyListener,
00143                                      nsSupportsWeakReference
00144 {
00145 private:
00146   friend class mozInlineSpellStatus;
00147 
00148   // Access with CanEnableInlineSpellChecking
00149   enum SpellCheckingState { SpellCheck_Uninitialized = -1,
00150                             SpellCheck_NotAvailable = 0,
00151                             SpellCheck_Available = 1};
00152   static SpellCheckingState gCanEnableSpellChecking;
00153 
00154   nsWeakPtr mEditor; 
00155   nsCOMPtr<nsIEditorSpellCheck> mSpellCheck;
00156   nsCOMPtr<nsITextServicesDocument> mTextServicesDocument;
00157   nsCOMPtr<nsIDOMTreeWalker> mTreeWalker;
00158   nsCOMPtr<mozISpellI18NUtil> mConverter;
00159 
00160   PRInt32 mNumWordsInSpellSelection;
00161   PRInt32 mMaxNumWordsInSpellSelection;
00162 
00163   // How many misspellings we can add at once. This is often less than the max
00164   // total number of misspellings. When you have a large textarea prepopulated
00165   // with text with many misspellings, we can hit this limit. By making it
00166   // lower than the total number of misspelled words, new text typed by the
00167   // user can also have spellchecking in it.
00168   PRInt32 mMaxMisspellingsPerCheck;
00169 
00170   // we need to keep track of the current text position in the document
00171   // so we can spell check the old word when the user clicks around the document.
00172   nsCOMPtr<nsIDOMNode> mCurrentSelectionAnchorNode;
00173   PRInt32              mCurrentSelectionOffset;
00174 
00175   // Set when we have spellchecked after the last edit operation. See the
00176   // commment at the top of the .cpp file for more info.
00177   PRBool mNeedsCheckAfterNavigation;
00178 
00179   // lazily created, may be NULL
00180   nsCOMPtr<nsIEventQueueService> mEventQueueService;
00181 
00182   // TODO: these should be defined somewhere so that they don't have to be copied
00183   // from editor!
00184   enum OperationID
00185   {
00186     kOpIgnore = -1,
00187     kOpNone = 0,
00188     kOpUndo,
00189     kOpRedo,
00190     kOpInsertNode,
00191     kOpCreateNode,
00192     kOpDeleteNode,
00193     kOpSplitNode,
00194     kOpJoinNode,
00195     kOpDeleteSelection,
00196 
00197     kOpInsertBreak    = 1000,
00198     kOpInsertText     = 1001,
00199     kOpInsertIMEText  = 1002,
00200     kOpDeleteText     = 1003,
00201 
00202     kOpMakeList            = 3001,
00203     kOpIndent              = 3002,
00204     kOpOutdent             = 3003,
00205     kOpAlign               = 3004,
00206     kOpMakeBasicBlock      = 3005,
00207     kOpRemoveList          = 3006,
00208     kOpMakeDefListItem     = 3007,
00209     kOpInsertElement       = 3008,
00210     kOpInsertQuotation     = 3009,
00211     kOpSetTextProperty     = 3010,
00212     kOpRemoveTextProperty  = 3011,
00213     kOpHTMLPaste           = 3012,
00214     kOpLoadHTML            = 3013,
00215     kOpResetTextProperties = 3014,
00216     kOpSetAbsolutePosition = 3015,
00217     kOpRemoveAbsolutePosition = 3016,
00218     kOpDecreaseZIndex      = 3017,
00219     kOpIncreaseZIndex      = 3018
00220   };
00221 
00222 public:
00223 
00224   NS_DECL_ISUPPORTS
00225   NS_DECL_NSIEDITACTIONLISTENER
00226   NS_DECL_NSIINLINESPELLCHECKER
00227 
00228   // returns true if it looks likely that we can enable real-time spell checking
00229   static PRBool CanEnableInlineSpellChecking();
00230 
00231   /*BEGIN implementations of mouseevent handler interface*/
00232   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
00233   NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
00234   NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
00235   NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
00236   NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent);
00237   NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent);
00238   NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent);
00239   /*END implementations of mouseevent handler interface*/
00240 
00241   /* BEGIN interfaces in to the keylistener  interface. */
00242   NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
00243   NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
00244   NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
00245   /* END interfaces from nsIDOMKeyListener */ 
00246 
00247   mozInlineSpellChecker();
00248   virtual ~mozInlineSpellChecker();
00249 
00250   // re-spellcheck the currently marked ranges
00251   nsresult SpellCheckSelection();
00252 
00253   // spell checks all of the words between two nodes
00254   nsresult SpellCheckBetweenNodes(nsIDOMNode *aStartNode,
00255                                   PRInt32 aStartOffset,
00256                                   nsIDOMNode *aEndNode,
00257                                   PRInt32 aEndOffset);
00258   
00259   // examines the dom node in question and returns true if the inline spell
00260   // checker should skip the node (i.e. the text is inside of a block quote
00261   // or an e-mail signature...)
00262   nsresult SkipSpellCheckForNode(nsIEditor* aEditor,
00263                                  nsIDOMNode *aNode, PRBool * aCheckSpelling);
00264 
00265   nsresult SpellCheckAfterChange(nsIDOMNode* aCursorNode, PRInt32 aCursorOffset,
00266                                  nsIDOMNode* aPreviousNode, PRInt32 aPreviousOffset,
00267                                  nsISelection* aSpellCheckSelection);
00268 
00269   // spell check the text contained within aRange, potentially scheduling
00270   // another check in the future if the time threshold is reached
00271   nsresult ScheduleSpellCheck(const mozInlineSpellStatus& aStatus);
00272 
00273   nsresult DoSpellCheckSelection(mozInlineSpellWordUtil& aWordUtil,
00274                                  nsISelection* aSpellCheckSelection,
00275                                  mozInlineSpellStatus* aStatus);
00276   nsresult DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
00277                         nsISelection *aSpellCheckSelection,
00278                         mozInlineSpellStatus* aStatus,
00279                         PRBool* aDoneChecking);
00280 
00281   // helper routine to determine if a point is inside of a the passed in selection.
00282   nsresult IsPointInSelection(nsISelection *aSelection,
00283                               nsIDOMNode *aNode,
00284                               PRInt32 aOffset,
00285                               nsIDOMRange **aRange);
00286 
00287   nsresult CleanupRangesInSelection(nsISelection *aSelection);
00288 
00289   nsresult RemoveRange(nsISelection *aSpellCheckSelection, nsIDOMRange * aRange);
00290   nsresult AddRange(nsISelection *aSpellCheckSelection, nsIDOMRange * aRange);
00291   PRBool   SpellCheckSelectionIsFull() { return mNumWordsInSpellSelection >= mMaxNumWordsInSpellSelection; }
00292 
00293   nsresult MakeSpellCheckRange(nsIDOMNode* aStartNode, PRInt32 aStartOffset,
00294                                nsIDOMNode* aEndNode, PRInt32 aEndOffset,
00295                                nsIDOMRange** aRange);
00296 
00297   // DOM and editor event registration helper routines
00298   nsresult RegisterEventListeners();
00299   nsresult UnregisterEventListeners();
00300   nsresult HandleNavigationEvent(nsIDOMEvent * aEvent, PRBool aForceWordSpellCheck, PRInt32 aNewPositionOffset = 0);
00301 
00302   nsresult GetSpellCheckSelection(nsISelection ** aSpellCheckSelection);
00303   nsresult SaveCurrentSelectionPosition();
00304 
00305   nsresult ResumeCheck(mozInlineSpellStatus* resume);
00306 };
00307 
00308 #endif /* __mozinlinespellchecker_h__ */