1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Inline Spellchecker
16 : *
17 : * The Initial Developer of the Original Code is Mozdev Group, Inc.
18 : * Portions created by the Initial Developer are Copyright (C) 2004
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s): Neil Deakin (neil@mozdevgroup.com)
22 : * Scott MacGregor (mscott@mozilla.org)
23 : * Brett Wilson <brettw@gmail.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef __mozinlinespellchecker_h__
40 : #define __mozinlinespellchecker_h__
41 :
42 : #include "nsAutoPtr.h"
43 : #include "nsRange.h"
44 : #include "nsIEditorSpellCheck.h"
45 : #include "nsIEditActionListener.h"
46 : #include "nsIInlineSpellChecker.h"
47 : #include "nsITextServicesDocument.h"
48 : #include "nsIDOMTreeWalker.h"
49 : #include "nsWeakReference.h"
50 : #include "nsIEditor.h"
51 : #include "nsIDOMEventListener.h"
52 : #include "nsWeakReference.h"
53 : #include "mozISpellI18NUtil.h"
54 : #include "nsCycleCollectionParticipant.h"
55 :
56 : // X.h defines KeyPress
57 : #ifdef KeyPress
58 : #undef KeyPress
59 : #endif
60 :
61 : class nsIDOMMouseEventListener;
62 : class mozInlineSpellWordUtil;
63 : class mozInlineSpellChecker;
64 : class mozInlineSpellResume;
65 :
66 : class mozInlineSpellStatus
67 0 : {
68 : public:
69 : mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker);
70 :
71 : nsresult InitForEditorChange(PRInt32 aAction,
72 : nsIDOMNode* aAnchorNode, PRInt32 aAnchorOffset,
73 : nsIDOMNode* aPreviousNode, PRInt32 aPreviousOffset,
74 : nsIDOMNode* aStartNode, PRInt32 aStartOffset,
75 : nsIDOMNode* aEndNode, PRInt32 aEndOffset);
76 : nsresult InitForNavigation(bool aForceCheck, PRInt32 aNewPositionOffset,
77 : nsIDOMNode* aOldAnchorNode, PRInt32 aOldAnchorOffset,
78 : nsIDOMNode* aNewAnchorNode, PRInt32 aNewAnchorOffset,
79 : bool* aContinue);
80 : nsresult InitForSelection();
81 : nsresult InitForRange(nsRange* aRange);
82 :
83 : nsresult FinishInitOnEvent(mozInlineSpellWordUtil& aWordUtil);
84 :
85 : // Return true if we plan to spell-check everything
86 0 : bool IsFullSpellCheck() const {
87 0 : return mOp == eOpChange && !mRange;
88 : }
89 :
90 : nsRefPtr<mozInlineSpellChecker> mSpellChecker;
91 :
92 : // The total number of words checked in this sequence, using this tally tells
93 : // us when to stop. This count is preserved as we continue checking in new
94 : // messages.
95 : PRInt32 mWordCount;
96 :
97 : // what happened?
98 : enum Operation { eOpChange, // for SpellCheckAfterChange except kOpDeleteSelection
99 : eOpChangeDelete, // for SpellCheckAfterChange kOpDeleteSelection
100 : eOpNavigation, // for HandleNavigationEvent
101 : eOpSelection, // re-check all misspelled words
102 : eOpResume }; // for resuming a previously started check
103 : Operation mOp;
104 :
105 : // Used for events where we have already computed the range to use. It can
106 : // also be NULL in these cases where we need to check the entire range.
107 : nsRefPtr<nsRange> mRange;
108 :
109 : // If we happen to know something was inserted, this is that range.
110 : // Can be NULL (this only allows an optimization, so not setting doesn't hurt)
111 : nsCOMPtr<nsIDOMRange> mCreatedRange;
112 :
113 : // Contains the range computed for the current word. Can be NULL.
114 : nsRefPtr<nsRange> mNoCheckRange;
115 :
116 : // Indicates the position of the cursor for the event (so we can compute
117 : // mNoCheckRange). It can be NULL if we don't care about the cursor position
118 : // (such as for the intial check of everything).
119 : //
120 : // For mOp == eOpNavigation, this is the NEW position of the cursor
121 : nsCOMPtr<nsIDOMRange> mAnchorRange;
122 :
123 : // -----
124 : // The following members are only for navigation events and are only
125 : // stored for FinishNavigationEvent to initialize the other members.
126 : // -----
127 :
128 : // this is the OLD position of the cursor
129 : nsCOMPtr<nsIDOMRange> mOldNavigationAnchorRange;
130 :
131 : // Set when we should force checking the current word. See
132 : // mozInlineSpellChecker::HandleNavigationEvent for a description of why we
133 : // have this.
134 : bool mForceNavigationWordCheck;
135 :
136 : // Contains the offset passed in to HandleNavigationEvent
137 : PRInt32 mNewNavigationPositionOffset;
138 :
139 : protected:
140 : nsresult FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil);
141 :
142 : nsresult FillNoCheckRangeFromAnchor(mozInlineSpellWordUtil& aWordUtil);
143 :
144 : nsresult GetDocument(nsIDOMDocument** aDocument);
145 : nsresult PositionToCollapsedRange(nsIDOMDocument* aDocument,
146 : nsIDOMNode* aNode, PRInt32 aOffset,
147 : nsIDOMRange** aRange);
148 : };
149 :
150 : class mozInlineSpellChecker : public nsIInlineSpellChecker,
151 : public nsIEditActionListener,
152 : public nsIDOMEventListener,
153 : public nsSupportsWeakReference
154 : {
155 : private:
156 : friend class mozInlineSpellStatus;
157 :
158 : // Access with CanEnableInlineSpellChecking
159 : enum SpellCheckingState { SpellCheck_Uninitialized = -1,
160 : SpellCheck_NotAvailable = 0,
161 : SpellCheck_Available = 1};
162 : static SpellCheckingState gCanEnableSpellChecking;
163 :
164 : nsWeakPtr mEditor;
165 : nsCOMPtr<nsIEditorSpellCheck> mSpellCheck;
166 : nsCOMPtr<nsITextServicesDocument> mTextServicesDocument;
167 : nsCOMPtr<nsIDOMTreeWalker> mTreeWalker;
168 : nsCOMPtr<mozISpellI18NUtil> mConverter;
169 :
170 : PRInt32 mNumWordsInSpellSelection;
171 : PRInt32 mMaxNumWordsInSpellSelection;
172 :
173 : // How many misspellings we can add at once. This is often less than the max
174 : // total number of misspellings. When you have a large textarea prepopulated
175 : // with text with many misspellings, we can hit this limit. By making it
176 : // lower than the total number of misspelled words, new text typed by the
177 : // user can also have spellchecking in it.
178 : PRInt32 mMaxMisspellingsPerCheck;
179 :
180 : // we need to keep track of the current text position in the document
181 : // so we can spell check the old word when the user clicks around the document.
182 : nsCOMPtr<nsIDOMNode> mCurrentSelectionAnchorNode;
183 : PRInt32 mCurrentSelectionOffset;
184 :
185 : // Set when we have spellchecked after the last edit operation. See the
186 : // commment at the top of the .cpp file for more info.
187 : bool mNeedsCheckAfterNavigation;
188 :
189 : // Set when we have a pending mozInlineSpellResume which will check
190 : // the whole document.
191 : bool mFullSpellCheckScheduled;
192 :
193 : // TODO: these should be defined somewhere so that they don't have to be copied
194 : // from editor!
195 : enum OperationID
196 : {
197 : kOpIgnore = -1,
198 : kOpNone = 0,
199 : kOpUndo,
200 : kOpRedo,
201 : kOpInsertNode,
202 : kOpCreateNode,
203 : kOpDeleteNode,
204 : kOpSplitNode,
205 : kOpJoinNode,
206 : kOpDeleteSelection,
207 :
208 : kOpInsertBreak = 1000,
209 : kOpInsertText = 1001,
210 : kOpInsertIMEText = 1002,
211 : kOpDeleteText = 1003,
212 :
213 : kOpMakeList = 3001,
214 : kOpIndent = 3002,
215 : kOpOutdent = 3003,
216 : kOpAlign = 3004,
217 : kOpMakeBasicBlock = 3005,
218 : kOpRemoveList = 3006,
219 : kOpMakeDefListItem = 3007,
220 : kOpInsertElement = 3008,
221 : kOpInsertQuotation = 3009,
222 : kOpSetTextProperty = 3010,
223 : kOpRemoveTextProperty = 3011,
224 : kOpHTMLPaste = 3012,
225 : kOpLoadHTML = 3013,
226 : kOpResetTextProperties = 3014,
227 : kOpSetAbsolutePosition = 3015,
228 : kOpRemoveAbsolutePosition = 3016,
229 : kOpDecreaseZIndex = 3017,
230 : kOpIncreaseZIndex = 3018
231 : };
232 :
233 : public:
234 :
235 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
236 : NS_DECL_NSIEDITACTIONLISTENER
237 : NS_DECL_NSIINLINESPELLCHECKER
238 : NS_DECL_NSIDOMEVENTLISTENER
239 1464 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozInlineSpellChecker, nsIDOMEventListener)
240 :
241 : // returns true if there are any spell checking dictionaries available
242 : static bool CanEnableInlineSpellChecking();
243 : // update the cached value whenever the list of available dictionaries changes
244 : static void UpdateCanEnableInlineSpellChecking();
245 :
246 : nsresult Blur(nsIDOMEvent* aEvent);
247 : nsresult MouseClick(nsIDOMEvent* aMouseEvent);
248 : nsresult KeyPress(nsIDOMEvent* aKeyEvent);
249 :
250 : mozInlineSpellChecker();
251 : virtual ~mozInlineSpellChecker();
252 :
253 : // spell checks all of the words between two nodes
254 : nsresult SpellCheckBetweenNodes(nsIDOMNode *aStartNode,
255 : PRInt32 aStartOffset,
256 : nsIDOMNode *aEndNode,
257 : PRInt32 aEndOffset);
258 :
259 : // examines the dom node in question and returns true if the inline spell
260 : // checker should skip the node (i.e. the text is inside of a block quote
261 : // or an e-mail signature...)
262 : nsresult SkipSpellCheckForNode(nsIEditor* aEditor,
263 : nsIDOMNode *aNode, bool * aCheckSpelling);
264 :
265 : nsresult SpellCheckAfterChange(nsIDOMNode* aCursorNode, PRInt32 aCursorOffset,
266 : nsIDOMNode* aPreviousNode, PRInt32 aPreviousOffset,
267 : nsISelection* aSpellCheckSelection);
268 :
269 : // spell check the text contained within aRange, potentially scheduling
270 : // another check in the future if the time threshold is reached
271 : nsresult ScheduleSpellCheck(const mozInlineSpellStatus& aStatus);
272 :
273 : nsresult DoSpellCheckSelection(mozInlineSpellWordUtil& aWordUtil,
274 : nsISelection* aSpellCheckSelection,
275 : mozInlineSpellStatus* aStatus);
276 : nsresult DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
277 : nsISelection *aSpellCheckSelection,
278 : mozInlineSpellStatus* aStatus,
279 : bool* aDoneChecking);
280 :
281 : // helper routine to determine if a point is inside of the passed in selection.
282 : nsresult IsPointInSelection(nsISelection *aSelection,
283 : nsIDOMNode *aNode,
284 : PRInt32 aOffset,
285 : nsIDOMRange **aRange);
286 :
287 : nsresult CleanupRangesInSelection(nsISelection *aSelection);
288 :
289 : nsresult RemoveRange(nsISelection *aSpellCheckSelection, nsIDOMRange * aRange);
290 : nsresult AddRange(nsISelection *aSpellCheckSelection, nsIDOMRange * aRange);
291 0 : bool SpellCheckSelectionIsFull() { return mNumWordsInSpellSelection >= mMaxNumWordsInSpellSelection; }
292 :
293 : nsresult MakeSpellCheckRange(nsIDOMNode* aStartNode, PRInt32 aStartOffset,
294 : nsIDOMNode* aEndNode, PRInt32 aEndOffset,
295 : nsRange** aRange);
296 :
297 : // DOM and editor event registration helper routines
298 : nsresult RegisterEventListeners();
299 : nsresult UnregisterEventListeners();
300 : nsresult HandleNavigationEvent(bool aForceWordSpellCheck, PRInt32 aNewPositionOffset = 0);
301 :
302 : nsresult GetSpellCheckSelection(nsISelection ** aSpellCheckSelection);
303 : nsresult SaveCurrentSelectionPosition();
304 :
305 : nsresult ResumeCheck(mozInlineSpellStatus* aStatus);
306 : };
307 :
308 : #endif /* __mozinlinespellchecker_h__ */
|