1 /*
2 * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include "config.h"
28 #include "EditorClientWx.h"
29
30 #include "EditCommand.h"
31 #include "Editor.h"
32 #include "FocusController.h"
33 #include "Frame.h"
34 #include "FrameView.h"
35 #include "KeyboardEvent.h"
36 #include "KeyboardCodes.h"
37 #include "NotImplemented.h"
38 #include "Page.h"
39 #include "PlatformKeyboardEvent.h"
40 #include "PlatformString.h"
41 #include "SelectionController.h"
42
43 #include "WebFrame.h"
44 #include "WebFramePrivate.h"
45 #include "WebView.h"
46 #include "WebViewPrivate.h"
47
48 #include <stdio.h>
49
50 namespace WebCore {
51
52 static const unsigned CtrlKey = 1 << 0;
53 static const unsigned AltKey = 1 << 1;
54 static const unsigned ShiftKey = 1 << 2;
55
56 struct KeyDownEntry {
57 unsigned virtualKey;
58 unsigned modifiers;
59 const char* name;
60 };
61
62 struct KeyPressEntry {
63 unsigned charCode;
64 unsigned modifiers;
65 const char* name;
66 };
67
68 static const KeyDownEntry keyDownEntries[] = {
69 { VK_LEFT, 0, "MoveLeft" },
70 { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" },
71 { VK_LEFT, CtrlKey, "MoveWordLeft" },
72 { VK_LEFT, CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection" },
73 { VK_RIGHT, 0, "MoveRight" },
74 { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" },
75 { VK_RIGHT, CtrlKey, "MoveWordRight" },
76 { VK_RIGHT, CtrlKey | ShiftKey, "MoveWordRightAndModifySelection" },
77 { VK_UP, 0, "MoveUp" },
78 { VK_UP, ShiftKey, "MoveUpAndModifySelection" },
79 { VK_PRIOR, ShiftKey, "MovePageUpAndModifySelection" },
80 { VK_DOWN, 0, "MoveDown" },
81 { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" },
82 { VK_NEXT, ShiftKey, "MovePageDownAndModifySelection" },
83 { VK_PRIOR, 0, "MovePageUp" },
84 { VK_NEXT, 0, "MovePageDown" },
85 { VK_HOME, 0, "MoveToBeginningOfLine" },
86 { VK_HOME, ShiftKey, "MoveToBeginningOfLineAndModifySelection" },
87 { VK_HOME, CtrlKey, "MoveToBeginningOfDocument" },
88 { VK_HOME, CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
89
90 { VK_END, 0, "MoveToEndOfLine" },
91 { VK_END, ShiftKey, "MoveToEndOfLineAndModifySelection" },
92 { VK_END, CtrlKey, "MoveToEndOfDocument" },
93 { VK_END, CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection" },
94
95 { VK_BACK, 0, "DeleteBackward" },
96 { VK_BACK, ShiftKey, "DeleteBackward" },
97 { VK_DELETE, 0, "DeleteForward" },
98 { VK_BACK, CtrlKey, "DeleteWordBackward" },
99 { VK_DELETE, CtrlKey, "DeleteWordForward" },
100
101 { 'B', CtrlKey, "ToggleBold" },
102 { 'I', CtrlKey, "ToggleItalic" },
103
104 { VK_ESCAPE, 0, "Cancel" },
105 //FIXME: this'll never happen. We can trash it or make it a normal period
106 { VK_OEM_PERIOD, CtrlKey, "Cancel" },
107 { VK_TAB, 0, "InsertTab" },
108 { VK_TAB, ShiftKey, "InsertBacktab" },
109 { VK_RETURN, 0, "InsertNewline" },
110 { VK_RETURN, CtrlKey, "InsertNewline" },
111 { VK_RETURN, AltKey, "InsertNewline" },
112 { VK_RETURN, AltKey | ShiftKey, "InsertNewline" },
113 { 'A', CtrlKey, "SelectAll" },
114 { 'Z', CtrlKey, "Undo" },
115 { 'Z', CtrlKey | ShiftKey, "Redo" },
116 };
117
118 static const KeyPressEntry keyPressEntries[] = {
119 { '\t', 0, "InsertTab" },
120 { '\t', ShiftKey, "InsertBacktab" },
121 { '\r', 0, "InsertNewline" },
122 { '\r', CtrlKey, "InsertNewline" },
123 { '\r', AltKey, "InsertNewline" },
124 { '\r', AltKey | ShiftKey, "InsertNewline" },
125 };
126
~EditorClientWx()127 EditorClientWx::~EditorClientWx()
128 {
129 m_page = NULL;
130 }
131
setPage(Page * page)132 void EditorClientWx::setPage(Page* page)
133 {
134 m_page = page;
135 }
136
pageDestroyed()137 void EditorClientWx::pageDestroyed()
138 {
139 delete this;
140 }
141
shouldDeleteRange(Range *)142 bool EditorClientWx::shouldDeleteRange(Range*)
143 {
144 notImplemented();
145 return true;
146 }
147
shouldShowDeleteInterface(HTMLElement *)148 bool EditorClientWx::shouldShowDeleteInterface(HTMLElement*)
149 {
150 notImplemented();
151 return false;
152 }
153
smartInsertDeleteEnabled()154 bool EditorClientWx::smartInsertDeleteEnabled()
155 {
156 notImplemented();
157 return false;
158 }
159
isSelectTrailingWhitespaceEnabled()160 bool EditorClientWx::isSelectTrailingWhitespaceEnabled()
161 {
162 notImplemented();
163 return false;
164 }
165
isContinuousSpellCheckingEnabled()166 bool EditorClientWx::isContinuousSpellCheckingEnabled()
167 {
168 notImplemented();
169 return false;
170 }
171
toggleContinuousSpellChecking()172 void EditorClientWx::toggleContinuousSpellChecking()
173 {
174 notImplemented();
175 }
176
isGrammarCheckingEnabled()177 bool EditorClientWx::isGrammarCheckingEnabled()
178 {
179 notImplemented();
180 return false;
181 }
182
toggleGrammarChecking()183 void EditorClientWx::toggleGrammarChecking()
184 {
185 notImplemented();
186 }
187
spellCheckerDocumentTag()188 int EditorClientWx::spellCheckerDocumentTag()
189 {
190 notImplemented();
191 return 0;
192 }
193
selectWordBeforeMenuEvent()194 bool EditorClientWx::selectWordBeforeMenuEvent()
195 {
196 notImplemented();
197 return false;
198 }
199
isEditable()200 bool EditorClientWx::isEditable()
201 {
202 Frame* frame = m_page->focusController()->focusedOrMainFrame();
203
204 if (frame) {
205 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->platformWidget());
206 if (webKitWin)
207 return webKitWin->IsEditable();
208 }
209 return false;
210 }
211
shouldBeginEditing(Range *)212 bool EditorClientWx::shouldBeginEditing(Range*)
213 {
214 notImplemented();
215 return true;
216 }
217
shouldEndEditing(Range *)218 bool EditorClientWx::shouldEndEditing(Range*)
219 {
220 notImplemented();
221 return true;
222 }
223
shouldInsertNode(Node *,Range *,EditorInsertAction)224 bool EditorClientWx::shouldInsertNode(Node*, Range*,
225 EditorInsertAction)
226 {
227 notImplemented();
228 return true;
229 }
230
shouldInsertText(const String &,Range *,EditorInsertAction)231 bool EditorClientWx::shouldInsertText(const String&, Range*,
232 EditorInsertAction)
233 {
234 notImplemented();
235 return true;
236 }
237
shouldApplyStyle(CSSStyleDeclaration *,Range *)238 bool EditorClientWx::shouldApplyStyle(CSSStyleDeclaration*,
239 Range*)
240 {
241 notImplemented();
242 return true;
243 }
244
shouldMoveRangeAfterDelete(Range *,Range *)245 bool EditorClientWx::shouldMoveRangeAfterDelete(Range*, Range*)
246 {
247 notImplemented();
248 return true;
249 }
250
shouldChangeSelectedRange(Range * fromRange,Range * toRange,EAffinity,bool stillSelecting)251 bool EditorClientWx::shouldChangeSelectedRange(Range* fromRange, Range* toRange,
252 EAffinity, bool stillSelecting)
253 {
254 notImplemented();
255 return true;
256 }
257
didBeginEditing()258 void EditorClientWx::didBeginEditing()
259 {
260 notImplemented();
261 }
262
respondToChangedContents()263 void EditorClientWx::respondToChangedContents()
264 {
265 notImplemented();
266 }
267
didEndEditing()268 void EditorClientWx::didEndEditing()
269 {
270 notImplemented();
271 }
272
didWriteSelectionToPasteboard()273 void EditorClientWx::didWriteSelectionToPasteboard()
274 {
275 notImplemented();
276 }
277
didSetSelectionTypesForPasteboard()278 void EditorClientWx::didSetSelectionTypesForPasteboard()
279 {
280 notImplemented();
281 }
282
registerCommandForUndo(PassRefPtr<EditCommand> command)283 void EditorClientWx::registerCommandForUndo(PassRefPtr<EditCommand> command)
284 {
285 Frame* frame = m_page->focusController()->focusedOrMainFrame();
286
287 if (frame) {
288 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->platformWidget());
289 if (webKitWin) {
290 webKitWin->GetMainFrame()->m_impl->undoStack.append(EditCommandWx(command));
291 }
292 }
293 }
294
registerCommandForRedo(PassRefPtr<EditCommand> command)295 void EditorClientWx::registerCommandForRedo(PassRefPtr<EditCommand> command)
296 {
297 Frame* frame = m_page->focusController()->focusedOrMainFrame();
298
299 if (frame) {
300 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->platformWidget());
301 if (webKitWin) {
302 webKitWin->GetMainFrame()->m_impl->redoStack.insert(0, EditCommandWx(command));
303 }
304 }
305 }
306
clearUndoRedoOperations()307 void EditorClientWx::clearUndoRedoOperations()
308 {
309 notImplemented();
310 }
311
canUndo() const312 bool EditorClientWx::canUndo() const
313 {
314 Frame* frame = m_page->focusController()->focusedOrMainFrame();
315
316 if (frame) {
317 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->platformWidget());
318 if (webKitWin && webKitWin->GetMainFrame()) {
319 return webKitWin->GetMainFrame()->m_impl->undoStack.size() != 0;
320 }
321 }
322 return false;
323 }
324
canRedo() const325 bool EditorClientWx::canRedo() const
326 {
327 Frame* frame = m_page->focusController()->focusedOrMainFrame();
328
329 if (frame) {
330 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->platformWidget());
331 if (webKitWin && webKitWin->GetMainFrame()) {
332 return webKitWin->GetMainFrame()->m_impl->redoStack.size() != 0;
333 }
334 }
335 return false;
336 }
337
undo()338 void EditorClientWx::undo()
339 {
340 Frame* frame = m_page->focusController()->focusedOrMainFrame();
341
342 if (frame) {
343 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->platformWidget());
344 if (webKitWin && webKitWin->GetMainFrame()) {
345 webKitWin->GetMainFrame()->m_impl->undoStack.last().editCommand()->unapply();
346 webKitWin->GetMainFrame()->m_impl->undoStack.removeLast();
347 }
348 }
349 }
350
redo()351 void EditorClientWx::redo()
352 {
353 Frame* frame = m_page->focusController()->focusedOrMainFrame();
354
355 if (frame) {
356 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->platformWidget());
357 if (webKitWin && webKitWin->GetMainFrame()) {
358 webKitWin->GetMainFrame()->m_impl->redoStack.first().editCommand()->reapply();
359 webKitWin->GetMainFrame()->m_impl->redoStack.remove(0);
360 }
361 }
362 }
363
handleEditingKeyboardEvent(KeyboardEvent * event)364 bool EditorClientWx::handleEditingKeyboardEvent(KeyboardEvent* event)
365 {
366 Node* node = event->target()->toNode();
367 ASSERT(node);
368 Frame* frame = node->document()->frame();
369 ASSERT(frame);
370
371 const PlatformKeyboardEvent* keyEvent = event->keyEvent();
372
373 //NB: this is what windows does, but they also have a keypress event for Alt+Enter which clearly won't get hit with this
374 if (!keyEvent || keyEvent->altKey()) // do not treat this as text input if Alt is down
375 return false;
376
377 Editor::Command command = frame->editor()->command(interpretKeyEvent(event));
378
379 if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
380 // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
381 // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or if not to let a CHAR event be generated
382 // (e.g. Tab that inserts a Tab character, or Enter).
383 return !command.isTextInsertion() && command.execute(event);
384 }
385
386 if (command.execute(event))
387 return true;
388
389 // Don't insert null or control characters as they can result in unexpected behaviour
390 if (event->charCode() < ' ')
391 return false;
392
393 return frame->editor()->insertText(event->keyEvent()->text(), event);
394 }
395
interpretKeyEvent(const KeyboardEvent * evt)396 const char* EditorClientWx::interpretKeyEvent(const KeyboardEvent* evt)
397 {
398 ASSERT(evt->keyEvent()->type() == PlatformKeyboardEvent::RawKeyDown || evt->keyEvent()->type() == PlatformKeyboardEvent::Char);
399
400 static HashMap<int, const char*>* keyDownCommandsMap = 0;
401 static HashMap<int, const char*>* keyPressCommandsMap = 0;
402
403 if (!keyDownCommandsMap) {
404 keyDownCommandsMap = new HashMap<int, const char*>;
405 keyPressCommandsMap = new HashMap<int, const char*>;
406
407 for (unsigned i = 0; i < WXSIZEOF(keyDownEntries); i++)
408 keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
409
410 for (unsigned i = 0; i < WXSIZEOF(keyPressEntries); i++)
411 keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
412 }
413
414 unsigned modifiers = 0;
415 if (evt->shiftKey())
416 modifiers |= ShiftKey;
417 if (evt->altKey())
418 modifiers |= AltKey;
419 if (evt->ctrlKey())
420 modifiers |= CtrlKey;
421
422 if (evt->keyEvent()->type() == PlatformKeyboardEvent::RawKeyDown) {
423 int mapKey = modifiers << 16 | evt->keyCode();
424 return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
425 }
426
427 int mapKey = modifiers << 16 | evt->charCode();
428 return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
429 }
430
431
handleInputMethodKeydown(KeyboardEvent * event)432 void EditorClientWx::handleInputMethodKeydown(KeyboardEvent* event)
433 {
434 // NOTE: we don't currently need to handle this. When key events occur,
435 // both this method and handleKeyboardEvent get a chance at handling them.
436 // We might use this method later on for IME-specific handling.
437 }
438
handleKeyboardEvent(KeyboardEvent * event)439 void EditorClientWx::handleKeyboardEvent(KeyboardEvent* event)
440 {
441 if (handleEditingKeyboardEvent(event))
442 event->setDefaultHandled();
443 }
444
textFieldDidBeginEditing(Element *)445 void EditorClientWx::textFieldDidBeginEditing(Element*)
446 {
447 notImplemented();
448 }
449
textFieldDidEndEditing(Element *)450 void EditorClientWx::textFieldDidEndEditing(Element*)
451 {
452 notImplemented();
453 }
454
textDidChangeInTextField(Element *)455 void EditorClientWx::textDidChangeInTextField(Element*)
456 {
457 notImplemented();
458 }
459
doTextFieldCommandFromEvent(Element *,KeyboardEvent *)460 bool EditorClientWx::doTextFieldCommandFromEvent(Element*, KeyboardEvent*)
461 {
462 notImplemented();
463 return false;
464 }
465
textWillBeDeletedInTextField(Element *)466 void EditorClientWx::textWillBeDeletedInTextField(Element*)
467 {
468 notImplemented();
469 }
470
textDidChangeInTextArea(Element *)471 void EditorClientWx::textDidChangeInTextArea(Element*)
472 {
473 notImplemented();
474 }
475
respondToChangedSelection()476 void EditorClientWx::respondToChangedSelection()
477 {
478 notImplemented();
479 }
480
ignoreWordInSpellDocument(const String &)481 void EditorClientWx::ignoreWordInSpellDocument(const String&)
482 {
483 notImplemented();
484 }
485
learnWord(const String &)486 void EditorClientWx::learnWord(const String&)
487 {
488 notImplemented();
489 }
490
checkSpellingOfString(const UChar *,int length,int * misspellingLocation,int * misspellingLength)491 void EditorClientWx::checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength)
492 {
493 notImplemented();
494 }
495
checkGrammarOfString(const UChar *,int length,Vector<GrammarDetail> &,int * badGrammarLocation,int * badGrammarLength)496 void EditorClientWx::checkGrammarOfString(const UChar*, int length, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength)
497 {
498 notImplemented();
499 }
500
updateSpellingUIWithGrammarString(const String &,const GrammarDetail & detail)501 void EditorClientWx::updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail)
502 {
503 notImplemented();
504 }
505
updateSpellingUIWithMisspelledWord(const String &)506 void EditorClientWx::updateSpellingUIWithMisspelledWord(const String&)
507 {
508 notImplemented();
509 }
510
showSpellingUI(bool show)511 void EditorClientWx::showSpellingUI(bool show)
512 {
513 notImplemented();
514 }
515
spellingUIIsShowing()516 bool EditorClientWx::spellingUIIsShowing()
517 {
518 notImplemented();
519 return false;
520 }
521
getGuessesForWord(const String &,Vector<String> & guesses)522 void EditorClientWx::getGuessesForWord(const String&, Vector<String>& guesses)
523 {
524 notImplemented();
525 }
526
getAutoCorrectSuggestionForMisspelledWord(const WebCore::String &)527 String EditorClientWx::getAutoCorrectSuggestionForMisspelledWord(const WebCore::String&)
528 {
529 notImplemented();
530 return String();
531 }
532
setInputMethodState(bool enabled)533 void EditorClientWx::setInputMethodState(bool enabled)
534 {
535 notImplemented();
536 }
537
538 }
539