2010-12-09 Maciej Stachowiak <mjs@apple.com>
[WebKit.git] / WebCore / editing / Editor.h
1 /*
2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef Editor_h
27 #define Editor_h
28
29 #include "ClipboardAccessPolicy.h"
30 #include "Color.h"
31 #include "CorrectionPanelInfo.h"
32 #include "EditAction.h"
33 #include "EditingBehavior.h"
34 #include "EditorDeleteAction.h"
35 #include "EditorInsertAction.h"
36 #include "FindOptions.h"
37 #include "SelectionController.h"
38
39 #if PLATFORM(MAC) && !defined(__OBJC__)
40 class NSDictionary;
41 typedef int NSWritingDirection;
42 #endif
43
44 namespace WebCore {
45
46 class CSSStyleDeclaration;
47 class Clipboard;
48 class DeleteButtonController;
49 class EditCommand;
50 class EditorClient;
51 class EditorInternalCommand;
52 class Frame;
53 class HTMLElement;
54 class HitTestResult;
55 class KillRing;
56 class Pasteboard;
57 class SimpleFontData;
58 class Text;
59 class TextEvent;
60
61 struct CompositionUnderline {
62     CompositionUnderline() 
63         : startOffset(0), endOffset(0), thick(false) { }
64     CompositionUnderline(unsigned s, unsigned e, const Color& c, bool t) 
65         : startOffset(s), endOffset(e), color(c), thick(t) { }
66     unsigned startOffset;
67     unsigned endOffset;
68     Color color;
69     bool thick;
70 };
71
72 enum TriState { FalseTriState, TrueTriState, MixedTriState };
73 enum EditorCommandSource { CommandFromMenuOrKeyBinding, CommandFromDOM, CommandFromDOMWithUserInterface };
74
75 class Editor {
76 public:
77     Editor(Frame*);
78     ~Editor();
79
80     EditorClient* client() const;
81     Frame* frame() const { return m_frame; }
82     DeleteButtonController* deleteButtonController() const { return m_deleteButtonController.get(); }
83     EditCommand* lastEditCommand() { return m_lastEditCommand.get(); }
84
85     void handleKeyboardEvent(KeyboardEvent*);
86     void handleInputMethodKeydown(KeyboardEvent*);
87     bool handleTextEvent(TextEvent*);
88
89     bool canEdit() const;
90     bool canEditRichly() const;
91
92     bool canDHTMLCut();
93     bool canDHTMLCopy();
94     bool canDHTMLPaste();
95     bool tryDHTMLCopy();
96     bool tryDHTMLCut();
97     bool tryDHTMLPaste();
98
99     bool canCut() const;
100     bool canCopy() const;
101     bool canPaste() const;
102     bool canDelete() const;
103     bool canSmartCopyOrDelete();
104
105     void cut();
106     void copy();
107     void paste();
108     void pasteAsPlainText();
109     void performDelete();
110
111     void copyURL(const KURL&, const String&);
112     void copyImage(const HitTestResult&);
113
114     void indent();
115     void outdent();
116     void transpose();
117
118     bool shouldInsertFragment(PassRefPtr<DocumentFragment>, PassRefPtr<Range>, EditorInsertAction);
119     bool shouldInsertText(const String&, Range*, EditorInsertAction) const;
120     bool shouldShowDeleteInterface(HTMLElement*) const;
121     bool shouldDeleteRange(Range*) const;
122     bool shouldApplyStyle(CSSStyleDeclaration*, Range*);
123     
124     void respondToChangedSelection(const VisibleSelection& oldSelection);
125     void respondToChangedContents(const VisibleSelection& endingSelection);
126
127     TriState selectionHasStyle(CSSStyleDeclaration*) const;
128     String selectionStartCSSPropertyValue(int propertyID);
129     const SimpleFontData* fontForSelection(bool&) const;
130     WritingDirection textDirectionForSelection(bool&) const;
131     
132     TriState selectionUnorderedListState() const;
133     TriState selectionOrderedListState() const;
134     PassRefPtr<Node> insertOrderedList();
135     PassRefPtr<Node> insertUnorderedList();
136     bool canIncreaseSelectionListLevel();
137     bool canDecreaseSelectionListLevel();
138     PassRefPtr<Node> increaseSelectionListLevel();
139     PassRefPtr<Node> increaseSelectionListLevelOrdered();
140     PassRefPtr<Node> increaseSelectionListLevelUnordered();
141     void decreaseSelectionListLevel();
142    
143     void removeFormattingAndStyle();
144
145     void clearLastEditCommand();
146
147     bool deleteWithDirection(SelectionController::EDirection, TextGranularity, bool killRing, bool isTypingAction);
148     void deleteSelectionWithSmartDelete(bool smartDelete);
149     bool dispatchCPPEvent(const AtomicString&, ClipboardAccessPolicy);
150     
151     Node* removedAnchor() const { return m_removedAnchor.get(); }
152     void setRemovedAnchor(PassRefPtr<Node> n) { m_removedAnchor = n; }
153
154     void applyStyle(CSSStyleDeclaration*, EditAction = EditActionUnspecified);
155     void applyParagraphStyle(CSSStyleDeclaration*, EditAction = EditActionUnspecified);
156     void applyStyleToSelection(CSSStyleDeclaration*, EditAction);
157     void applyParagraphStyleToSelection(CSSStyleDeclaration*, EditAction);
158
159     void appliedEditing(PassRefPtr<EditCommand>);
160     void unappliedEditing(PassRefPtr<EditCommand>);
161     void reappliedEditing(PassRefPtr<EditCommand>);
162     
163     bool selectionStartHasStyle(CSSStyleDeclaration*) const;
164
165     bool clientIsEditable() const;
166     
167     void setShouldStyleWithCSS(bool flag) { m_shouldStyleWithCSS = flag; }
168     bool shouldStyleWithCSS() const { return m_shouldStyleWithCSS; }
169
170     class Command {
171     public:
172         Command();
173         Command(PassRefPtr<Frame>, const EditorInternalCommand*, EditorCommandSource);
174
175         bool execute(const String& parameter = String(), Event* triggeringEvent = 0) const;
176         bool execute(Event* triggeringEvent) const;
177
178         bool isSupported() const;
179         bool isEnabled(Event* triggeringEvent = 0) const;
180
181         TriState state(Event* triggeringEvent = 0) const;
182         String value(Event* triggeringEvent = 0) const;
183
184         bool isTextInsertion() const;
185
186     private:
187         RefPtr<Frame> m_frame;
188         const EditorInternalCommand* m_command;
189         EditorCommandSource m_source;
190     };
191     Command command(const String& commandName); // Default is CommandFromMenuOrKeyBinding.
192     Command command(const String& commandName, EditorCommandSource);
193
194     bool insertText(const String&, Event* triggeringEvent);
195     bool insertTextWithoutSendingTextEvent(const String&, bool selectInsertedText, Event* triggeringEvent);
196     bool insertLineBreak();
197     bool insertParagraphSeparator();
198     
199     bool isContinuousSpellCheckingEnabled();
200     void toggleContinuousSpellChecking();
201     bool isGrammarCheckingEnabled();
202     void toggleGrammarChecking();
203     void ignoreSpelling();
204     void learnSpelling();
205     int spellCheckerDocumentTag();
206     bool isSelectionUngrammatical();
207     bool isSelectionMisspelled();
208     Vector<String> guessesForMisspelledSelection();
209     Vector<String> guessesForUngrammaticalSelection();
210     Vector<String> guessesForMisspelledOrUngrammaticalSelection(bool& misspelled, bool& ungrammatical);
211     bool isSpellCheckingEnabledInFocusedNode() const;
212     bool isSpellCheckingEnabledFor(Node*) const;
213     void markMisspellingsAfterTypingToWord(const VisiblePosition &wordStart, const VisibleSelection& selectionAfterTyping);
214     void markMisspellings(const VisibleSelection&, RefPtr<Range>& firstMisspellingRange);
215     void markBadGrammar(const VisibleSelection&);
216     void markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelection, bool markGrammar, const VisibleSelection& grammarSelection);
217 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
218     void uppercaseWord();
219     void lowercaseWord();
220     void capitalizeWord();
221     void showSubstitutionsPanel();
222     bool substitutionsPanelIsShowing();
223     void toggleSmartInsertDelete();
224     bool isAutomaticQuoteSubstitutionEnabled();
225     void toggleAutomaticQuoteSubstitution();
226     bool isAutomaticLinkDetectionEnabled();
227     void toggleAutomaticLinkDetection();
228     bool isAutomaticDashSubstitutionEnabled();
229     void toggleAutomaticDashSubstitution();
230     bool isAutomaticTextReplacementEnabled();
231     void toggleAutomaticTextReplacement();
232     bool isAutomaticSpellingCorrectionEnabled();
233     void toggleAutomaticSpellingCorrection();
234     enum TextCheckingOptionFlags {
235         MarkSpelling = 1 << 0,
236         MarkGrammar = 1 << 1,
237         PerformReplacement = 1 << 2,
238         ShowCorrectionPanel = 1 << 3,
239     };
240     typedef unsigned TextCheckingOptions;
241
242     void markAllMisspellingsAndBadGrammarInRanges(TextCheckingOptions, Range* spellingRange, Range* grammarRange);
243     void changeBackToReplacedString(const String& replacedString);
244 #endif
245     void advanceToNextMisspelling(bool startBeforeSelection = false);
246     void showSpellingGuessPanel();
247     bool spellingPanelIsShowing();
248
249     bool shouldBeginEditing(Range*);
250     bool shouldEndEditing(Range*);
251
252     void clearUndoRedoOperations();
253     bool canUndo();
254     void undo();
255     bool canRedo();
256     void redo();
257
258     void didBeginEditing();
259     void didEndEditing();
260     void didWriteSelectionToPasteboard();
261     
262     void showFontPanel();
263     void showStylesPanel();
264     void showColorPanel();
265     void toggleBold();
266     void toggleUnderline();
267     void setBaseWritingDirection(WritingDirection);
268
269     // smartInsertDeleteEnabled and selectTrailingWhitespaceEnabled are 
270     // mutually exclusive, meaning that enabling one will disable the other.
271     bool smartInsertDeleteEnabled();
272     bool isSelectTrailingWhitespaceEnabled();
273     
274     bool hasBidiSelection() const;
275
276     // international text input composition
277     bool hasComposition() const { return m_compositionNode; }
278     void setComposition(const String&, const Vector<CompositionUnderline>&, unsigned selectionStart, unsigned selectionEnd);
279     void confirmComposition();
280     void confirmComposition(const String&); // if no existing composition, replaces selection
281     void confirmCompositionWithoutDisturbingSelection();
282     PassRefPtr<Range> compositionRange() const;
283     bool getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const;
284
285     // getting international text input composition state (for use by InlineTextBox)
286     Text* compositionNode() const { return m_compositionNode.get(); }
287     unsigned compositionStart() const { return m_compositionStart; }
288     unsigned compositionEnd() const { return m_compositionEnd; }
289     bool compositionUsesCustomUnderlines() const { return !m_customCompositionUnderlines.isEmpty(); }
290     const Vector<CompositionUnderline>& customCompositionUnderlines() const { return m_customCompositionUnderlines; }
291
292     bool ignoreCompositionSelectionChange() const { return m_ignoreCompositionSelectionChange; }
293
294     void setStartNewKillRingSequence(bool);
295
296     PassRefPtr<Range> rangeForPoint(const IntPoint& windowPoint);
297
298     void clear();
299
300     VisibleSelection selectionForCommand(Event*);
301
302     KillRing* killRing() const { return m_killRing.get(); }
303
304     EditingBehavior behavior() const;
305
306     PassRefPtr<Range> selectedRange();
307     
308     // We should make these functions private when their callers in Frame are moved over here to Editor
309     bool insideVisibleArea(const IntPoint&) const;
310     bool insideVisibleArea(Range*) const;
311
312     void addToKillRing(Range*, bool prepend);
313
314     void handleCancelOperation();
315     void startCorrectionPanelTimer(CorrectionPanelInfo::PanelType);
316     // If user confirmed a correction in the correction panel, correction has non-zero length, otherwise it means that user has dismissed the panel.
317     void handleCorrectionPanelResult(const String& correction);
318     bool isShowingCorrectionPanel();
319
320     void pasteAsFragment(PassRefPtr<DocumentFragment>, bool smartReplace, bool matchStyle);
321     void pasteAsPlainText(const String&, bool smartReplace);
322
323     // This is only called on the mac where paste is implemented primarily at the WebKit level.
324     void pasteAsPlainTextBypassingDHTML();
325  
326     void clearMisspellingsAndBadGrammar(const VisibleSelection&);
327     void markMisspellingsAndBadGrammar(const VisibleSelection&);
328
329     Node* findEventTargetFrom(const VisibleSelection& selection) const;
330
331     String selectedText() const;
332     bool findString(const String&, FindOptions);
333     // FIXME: Switch callers over to the FindOptions version and retire this one.
334     bool findString(const String&, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection);
335
336     const VisibleSelection& mark() const; // Mark, to be used as emacs uses it.
337     void setMark(const VisibleSelection&);
338
339     void computeAndSetTypingStyle(CSSStyleDeclaration* , EditAction = EditActionUnspecified);
340     void applyEditingStyleToBodyElement() const;
341     void applyEditingStyleToElement(Element*) const;
342
343     IntRect firstRectForRange(Range*) const;
344
345     void respondToChangedSelection(const VisibleSelection& oldSelection, bool closeTyping);
346     bool shouldChangeSelection(const VisibleSelection& oldSelection, const VisibleSelection& newSelection, EAffinity, bool stillSelecting) const;
347
348     RenderStyle* styleForSelectionStart(Node*& nodeToRemove) const;
349
350     unsigned countMatchesForText(const String&, FindOptions, unsigned limit, bool markMatches);
351     unsigned countMatchesForText(const String&, Range*, FindOptions, unsigned limit, bool markMatches);
352     bool markedTextMatchesAreHighlighted() const;
353     void setMarkedTextMatchesAreHighlighted(bool);
354
355     PassRefPtr<CSSMutableStyleDeclaration> selectionComputedStyle(bool& shouldUseFixedFontDefaultSize) const;
356
357     void textFieldDidBeginEditing(Element*);
358     void textFieldDidEndEditing(Element*);
359     void textDidChangeInTextField(Element*);
360     bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*);
361     void textWillBeDeletedInTextField(Element* input);
362     void textDidChangeInTextArea(Element*);
363
364 #if PLATFORM(MAC)
365     NSDictionary* fontAttributesForSelectionStart() const;
366     NSWritingDirection baseWritingDirectionForSelectionStart() const;
367     bool canCopyExcludingStandaloneImages();
368     void takeFindStringFromSelection();
369 #endif
370
371     bool selectionStartHasSpellingMarkerFor(int from, int length) const;
372     void removeSpellAndCorrectionMarkersFromWordsToBeEdited(bool doNotRemoveIfSelectionAtWordBoundary);
373
374 private:
375     Frame* m_frame;
376     OwnPtr<DeleteButtonController> m_deleteButtonController;
377     RefPtr<EditCommand> m_lastEditCommand;
378     RefPtr<Node> m_removedAnchor;
379     RefPtr<Text> m_compositionNode;
380     unsigned m_compositionStart;
381     unsigned m_compositionEnd;
382     Vector<CompositionUnderline> m_customCompositionUnderlines;
383     bool m_ignoreCompositionSelectionChange;
384     bool m_shouldStartNewKillRingSequence;
385     bool m_shouldStyleWithCSS;
386     OwnPtr<KillRing> m_killRing;
387     CorrectionPanelInfo m_correctionPanelInfo;
388     Timer<Editor> m_correctionPanelTimer;
389     bool m_correctionPanelIsDismissedByEditor;
390     VisibleSelection m_mark;
391     bool m_areMarkedTextMatchesHighlighted;
392
393     bool canDeleteRange(Range*) const;
394     bool canSmartReplaceWithPasteboard(Pasteboard*);
395     PassRefPtr<Clipboard> newGeneralClipboard(ClipboardAccessPolicy, Frame*);
396     void pasteAsPlainTextWithPasteboard(Pasteboard*);
397     void pasteWithPasteboard(Pasteboard*, bool allowPlainText);
398     void replaceSelectionWithFragment(PassRefPtr<DocumentFragment>, bool selectReplacement, bool smartReplace, bool matchStyle);
399     void replaceSelectionWithText(const String&, bool selectReplacement, bool smartReplace);
400     void writeSelectionToPasteboard(Pasteboard*);
401     void revealSelectionAfterEditingOperation();
402     void markMisspellingsOrBadGrammar(const VisibleSelection&, bool checkSpelling, RefPtr<Range>& firstMisspellingRange);
403
404     void selectComposition();
405     void confirmComposition(const String&, bool preserveSelection);
406     void setIgnoreCompositionSelectionChange(bool ignore);
407
408     PassRefPtr<Range> firstVisibleRange(const String&, FindOptions);
409     PassRefPtr<Range> lastVisibleRange(const String&, FindOptions);
410     PassRefPtr<Range> nextVisibleRange(Range*, const String&, FindOptions);
411
412     void changeSelectionAfterCommand(const VisibleSelection& newSelection, bool closeTyping, bool clearTypingStyle);
413     void correctionPanelTimerFired(Timer<Editor>*);
414     Node* findEventTargetFromSelection() const;
415     void stopCorrectionPanelTimer();
416     void dismissCorrectionPanel(ReasonForDismissingCorrectionPanel);
417     void applyCorrectionPanelInfo(const Vector<DocumentMarker::MarkerType>& markerTypesToAdd);
418 };
419
420 inline void Editor::setStartNewKillRingSequence(bool flag)
421 {
422     m_shouldStartNewKillRingSequence = flag;
423 }
424
425 inline const VisibleSelection& Editor::mark() const
426 {
427     return m_mark;
428 }
429
430 inline void Editor::setMark(const VisibleSelection& selection)
431 {
432     m_mark = selection;
433 }
434
435 inline bool Editor::markedTextMatchesAreHighlighted() const
436 {
437     return m_areMarkedTextMatchesHighlighted;
438 }
439
440
441 } // namespace WebCore
442
443 #endif // Editor_h