|
1 /* |
|
2 * Copyright (C) 2006, 2007 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 #include "config.h" |
|
27 #include "WebKitDLL.h" |
|
28 #include "WebEditorClient.h" |
|
29 |
|
30 #include "IWebEditingDelegate.h" |
|
31 #include "IWebUndoTarget.h" |
|
32 #include "IWebURLResponse.h" |
|
33 #include "WebLocalizableStrings.h" |
|
34 #include "WebView.h" |
|
35 #include "DOMCoreClasses.h" |
|
36 #pragma warning(push, 0) |
|
37 #include <WebCore/BString.h> |
|
38 #include <WebCore/Document.h> |
|
39 #include <WebCore/EditCommand.h> |
|
40 #include <WebCore/HTMLElement.h> |
|
41 #include <WebCore/HTMLInputElement.h> |
|
42 #include <WebCore/HTMLNames.h> |
|
43 #include <WebCore/KeyboardEvent.h> |
|
44 #include <WebCore/PlatformKeyboardEvent.h> |
|
45 #include <WebCore/NotImplemented.h> |
|
46 #include <WebCore/Range.h> |
|
47 #pragma warning(pop) |
|
48 |
|
49 using namespace WebCore; |
|
50 using namespace HTMLNames; |
|
51 |
|
52 // {09A11D2B-FAFB-4ca0-A6F7-791EE8932C88} |
|
53 static const GUID IID_IWebUndoCommand = |
|
54 { 0x9a11d2b, 0xfafb, 0x4ca0, { 0xa6, 0xf7, 0x79, 0x1e, 0xe8, 0x93, 0x2c, 0x88 } }; |
|
55 |
|
56 class IWebUndoCommand : public IUnknown { |
|
57 public: |
|
58 virtual void execute() = 0; |
|
59 }; |
|
60 |
|
61 // WebEditorUndoTarget ------------------------------------------------------------- |
|
62 |
|
63 class WebEditorUndoTarget : public IWebUndoTarget |
|
64 { |
|
65 public: |
|
66 WebEditorUndoTarget(); |
|
67 |
|
68 // IUnknown |
|
69 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); |
|
70 virtual ULONG STDMETHODCALLTYPE AddRef(void); |
|
71 virtual ULONG STDMETHODCALLTYPE Release(void); |
|
72 |
|
73 // IWebUndoTarget |
|
74 virtual HRESULT STDMETHODCALLTYPE invoke( |
|
75 /* [in] */ BSTR actionName, |
|
76 /* [in] */ IUnknown *obj); |
|
77 |
|
78 private: |
|
79 ULONG m_refCount; |
|
80 }; |
|
81 |
|
82 WebEditorUndoTarget::WebEditorUndoTarget() |
|
83 : m_refCount(1) |
|
84 { |
|
85 } |
|
86 |
|
87 HRESULT STDMETHODCALLTYPE WebEditorUndoTarget::QueryInterface(REFIID riid, void** ppvObject) |
|
88 { |
|
89 *ppvObject = 0; |
|
90 if (IsEqualGUID(riid, IID_IUnknown)) |
|
91 *ppvObject = static_cast<IWebUndoTarget*>(this); |
|
92 else if (IsEqualGUID(riid, IID_IWebUndoTarget)) |
|
93 *ppvObject = static_cast<IWebUndoTarget*>(this); |
|
94 else |
|
95 return E_NOINTERFACE; |
|
96 |
|
97 AddRef(); |
|
98 return S_OK; |
|
99 } |
|
100 |
|
101 ULONG STDMETHODCALLTYPE WebEditorUndoTarget::AddRef(void) |
|
102 { |
|
103 return ++m_refCount; |
|
104 } |
|
105 |
|
106 ULONG STDMETHODCALLTYPE WebEditorUndoTarget::Release(void) |
|
107 { |
|
108 ULONG newRef = --m_refCount; |
|
109 if (!newRef) |
|
110 delete(this); |
|
111 |
|
112 return newRef; |
|
113 } |
|
114 |
|
115 HRESULT STDMETHODCALLTYPE WebEditorUndoTarget::invoke( |
|
116 /* [in] */ BSTR /*actionName*/, |
|
117 /* [in] */ IUnknown *obj) |
|
118 { |
|
119 IWebUndoCommand* undoCommand = 0; |
|
120 if (SUCCEEDED(obj->QueryInterface(IID_IWebUndoCommand, (void**)&undoCommand))) { |
|
121 undoCommand->execute(); |
|
122 undoCommand->Release(); |
|
123 } |
|
124 return S_OK; |
|
125 } |
|
126 |
|
127 // WebEditorClient ------------------------------------------------------------------ |
|
128 |
|
129 WebEditorClient::WebEditorClient(WebView* webView) |
|
130 : m_webView(webView) |
|
131 , m_undoTarget(0) |
|
132 { |
|
133 m_undoTarget = new WebEditorUndoTarget(); |
|
134 } |
|
135 |
|
136 WebEditorClient::~WebEditorClient() |
|
137 { |
|
138 if (m_undoTarget) |
|
139 m_undoTarget->Release(); |
|
140 } |
|
141 |
|
142 void WebEditorClient::pageDestroyed() |
|
143 { |
|
144 delete this; |
|
145 } |
|
146 |
|
147 bool WebEditorClient::isContinuousSpellCheckingEnabled() |
|
148 { |
|
149 BOOL enabled; |
|
150 if (FAILED(m_webView->isContinuousSpellCheckingEnabled(&enabled))) |
|
151 return false; |
|
152 return !!enabled; |
|
153 } |
|
154 |
|
155 void WebEditorClient::toggleContinuousSpellChecking() |
|
156 { |
|
157 m_webView->toggleContinuousSpellChecking(0); |
|
158 } |
|
159 |
|
160 bool WebEditorClient::isGrammarCheckingEnabled() |
|
161 { |
|
162 BOOL enabled; |
|
163 if (FAILED(m_webView->isGrammarCheckingEnabled(&enabled))) |
|
164 return false; |
|
165 return !!enabled; |
|
166 } |
|
167 |
|
168 void WebEditorClient::toggleGrammarChecking() |
|
169 { |
|
170 m_webView->toggleGrammarChecking(0); |
|
171 } |
|
172 |
|
173 static void initViewSpecificSpelling(IWebViewEditing* viewEditing) |
|
174 { |
|
175 // we just use this as a flag to indicate that we've spell checked the document |
|
176 // and need to close the spell checker out when the view closes. |
|
177 int tag; |
|
178 viewEditing->spellCheckerDocumentTag(&tag); |
|
179 } |
|
180 |
|
181 int WebEditorClient::spellCheckerDocumentTag() |
|
182 { |
|
183 // we don't use the concept of spelling tags |
|
184 notImplemented(); |
|
185 ASSERT_NOT_REACHED(); |
|
186 return 0; |
|
187 } |
|
188 |
|
189 bool WebEditorClient::shouldBeginEditing(Range*) |
|
190 { |
|
191 notImplemented(); |
|
192 return true; |
|
193 } |
|
194 |
|
195 bool WebEditorClient::shouldEndEditing(Range*) |
|
196 { |
|
197 notImplemented(); |
|
198 return true; |
|
199 } |
|
200 |
|
201 void WebEditorClient::didBeginEditing() |
|
202 { |
|
203 notImplemented(); |
|
204 } |
|
205 |
|
206 void WebEditorClient::respondToChangedContents() |
|
207 { |
|
208 notImplemented(); |
|
209 } |
|
210 |
|
211 void WebEditorClient::respondToChangedSelection() |
|
212 { |
|
213 m_webView->selectionChanged(); |
|
214 } |
|
215 |
|
216 void WebEditorClient::didEndEditing() |
|
217 { |
|
218 notImplemented(); |
|
219 } |
|
220 |
|
221 void WebEditorClient::didWriteSelectionToPasteboard() |
|
222 { |
|
223 notImplemented(); |
|
224 } |
|
225 |
|
226 void WebEditorClient::didSetSelectionTypesForPasteboard() |
|
227 { |
|
228 notImplemented(); |
|
229 } |
|
230 |
|
231 bool WebEditorClient::shouldDeleteRange(Range* /*range*/) |
|
232 { |
|
233 notImplemented(); |
|
234 return true; |
|
235 |
|
236 // FIXME: calling m_webView->editingDelegate() will cause an assertion failure so we don't want to enable this code until that's implemented. |
|
237 //BOOL result = false; |
|
238 //IWebViewEditingDelegate* editingDelegate; |
|
239 //// FIXME: DOMRange needs to be implemented before anything meaningful can be done here |
|
240 //IDOMRange* domRange(0); |
|
241 //if (SUCCEEDED(m_webView->editingDelegate(&editingDelegate))) { |
|
242 // editingDelegate->shouldDeleteDOMRange(m_webView, domRange, &result); |
|
243 // editingDelegate->Release(); |
|
244 //} |
|
245 //return !!result; |
|
246 } |
|
247 |
|
248 bool WebEditorClient::shouldInsertNode(Node* /*node*/, Range* /*replacingRange*/, EditorInsertAction /*givenAction*/) |
|
249 { |
|
250 notImplemented(); |
|
251 return true; |
|
252 } |
|
253 |
|
254 bool WebEditorClient::shouldInsertText(String /*str*/, Range* /* replacingRange */, EditorInsertAction /*givenAction*/) |
|
255 { |
|
256 notImplemented(); |
|
257 return true; |
|
258 |
|
259 // FIXME: calling m_webView->editingDelegate() will cause an assertion failure so we don't want to enable this code until that's implemented. |
|
260 //BOOL result = false; |
|
261 //IWebViewEditingDelegate* editingDelegate; |
|
262 //// FIXME: DOMRange needs to be implemented before anything meaningful can be done here |
|
263 //IDOMRange* domRange(0); // make a DOMRange from replacingRange |
|
264 //BString text(str); |
|
265 //if (SUCCEEDED(m_webView->editingDelegate(&editingDelegate))) { |
|
266 // editingDelegate->shouldInsertText(m_webView, text, domRange, (WebViewInsertAction) givenAction, &result); |
|
267 // editingDelegate->Release(); |
|
268 //} |
|
269 //return !!result; |
|
270 } |
|
271 |
|
272 //bool WebEditorClient::shouldChangeSelectedRange(Range *currentRange, Range *toProposedRange, SelectionAffinity selectionAffinity, bool stillSelecting) |
|
273 //{ notImplemented(); return false; } |
|
274 |
|
275 bool WebEditorClient::shouldApplyStyle(CSSStyleDeclaration* /*style*/, Range* /*toElementsInDOMRange*/) |
|
276 { notImplemented(); return true; } |
|
277 |
|
278 bool WebEditorClient::shouldMoveRangeAfterDelete(Range* /*range*/, Range* /*rangeToBeReplaced*/) |
|
279 { notImplemented(); return true; } |
|
280 |
|
281 bool WebEditorClient::shouldChangeTypingStyle(CSSStyleDeclaration* /*currentStyle*/, CSSStyleDeclaration* /*toProposedStyle*/) |
|
282 { notImplemented(); return false; } |
|
283 |
|
284 void WebEditorClient::webViewDidChangeTypingStyle(WebNotification* /*notification*/) |
|
285 { notImplemented(); } |
|
286 |
|
287 void WebEditorClient::webViewDidChangeSelection(WebNotification* /*notification*/) |
|
288 { notImplemented(); } |
|
289 |
|
290 bool WebEditorClient::shouldShowDeleteInterface(HTMLElement* /*element*/) |
|
291 { notImplemented(); return false; } |
|
292 |
|
293 bool WebEditorClient::smartInsertDeleteEnabled(void) |
|
294 { |
|
295 BOOL enabled = FALSE; |
|
296 m_webView->smartInsertDeleteEnabled(&enabled); |
|
297 return !!enabled; |
|
298 } |
|
299 |
|
300 bool WebEditorClient::shouldChangeSelectedRange(WebCore::Range*, WebCore::Range*, WebCore::EAffinity, bool) |
|
301 { notImplemented(); return true; } |
|
302 |
|
303 void WebEditorClient::textFieldDidBeginEditing(Element* e) |
|
304 { |
|
305 IWebFormDelegate* formDelegate; |
|
306 if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) { |
|
307 IDOMElement* domElement = DOMElement::createInstance(e); |
|
308 if (domElement) { |
|
309 IDOMHTMLInputElement* domInputElement; |
|
310 if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) { |
|
311 formDelegate->textFieldDidBeginEditing(domInputElement, kit(e->document()->frame())); |
|
312 domInputElement->Release(); |
|
313 } |
|
314 domElement->Release(); |
|
315 } |
|
316 formDelegate->Release(); |
|
317 } |
|
318 } |
|
319 |
|
320 void WebEditorClient::textFieldDidEndEditing(Element* e) |
|
321 { |
|
322 IWebFormDelegate* formDelegate; |
|
323 if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) { |
|
324 IDOMElement* domElement = DOMElement::createInstance(e); |
|
325 if (domElement) { |
|
326 IDOMHTMLInputElement* domInputElement; |
|
327 if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) { |
|
328 formDelegate->textFieldDidEndEditing(domInputElement, kit(e->document()->frame())); |
|
329 domInputElement->Release(); |
|
330 } |
|
331 domElement->Release(); |
|
332 } |
|
333 formDelegate->Release(); |
|
334 } |
|
335 } |
|
336 |
|
337 void WebEditorClient::textDidChangeInTextField(Element* e) |
|
338 { |
|
339 IWebFormDelegate* formDelegate; |
|
340 if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) { |
|
341 IDOMElement* domElement = DOMElement::createInstance(e); |
|
342 if (domElement) { |
|
343 IDOMHTMLInputElement* domInputElement; |
|
344 if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) { |
|
345 formDelegate->textDidChangeInTextField(domInputElement, kit(e->document()->frame())); |
|
346 domInputElement->Release(); |
|
347 } |
|
348 domElement->Release(); |
|
349 } |
|
350 formDelegate->Release(); |
|
351 } |
|
352 } |
|
353 |
|
354 bool WebEditorClient::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke) |
|
355 { |
|
356 BOOL result = FALSE; |
|
357 IWebFormDelegate* formDelegate; |
|
358 if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) { |
|
359 IDOMElement* domElement = DOMElement::createInstance(e); |
|
360 if (domElement) { |
|
361 IDOMHTMLInputElement* domInputElement; |
|
362 if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) { |
|
363 String command = m_webView->interpretKeyEvent(ke); |
|
364 // We allow empty commands here because the app code actually depends on this being called for all key presses. |
|
365 // We may want to revisit this later because it doesn't really make sense to send an empty command. |
|
366 formDelegate->doPlatformCommand(domInputElement, BString(command), kit(e->document()->frame()), &result); |
|
367 domInputElement->Release(); |
|
368 } |
|
369 domElement->Release(); |
|
370 } |
|
371 formDelegate->Release(); |
|
372 } |
|
373 return !!result; |
|
374 } |
|
375 |
|
376 void WebEditorClient::textWillBeDeletedInTextField(Element* e) |
|
377 { |
|
378 // We're using the deleteBackward command for all deletion operations since the autofill code treats all deletions the same way. |
|
379 IWebFormDelegate* formDelegate; |
|
380 if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) { |
|
381 IDOMElement* domElement = DOMElement::createInstance(e); |
|
382 if (domElement) { |
|
383 IDOMHTMLInputElement* domInputElement; |
|
384 if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) { |
|
385 BOOL result; |
|
386 formDelegate->doPlatformCommand(domInputElement, BString("BackwardDelete"), kit(e->document()->frame()), &result); |
|
387 domInputElement->Release(); |
|
388 } |
|
389 domElement->Release(); |
|
390 } |
|
391 formDelegate->Release(); |
|
392 } |
|
393 } |
|
394 |
|
395 void WebEditorClient::textDidChangeInTextArea(Element* e) |
|
396 { |
|
397 IWebFormDelegate* formDelegate; |
|
398 if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) { |
|
399 IDOMElement* domElement = DOMElement::createInstance(e); |
|
400 if (domElement) { |
|
401 IDOMHTMLTextAreaElement* domTextAreaElement; |
|
402 if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLTextAreaElement, (void**)&domTextAreaElement))) { |
|
403 formDelegate->textDidChangeInTextArea(domTextAreaElement, kit(e->document()->frame())); |
|
404 domTextAreaElement->Release(); |
|
405 } |
|
406 domElement->Release(); |
|
407 } |
|
408 formDelegate->Release(); |
|
409 } |
|
410 } |
|
411 |
|
412 class WebEditorUndoCommand : public IWebUndoCommand |
|
413 { |
|
414 public: |
|
415 WebEditorUndoCommand(PassRefPtr<EditCommand> editCommand, bool isUndo); |
|
416 void execute(); |
|
417 |
|
418 // IUnknown |
|
419 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); |
|
420 virtual ULONG STDMETHODCALLTYPE AddRef(void); |
|
421 virtual ULONG STDMETHODCALLTYPE Release(void); |
|
422 |
|
423 private: |
|
424 ULONG m_refCount; |
|
425 RefPtr<EditCommand> m_editCommand; |
|
426 bool m_isUndo; |
|
427 }; |
|
428 |
|
429 WebEditorUndoCommand::WebEditorUndoCommand(PassRefPtr<EditCommand> editCommand, bool isUndo) |
|
430 : m_editCommand(editCommand) |
|
431 , m_isUndo(isUndo) |
|
432 , m_refCount(1) |
|
433 { |
|
434 } |
|
435 |
|
436 void WebEditorUndoCommand::execute() |
|
437 { |
|
438 if (m_isUndo) |
|
439 m_editCommand->unapply(); |
|
440 else |
|
441 m_editCommand->reapply(); |
|
442 } |
|
443 |
|
444 HRESULT STDMETHODCALLTYPE WebEditorUndoCommand::QueryInterface(REFIID riid, void** ppvObject) |
|
445 { |
|
446 *ppvObject = 0; |
|
447 if (IsEqualGUID(riid, IID_IUnknown)) |
|
448 *ppvObject = static_cast<IWebUndoCommand*>(this); |
|
449 else if (IsEqualGUID(riid, IID_IWebUndoCommand)) |
|
450 *ppvObject = static_cast<IWebUndoCommand*>(this); |
|
451 else |
|
452 return E_NOINTERFACE; |
|
453 |
|
454 AddRef(); |
|
455 return S_OK; |
|
456 } |
|
457 |
|
458 ULONG STDMETHODCALLTYPE WebEditorUndoCommand::AddRef(void) |
|
459 { |
|
460 return ++m_refCount; |
|
461 } |
|
462 |
|
463 ULONG STDMETHODCALLTYPE WebEditorUndoCommand::Release(void) |
|
464 { |
|
465 ULONG newRef = --m_refCount; |
|
466 if (!newRef) |
|
467 delete(this); |
|
468 |
|
469 return newRef; |
|
470 } |
|
471 |
|
472 static LPCTSTR undoNameForEditAction(EditAction editAction) |
|
473 { |
|
474 switch (editAction) { |
|
475 case EditActionUnspecified: return 0; |
|
476 case EditActionSetColor: return LPCTSTR_UI_STRING_KEY("Set Color", "Set Color (Undo action name)", "Undo action name"); |
|
477 case EditActionSetBackgroundColor: return LPCTSTR_UI_STRING_KEY("Set Background Color", "Set Background Color (Undo action name)", "Undo action name"); |
|
478 case EditActionTurnOffKerning: return LPCTSTR_UI_STRING_KEY("Turn Off Kerning", "Turn Off Kerning (Undo action name)", "Undo action name"); |
|
479 case EditActionTightenKerning: return LPCTSTR_UI_STRING_KEY("Tighten Kerning", "Tighten Kerning (Undo action name)", "Undo action name"); |
|
480 case EditActionLoosenKerning: return LPCTSTR_UI_STRING_KEY("Loosen Kerning", "Loosen Kerning (Undo action name)", "Undo action name"); |
|
481 case EditActionUseStandardKerning: return LPCTSTR_UI_STRING_KEY("Use Standard Kerning", "Use Standard Kerning (Undo action name)", "Undo action name"); |
|
482 case EditActionTurnOffLigatures: return LPCTSTR_UI_STRING_KEY("Turn Off Ligatures", "Turn Off Ligatures (Undo action name)", "Undo action name"); |
|
483 case EditActionUseStandardLigatures: return LPCTSTR_UI_STRING_KEY("Use Standard Ligatures", "Use Standard Ligatures (Undo action name)", "Undo action name"); |
|
484 case EditActionUseAllLigatures: return LPCTSTR_UI_STRING_KEY("Use All Ligatures", "Use All Ligatures (Undo action name)", "Undo action name"); |
|
485 case EditActionRaiseBaseline: return LPCTSTR_UI_STRING_KEY("Raise Baseline", "Raise Baseline (Undo action name)", "Undo action name"); |
|
486 case EditActionLowerBaseline: return LPCTSTR_UI_STRING_KEY("Lower Baseline", "Lower Baseline (Undo action name)", "Undo action name"); |
|
487 case EditActionSetTraditionalCharacterShape: return LPCTSTR_UI_STRING_KEY("Set Traditional Character Shape", "Set Traditional Character Shape (Undo action name)", "Undo action name"); |
|
488 case EditActionSetFont: return LPCTSTR_UI_STRING_KEY("Set Font", "Set Font (Undo action name)", "Undo action name"); |
|
489 case EditActionChangeAttributes: return LPCTSTR_UI_STRING_KEY("Change Attributes", "Change Attributes (Undo action name)", "Undo action name"); |
|
490 case EditActionAlignLeft: return LPCTSTR_UI_STRING_KEY("Align Left", "Align Left (Undo action name)", "Undo action name"); |
|
491 case EditActionAlignRight: return LPCTSTR_UI_STRING_KEY("Align Right", "Align Right (Undo action name)", "Undo action name"); |
|
492 case EditActionCenter: return LPCTSTR_UI_STRING_KEY("Center", "Center (Undo action name)", "Undo action name"); |
|
493 case EditActionJustify: return LPCTSTR_UI_STRING_KEY("Justify", "Justify (Undo action name)", "Undo action name"); |
|
494 case EditActionSetWritingDirection: return LPCTSTR_UI_STRING_KEY("Set Writing Direction", "Set Writing Direction (Undo action name)", "Undo action name"); |
|
495 case EditActionSubscript: return LPCTSTR_UI_STRING_KEY("Subscript", "Subscript (Undo action name)", "Undo action name"); |
|
496 case EditActionSuperscript: return LPCTSTR_UI_STRING_KEY("Superscript", "Superscript (Undo action name)", "Undo action name"); |
|
497 case EditActionUnderline: return LPCTSTR_UI_STRING_KEY("Underline", "Underline (Undo action name)", "Undo action name"); |
|
498 case EditActionOutline: return LPCTSTR_UI_STRING_KEY("Outline", "Outline (Undo action name)", "Undo action name"); |
|
499 case EditActionUnscript: return LPCTSTR_UI_STRING_KEY("Unscript", "Unscript (Undo action name)", "Undo action name"); |
|
500 case EditActionDrag: return LPCTSTR_UI_STRING_KEY("Drag", "Drag (Undo action name)", "Undo action name"); |
|
501 case EditActionCut: return LPCTSTR_UI_STRING_KEY("Cut", "Cut (Undo action name)", "Undo action name"); |
|
502 case EditActionPaste: return LPCTSTR_UI_STRING_KEY("Paste", "Paste (Undo action name)", "Undo action name"); |
|
503 case EditActionPasteFont: return LPCTSTR_UI_STRING_KEY("Paste Font", "Paste Font (Undo action name)", "Undo action name"); |
|
504 case EditActionPasteRuler: return LPCTSTR_UI_STRING_KEY("Paste Ruler", "Paste Ruler (Undo action name)", "Undo action name"); |
|
505 case EditActionTyping: return LPCTSTR_UI_STRING_KEY("Typing", "Typing (Undo action name)", "Undo action name"); |
|
506 case EditActionCreateLink: return LPCTSTR_UI_STRING_KEY("Create Link", "Create Link (Undo action name)", "Undo action name"); |
|
507 case EditActionUnlink: return LPCTSTR_UI_STRING_KEY("Unlink", "Unlink (Undo action name)", "Undo action name"); |
|
508 case EditActionInsertList: return LPCTSTR_UI_STRING_KEY("Insert List", "Insert List (Undo action name)", "Undo action name"); |
|
509 case EditActionFormatBlock: return LPCTSTR_UI_STRING_KEY("Formatting", "Format Block (Undo action name)", "Undo action name"); |
|
510 case EditActionIndent: return LPCTSTR_UI_STRING_KEY("Indent", "Indent (Undo action name)", "Undo action name"); |
|
511 case EditActionOutdent: return LPCTSTR_UI_STRING_KEY("Outdent", "Outdent (Undo action name)", "Undo action name"); |
|
512 } |
|
513 return 0; |
|
514 } |
|
515 |
|
516 void WebEditorClient::registerCommandForUndo(PassRefPtr<EditCommand> command) |
|
517 { |
|
518 IWebUIDelegate* uiDelegate = 0; |
|
519 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { |
|
520 LPCTSTR actionName = undoNameForEditAction(command->editingAction()); |
|
521 WebEditorUndoCommand* undoCommand = new WebEditorUndoCommand(command, true); |
|
522 if (!undoCommand) |
|
523 return; |
|
524 uiDelegate->registerUndoWithTarget(m_undoTarget, 0, undoCommand); |
|
525 undoCommand->Release(); // the undo manager owns the reference |
|
526 BSTR actionNameBSTR = SysAllocString(actionName); |
|
527 if (actionNameBSTR) { |
|
528 uiDelegate->setActionTitle(actionNameBSTR); |
|
529 SysFreeString(actionNameBSTR); |
|
530 } |
|
531 uiDelegate->Release(); |
|
532 } |
|
533 } |
|
534 |
|
535 void WebEditorClient::registerCommandForRedo(PassRefPtr<EditCommand> command) |
|
536 { |
|
537 IWebUIDelegate* uiDelegate = 0; |
|
538 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { |
|
539 WebEditorUndoCommand* undoCommand = new WebEditorUndoCommand(command, false); |
|
540 if (!undoCommand) |
|
541 return; |
|
542 uiDelegate->registerUndoWithTarget(m_undoTarget, 0, undoCommand); |
|
543 undoCommand->Release(); // the undo manager owns the reference |
|
544 uiDelegate->Release(); |
|
545 } |
|
546 } |
|
547 |
|
548 void WebEditorClient::clearUndoRedoOperations() |
|
549 { |
|
550 IWebUIDelegate* uiDelegate = 0; |
|
551 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { |
|
552 uiDelegate->removeAllActionsWithTarget(m_undoTarget); |
|
553 uiDelegate->Release(); |
|
554 } |
|
555 } |
|
556 |
|
557 bool WebEditorClient::canUndo() const |
|
558 { |
|
559 BOOL result = FALSE; |
|
560 IWebUIDelegate* uiDelegate = 0; |
|
561 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { |
|
562 uiDelegate->canUndo(&result); |
|
563 uiDelegate->Release(); |
|
564 } |
|
565 return !!result; |
|
566 } |
|
567 |
|
568 bool WebEditorClient::canRedo() const |
|
569 { |
|
570 BOOL result = FALSE; |
|
571 IWebUIDelegate* uiDelegate = 0; |
|
572 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { |
|
573 uiDelegate->canRedo(&result); |
|
574 uiDelegate->Release(); |
|
575 } |
|
576 return !!result; |
|
577 } |
|
578 |
|
579 void WebEditorClient::undo() |
|
580 { |
|
581 IWebUIDelegate* uiDelegate = 0; |
|
582 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { |
|
583 uiDelegate->undo(); |
|
584 uiDelegate->Release(); |
|
585 } |
|
586 } |
|
587 |
|
588 void WebEditorClient::redo() |
|
589 { |
|
590 IWebUIDelegate* uiDelegate = 0; |
|
591 if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) { |
|
592 uiDelegate->redo(); |
|
593 uiDelegate->Release(); |
|
594 } |
|
595 } |
|
596 |
|
597 void WebEditorClient::handleKeypress(KeyboardEvent* evt) |
|
598 { |
|
599 if (m_webView->handleEditingKeyboardEvent(evt)) |
|
600 evt->setDefaultHandled(); |
|
601 } |
|
602 |
|
603 void WebEditorClient::handleInputMethodKeypress(KeyboardEvent* evt) |
|
604 { |
|
605 if (m_webView->inIMEKeyDown()) |
|
606 evt->setDefaultHandled(); |
|
607 } |
|
608 |
|
609 bool WebEditorClient::isEditable() |
|
610 { |
|
611 return false; |
|
612 } |
|
613 |
|
614 void WebEditorClient::ignoreWordInSpellDocument(const String& word) |
|
615 { |
|
616 COMPtr<IWebEditingDelegate> ed; |
|
617 if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get()) |
|
618 return; |
|
619 |
|
620 initViewSpecificSpelling(m_webView); |
|
621 ed->ignoreWordInSpellDocument(m_webView, BString(word)); |
|
622 } |
|
623 |
|
624 void WebEditorClient::learnWord(const String& word) |
|
625 { |
|
626 COMPtr<IWebEditingDelegate> ed; |
|
627 if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get()) |
|
628 return; |
|
629 |
|
630 ed->learnWord(BString(word)); |
|
631 } |
|
632 |
|
633 void WebEditorClient::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength) |
|
634 { |
|
635 *misspellingLocation = -1; |
|
636 *misspellingLength = 0; |
|
637 |
|
638 COMPtr<IWebEditingDelegate> ed; |
|
639 if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get()) |
|
640 return; |
|
641 |
|
642 initViewSpecificSpelling(m_webView); |
|
643 ed->checkSpellingOfString(m_webView, text, length, misspellingLocation, misspellingLength); |
|
644 } |
|
645 |
|
646 void WebEditorClient::checkGrammarOfString(const UChar* text, int length, Vector<GrammarDetail>& details, int* badGrammarLocation, int* badGrammarLength) |
|
647 { |
|
648 details.clear(); |
|
649 *badGrammarLocation = -1; |
|
650 *badGrammarLength = 0; |
|
651 |
|
652 COMPtr<IWebEditingDelegate> ed; |
|
653 if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get()) |
|
654 return; |
|
655 |
|
656 initViewSpecificSpelling(m_webView); |
|
657 COMPtr<IEnumWebGrammarDetails> enumDetailsObj; |
|
658 if (FAILED(ed->checkGrammarOfString(m_webView, text, length, &enumDetailsObj, badGrammarLocation, badGrammarLength))) |
|
659 return; |
|
660 |
|
661 while (true) { |
|
662 ULONG fetched; |
|
663 COMPtr<IWebGrammarDetail> detailObj; |
|
664 if (enumDetailsObj->Next(1, &detailObj, &fetched) != S_OK) |
|
665 break; |
|
666 |
|
667 GrammarDetail detail; |
|
668 if (FAILED(detailObj->length(&detail.length))) |
|
669 continue; |
|
670 if (FAILED(detailObj->location(&detail.location))) |
|
671 continue; |
|
672 BSTR userDesc; |
|
673 if (FAILED(detailObj->userDescription(&userDesc))) |
|
674 continue; |
|
675 detail.userDescription = String(userDesc, SysStringLen(userDesc)); |
|
676 SysFreeString(userDesc); |
|
677 |
|
678 COMPtr<IEnumSpellingGuesses> enumGuessesObj; |
|
679 if (FAILED(detailObj->guesses(&enumGuessesObj))) |
|
680 continue; |
|
681 while (true) { |
|
682 BSTR guess; |
|
683 if (enumGuessesObj->Next(1, &guess, &fetched) != S_OK) |
|
684 break; |
|
685 detail.guesses.append(String(guess, SysStringLen(guess))); |
|
686 SysFreeString(guess); |
|
687 } |
|
688 |
|
689 details.append(detail); |
|
690 } |
|
691 } |
|
692 |
|
693 void WebEditorClient::updateSpellingUIWithGrammarString(const String& string, const WebCore::GrammarDetail& detail) |
|
694 { |
|
695 COMPtr<IWebEditingDelegate> ed; |
|
696 if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get()) |
|
697 return; |
|
698 |
|
699 Vector<BSTR> guessesBSTRs; |
|
700 for (unsigned i = 0; i < detail.guesses.size(); i++) { |
|
701 BString guess(detail.guesses[i]); |
|
702 guessesBSTRs.append(guess.release()); |
|
703 } |
|
704 BString userDescriptionBSTR(detail.userDescription); |
|
705 ed->updateSpellingUIWithGrammarString(BString(string), detail.location, detail.length, userDescriptionBSTR, guessesBSTRs.data(), (int)guessesBSTRs.size()); |
|
706 for (unsigned i = 0; i < guessesBSTRs.size(); i++) |
|
707 SysFreeString(guessesBSTRs[i]); |
|
708 } |
|
709 |
|
710 void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& word) |
|
711 { |
|
712 COMPtr<IWebEditingDelegate> ed; |
|
713 if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get()) |
|
714 return; |
|
715 |
|
716 ed->updateSpellingUIWithMisspelledWord(BString(word)); |
|
717 } |
|
718 |
|
719 void WebEditorClient::showSpellingUI(bool show) |
|
720 { |
|
721 COMPtr<IWebEditingDelegate> ed; |
|
722 if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get()) |
|
723 return; |
|
724 |
|
725 ed->showSpellingUI(show); |
|
726 } |
|
727 |
|
728 bool WebEditorClient::spellingUIIsShowing() |
|
729 { |
|
730 COMPtr<IWebEditingDelegate> ed; |
|
731 if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get()) |
|
732 return false; |
|
733 |
|
734 BOOL showing; |
|
735 if (FAILED(ed->spellingUIIsShowing(&showing))) |
|
736 return false; |
|
737 |
|
738 return !!showing; |
|
739 } |
|
740 |
|
741 void WebEditorClient::getGuessesForWord(const String& word, Vector<String>& guesses) |
|
742 { |
|
743 guesses.clear(); |
|
744 |
|
745 COMPtr<IWebEditingDelegate> ed; |
|
746 if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get()) |
|
747 return; |
|
748 |
|
749 COMPtr<IEnumSpellingGuesses> enumGuessesObj; |
|
750 if (FAILED(ed->guessesForWord(BString(word), &enumGuessesObj))) |
|
751 return; |
|
752 |
|
753 while (true) { |
|
754 ULONG fetched; |
|
755 BSTR guess; |
|
756 if (enumGuessesObj->Next(1, &guess, &fetched) != S_OK) |
|
757 break; |
|
758 guesses.append(String(guess, SysStringLen(guess))); |
|
759 SysFreeString(guess); |
|
760 } |
|
761 } |
|
762 |
|
763 void WebEditorClient::setInputMethodState(bool enabled) |
|
764 { |
|
765 m_webView->setInputMethodState(enabled); |
|
766 } |