/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Inline Spellchecker * * The Initial Developer of the Original Code is Mozdev Group, Inc. * Portions created by the Initial Developer are Copyright (C) 2004 * the Initial Developer. All Rights Reserved. * * Contributor(s): Neil Deakin (neil@mozdevgroup.com) * Scott MacGregor (mscott@mozilla.org) * Brett Wilson * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef __mozinlinespellchecker_h__ #define __mozinlinespellchecker_h__ #include "nsAutoPtr.h" #include "nsIDOMRange.h" #include "nsIEditorSpellCheck.h" #include "nsIEditActionListener.h" #include "nsIInlineSpellChecker.h" #include "nsITextServicesDocument.h" #include "nsIDOMTreeWalker.h" #include "nsWeakReference.h" #include "nsIEditor.h" #include "nsIDOMFocusListener.h" #include "nsIDOMMouseListener.h" #include "nsIDOMKeyListener.h" #include "nsWeakReference.h" #include "mozISpellI18NUtil.h" class nsIDOMDocumentRange; class nsIDOMMouseEventListener; class mozInlineSpellWordUtil; class mozInlineSpellChecker; class mozInlineSpellResume; class mozInlineSpellStatus { public: mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker); nsresult InitForEditorChange(PRInt32 aAction, nsIDOMNode* aAnchorNode, PRInt32 aAnchorOffset, nsIDOMNode* aPreviousNode, PRInt32 aPreviousOffset, nsIDOMNode* aStartNode, PRInt32 aStartOffset, nsIDOMNode* aEndNode, PRInt32 aEndOffset); nsresult InitForNavigation(PRBool aForceCheck, PRInt32 aNewPositionOffset, nsIDOMNode* aOldAnchorNode, PRInt32 aOldAnchorOffset, nsIDOMNode* aNewAnchorNode, PRInt32 aNewAnchorOffset, PRBool* aContinue); nsresult InitForSelection(); nsresult InitForRange(nsIDOMRange* aRange); nsresult FinishInitOnEvent(mozInlineSpellWordUtil& aWordUtil); nsRefPtr mSpellChecker; // The total number of words checked in this sequence, using this tally tells // us when to stop. This count is preserved as we continue checking in new // messages. PRInt32 mWordCount; // what happened? enum Operation { eOpChange, // for SpellCheckAfterChange except kOpDeleteSelection eOpChangeDelete, // for SpellCheckAfterChange kOpDeleteSelection eOpNavigation, // for HandleNavigationEvent eOpSelection, // re-check all misspelled words eOpResume }; // for resuming a previously started check Operation mOp; // Used for events where we have already computed the range to use. It can // also be NULL in these cases where we need to check the entire range. nsCOMPtr mRange; // If we happen to know something was inserted, this is that range. // Can be NULL (this only allows an optimization, so not setting doesn't hurt) nsCOMPtr mCreatedRange; // Contains the range computed for the current word. Can be NULL. nsCOMPtr mNoCheckRange; // Indicates the position of the cursor for the event (so we can compute // mNoCheckRange). It can be NULL if we don't care about the cursor position // (such as for the intial check of everything). // // For mOp == eOpNavigation, this is the NEW position of the cursor nsCOMPtr mAnchorRange; // ----- // The following members are only for navigation events and are only // stored for FinishNavigationEvent to initialize the other members. // ----- // this is the OLD position of the cursor nsCOMPtr mOldNavigationAnchorRange; // Set when we should force checking the current word. See // mozInlineSpellChecker::HandleNavigationEvent for a description of why we // have this. PRBool mForceNavigationWordCheck; // Contains the offset passed in to HandleNavigationEvent PRInt32 mNewNavigationPositionOffset; protected: nsresult FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil); nsresult FillNoCheckRangeFromAnchor(mozInlineSpellWordUtil& aWordUtil); nsresult GetDocumentRange(nsIDOMDocumentRange** aDocRange); nsresult PositionToCollapsedRange(nsIDOMDocumentRange* aDocRange, nsIDOMNode* aNode, PRInt32 aOffset, nsIDOMRange** aRange); }; class mozInlineSpellChecker : public nsIInlineSpellChecker, nsIEditActionListener, nsIDOMFocusListener, nsIDOMMouseListener, nsIDOMKeyListener, nsSupportsWeakReference { private: friend class mozInlineSpellStatus; // Access with CanEnableInlineSpellChecking enum SpellCheckingState { SpellCheck_Uninitialized = -1, SpellCheck_NotAvailable = 0, SpellCheck_Available = 1}; static SpellCheckingState gCanEnableSpellChecking; nsWeakPtr mEditor; nsCOMPtr mSpellCheck; nsCOMPtr mTextServicesDocument; nsCOMPtr mTreeWalker; nsCOMPtr mConverter; PRInt32 mNumWordsInSpellSelection; PRInt32 mMaxNumWordsInSpellSelection; // How many misspellings we can add at once. This is often less than the max // total number of misspellings. When you have a large textarea prepopulated // with text with many misspellings, we can hit this limit. By making it // lower than the total number of misspelled words, new text typed by the // user can also have spellchecking in it. PRInt32 mMaxMisspellingsPerCheck; // we need to keep track of the current text position in the document // so we can spell check the old word when the user clicks around the document. nsCOMPtr mCurrentSelectionAnchorNode; PRInt32 mCurrentSelectionOffset; // Set when we have spellchecked after the last edit operation. See the // commment at the top of the .cpp file for more info. PRBool mNeedsCheckAfterNavigation; // TODO: these should be defined somewhere so that they don't have to be copied // from editor! enum OperationID { kOpIgnore = -1, kOpNone = 0, kOpUndo, kOpRedo, kOpInsertNode, kOpCreateNode, kOpDeleteNode, kOpSplitNode, kOpJoinNode, kOpDeleteSelection, kOpInsertBreak = 1000, kOpInsertText = 1001, kOpInsertIMEText = 1002, kOpDeleteText = 1003, kOpMakeList = 3001, kOpIndent = 3002, kOpOutdent = 3003, kOpAlign = 3004, kOpMakeBasicBlock = 3005, kOpRemoveList = 3006, kOpMakeDefListItem = 3007, kOpInsertElement = 3008, kOpInsertQuotation = 3009, kOpSetTextProperty = 3010, kOpRemoveTextProperty = 3011, kOpHTMLPaste = 3012, kOpLoadHTML = 3013, kOpResetTextProperties = 3014, kOpSetAbsolutePosition = 3015, kOpRemoveAbsolutePosition = 3016, kOpDecreaseZIndex = 3017, kOpIncreaseZIndex = 3018 }; public: NS_DECL_ISUPPORTS NS_DECL_NSIEDITACTIONLISTENER NS_DECL_NSIINLINESPELLCHECKER // returns true if it looks likely that we can enable real-time spell checking static PRBool CanEnableInlineSpellChecking(); /*BEGIN implementations of focus event handler interface*/ NS_IMETHOD Focus(nsIDOMEvent* aEvent); NS_IMETHOD Blur(nsIDOMEvent* aEvent); /*END implementations of focus event handler interface*/ /*BEGIN implementations of mouseevent handler interface*/ NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent); NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent); NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent); NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent); NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent); NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent); /*END implementations of mouseevent handler interface*/ /* BEGIN interfaces in to the keylistener interface. */ NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent); NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent); NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent); /* END interfaces from nsIDOMKeyListener */ mozInlineSpellChecker(); virtual ~mozInlineSpellChecker(); // spell checks all of the words between two nodes nsresult SpellCheckBetweenNodes(nsIDOMNode *aStartNode, PRInt32 aStartOffset, nsIDOMNode *aEndNode, PRInt32 aEndOffset); // examines the dom node in question and returns true if the inline spell // checker should skip the node (i.e. the text is inside of a block quote // or an e-mail signature...) nsresult SkipSpellCheckForNode(nsIEditor* aEditor, nsIDOMNode *aNode, PRBool * aCheckSpelling); nsresult SpellCheckAfterChange(nsIDOMNode* aCursorNode, PRInt32 aCursorOffset, nsIDOMNode* aPreviousNode, PRInt32 aPreviousOffset, nsISelection* aSpellCheckSelection); // spell check the text contained within aRange, potentially scheduling // another check in the future if the time threshold is reached nsresult ScheduleSpellCheck(const mozInlineSpellStatus& aStatus); nsresult DoSpellCheckSelection(mozInlineSpellWordUtil& aWordUtil, nsISelection* aSpellCheckSelection, mozInlineSpellStatus* aStatus); nsresult DoSpellCheck(mozInlineSpellWordUtil& aWordUtil, nsISelection *aSpellCheckSelection, mozInlineSpellStatus* aStatus, PRBool* aDoneChecking); // helper routine to determine if a point is inside of a the passed in selection. nsresult IsPointInSelection(nsISelection *aSelection, nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMRange **aRange); nsresult CleanupRangesInSelection(nsISelection *aSelection); nsresult RemoveRange(nsISelection *aSpellCheckSelection, nsIDOMRange * aRange); nsresult AddRange(nsISelection *aSpellCheckSelection, nsIDOMRange * aRange); PRBool SpellCheckSelectionIsFull() { return mNumWordsInSpellSelection >= mMaxNumWordsInSpellSelection; } nsresult MakeSpellCheckRange(nsIDOMNode* aStartNode, PRInt32 aStartOffset, nsIDOMNode* aEndNode, PRInt32 aEndOffset, nsIDOMRange** aRange); // DOM and editor event registration helper routines nsresult RegisterEventListeners(); nsresult UnregisterEventListeners(); nsresult HandleNavigationEvent(nsIDOMEvent * aEvent, PRBool aForceWordSpellCheck, PRInt32 aNewPositionOffset = 0); nsresult GetSpellCheckSelection(nsISelection ** aSpellCheckSelection); nsresult SaveCurrentSelectionPosition(); nsresult ResumeCheck(mozInlineSpellStatus* aStatus); }; #endif /* __mozinlinespellchecker_h__ */