1/*
2 *  Copyright (C) 2007 Alp Toker <alp@atoker.com>
3 *  Copyright (C) 2008 Nuanti Ltd.
4 *  Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia
5 *  Copyright (C) 2009-2010 ProFUSION embedded systems
6 *  Copyright (C) 2009-2010 Samsung Electronics
7 *  Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
8 *
9 *  This library is free software; you can redistribute it and/or
10 *  modify it under the terms of the GNU Lesser General Public
11 *  License as published by the Free Software Foundation; either
12 *  version 2 of the License, or (at your option) any later version.
13 *
14 *  This library is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 *  Lesser General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public
20 *  License along with this library; if not, write to the Free Software
21 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 */
23
24#include "config.h"
25#include "EditorClientWinCE.h"
26
27#include "EditCommand.h"
28#include "Frame.h"
29#include "KeyboardEvent.h"
30#include "NotImplemented.h"
31#include "PlatformKeyboardEvent.h"
32#include "Settings.h"
33
34using namespace WebCore;
35
36namespace WebKit {
37
38EditorClientWinCE::EditorClientWinCE(WebView* webView)
39    : m_webView(webView)
40{
41}
42
43EditorClientWinCE::~EditorClientWinCE()
44{
45}
46
47void EditorClientWinCE::setInputMethodState(bool active)
48{
49    notImplemented();
50}
51
52bool EditorClientWinCE::shouldDeleteRange(Range*)
53{
54    notImplemented();
55    return true;
56}
57
58bool EditorClientWinCE::shouldShowDeleteInterface(HTMLElement*)
59{
60    return false;
61}
62
63bool EditorClientWinCE::isContinuousSpellCheckingEnabled()
64{
65    notImplemented();
66    return false;
67}
68
69bool EditorClientWinCE::isGrammarCheckingEnabled()
70{
71    notImplemented();
72    return false;
73}
74
75int EditorClientWinCE::spellCheckerDocumentTag()
76{
77    notImplemented();
78    return 0;
79}
80
81bool EditorClientWinCE::shouldBeginEditing(WebCore::Range*)
82{
83    notImplemented();
84    return true;
85}
86
87bool EditorClientWinCE::shouldEndEditing(WebCore::Range*)
88{
89    notImplemented();
90    return true;
91}
92
93bool EditorClientWinCE::shouldInsertText(const String&, Range*, EditorInsertAction)
94{
95    notImplemented();
96    return true;
97}
98
99bool EditorClientWinCE::shouldChangeSelectedRange(Range*, Range*, EAffinity, bool)
100{
101    notImplemented();
102    return true;
103}
104
105bool EditorClientWinCE::shouldApplyStyle(WebCore::CSSStyleDeclaration*, WebCore::Range*)
106{
107    notImplemented();
108    return true;
109}
110
111bool EditorClientWinCE::shouldMoveRangeAfterDelete(WebCore::Range*, WebCore::Range*)
112{
113    notImplemented();
114    return true;
115}
116
117void EditorClientWinCE::didBeginEditing()
118{
119    notImplemented();
120}
121
122void EditorClientWinCE::respondToChangedContents()
123{
124    notImplemented();
125}
126
127void EditorClientWinCE::respondToChangedSelection()
128{
129    notImplemented();
130}
131
132void EditorClientWinCE::didEndEditing()
133{
134    notImplemented();
135}
136
137void EditorClientWinCE::didWriteSelectionToPasteboard()
138{
139    notImplemented();
140}
141
142void EditorClientWinCE::didSetSelectionTypesForPasteboard()
143{
144    notImplemented();
145}
146
147void EditorClientWinCE::registerCommandForUndo(WTF::PassRefPtr<WebCore::EditCommand> command)
148{
149    notImplemented();
150}
151
152void EditorClientWinCE::registerCommandForRedo(WTF::PassRefPtr<WebCore::EditCommand> command)
153{
154    notImplemented();
155}
156
157void EditorClientWinCE::clearUndoRedoOperations()
158{
159    notImplemented();
160}
161
162bool EditorClientWinCE::canCopyCut(bool defaultValue) const
163{
164    return defaultValue;
165}
166
167bool EditorClientWinCE::canPaste(bool defaultValue) const
168{
169    return defaultValue;
170}
171
172bool EditorClientWinCE::canUndo() const
173{
174    notImplemented();
175    return false;
176}
177
178bool EditorClientWinCE::canRedo() const
179{
180    notImplemented();
181    return false;
182}
183
184void EditorClientWinCE::undo()
185{
186    notImplemented();
187}
188
189void EditorClientWinCE::redo()
190{
191    notImplemented();
192}
193
194bool EditorClientWinCE::shouldInsertNode(Node*, Range*, EditorInsertAction)
195{
196    notImplemented();
197    return true;
198}
199
200void EditorClientWinCE::pageDestroyed()
201{
202    delete this;
203}
204
205bool EditorClientWinCE::smartInsertDeleteEnabled()
206{
207    notImplemented();
208    return false;
209}
210
211bool EditorClientWinCE::isSelectTrailingWhitespaceEnabled()
212{
213    notImplemented();
214    return false;
215}
216
217void EditorClientWinCE::toggleContinuousSpellChecking()
218{
219    notImplemented();
220}
221
222void EditorClientWinCE::toggleGrammarChecking()
223{
224    notImplemented();
225}
226
227static const unsigned CtrlKey = 1 << 0;
228static const unsigned AltKey = 1 << 1;
229static const unsigned ShiftKey = 1 << 2;
230
231struct KeyDownEntry {
232    unsigned virtualKey;
233    unsigned modifiers;
234    const char* name;
235};
236
237struct KeyPressEntry {
238    unsigned charCode;
239    unsigned modifiers;
240    const char* name;
241};
242
243static const KeyDownEntry keyDownEntries[] = {
244    { VK_LEFT,   0,                  "MoveLeft"                                    },
245    { VK_LEFT,   ShiftKey,           "MoveLeftAndModifySelection"                  },
246    { VK_LEFT,   CtrlKey,            "MoveWordLeft"                                },
247    { VK_LEFT,   CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection"              },
248    { VK_RIGHT,  0,                  "MoveRight"                                   },
249    { VK_RIGHT,  ShiftKey,           "MoveRightAndModifySelection"                 },
250    { VK_RIGHT,  CtrlKey,            "MoveWordRight"                               },
251    { VK_RIGHT,  CtrlKey | ShiftKey, "MoveWordRightAndModifySelection"             },
252    { VK_UP,     0,                  "MoveUp"                                      },
253    { VK_UP,     ShiftKey,           "MoveUpAndModifySelection"                    },
254    { VK_PRIOR,  ShiftKey,           "MovePageUpAndModifySelection"                },
255    { VK_DOWN,   0,                  "MoveDown"                                    },
256    { VK_DOWN,   ShiftKey,           "MoveDownAndModifySelection"                  },
257    { VK_NEXT,   ShiftKey,           "MovePageDownAndModifySelection"              },
258    { VK_PRIOR,  0,                  "MovePageUp"                                  },
259    { VK_NEXT,   0,                  "MovePageDown"                                },
260    { VK_HOME,   0,                  "MoveToBeginningOfLine"                       },
261    { VK_HOME,   ShiftKey,           "MoveToBeginningOfLineAndModifySelection"     },
262    { VK_HOME,   CtrlKey,            "MoveToBeginningOfDocument"                   },
263    { VK_HOME,   CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
264
265    { VK_END,    0,                  "MoveToEndOfLine"                             },
266    { VK_END,    ShiftKey,           "MoveToEndOfLineAndModifySelection"           },
267    { VK_END,    CtrlKey,            "MoveToEndOfDocument"                         },
268    { VK_END,    CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection"       },
269
270    { VK_BACK,   0,                  "DeleteBackward"                              },
271    { VK_BACK,   ShiftKey,           "DeleteBackward"                              },
272    { VK_DELETE, 0,                  "DeleteForward"                               },
273    { VK_BACK,   CtrlKey,            "DeleteWordBackward"                          },
274    { VK_DELETE, CtrlKey,            "DeleteWordForward"                           },
275
276    { 'B',       CtrlKey,            "ToggleBold"                                  },
277    { 'I',       CtrlKey,            "ToggleItalic"                                },
278
279    { VK_ESCAPE, 0,                  "Cancel"                                      },
280    { VK_TAB,    0,                  "InsertTab"                                   },
281    { VK_TAB,    ShiftKey,           "InsertBacktab"                               },
282    { VK_RETURN, 0,                  "InsertNewline"                               },
283    { VK_RETURN, CtrlKey,            "InsertNewline"                               },
284    { VK_RETURN, AltKey,             "InsertNewline"                               },
285    { VK_RETURN, AltKey | ShiftKey,  "InsertNewline"                               },
286
287    // It's not quite clear whether clipboard shortcuts and Undo/Redo should be handled
288    // in the application or in WebKit. We chose WebKit for now.
289    { 'C',       CtrlKey,            "Copy"                                        },
290    { 'V',       CtrlKey,            "Paste"                                       },
291    { 'X',       CtrlKey,            "Cut"                                         },
292    { 'A',       CtrlKey,            "SelectAll"                                   },
293    { VK_INSERT, CtrlKey,            "Copy"                                        },
294    { VK_DELETE, ShiftKey,           "Cut"                                         },
295    { VK_INSERT, ShiftKey,           "Paste"                                       },
296    { 'Z',       CtrlKey,            "Undo"                                        },
297    { 'Z',       CtrlKey | ShiftKey, "Redo"                                        }
298};
299
300static const KeyPressEntry keyPressEntries[] = {
301    { '\t',   0,                  "InsertTab"                                   },
302    { '\t',   ShiftKey,           "InsertBacktab"                               },
303    { '\r',   0,                  "InsertNewline"                               },
304    { '\r',   CtrlKey,            "InsertNewline"                               },
305    { '\r',   AltKey,             "InsertNewline"                               },
306    { '\r',   AltKey | ShiftKey,  "InsertNewline"                               }
307};
308
309const char* EditorClientWinCE::interpretKeyEvent(const KeyboardEvent* event)
310{
311    ASSERT(event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent);
312
313    static HashMap<int, const char*>* keyDownCommandsMap = 0;
314    static HashMap<int, const char*>* keyPressCommandsMap = 0;
315
316    if (!keyDownCommandsMap) {
317        keyDownCommandsMap = new HashMap<int, const char*>;
318        keyPressCommandsMap = new HashMap<int, const char*>;
319
320        for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyDownEntries); ++i)
321            keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
322
323        for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyPressEntries); ++i)
324            keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
325    }
326
327    unsigned modifiers = 0;
328    if (event->shiftKey())
329        modifiers |= ShiftKey;
330    if (event->altKey())
331        modifiers |= AltKey;
332    if (event->ctrlKey())
333        modifiers |= CtrlKey;
334
335    if (event->type() == eventNames().keydownEvent) {
336        int mapKey = modifiers << 16 | event->keyCode();
337        return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
338    }
339
340    int mapKey = modifiers << 16 | event->charCode();
341    return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
342}
343
344bool EditorClientWinCE::handleEditingKeyboardEvent(KeyboardEvent* event)
345{
346    Node* node = event->target()->toNode();
347    ASSERT(node);
348    Frame* frame = node->document()->frame();
349    ASSERT(frame);
350
351    const PlatformKeyboardEvent* keyEvent = event->keyEvent();
352    if (!keyEvent)
353        return false;
354
355    bool caretBrowsing = frame->settings()->caretBrowsingEnabled();
356    if (caretBrowsing) {
357        switch (keyEvent->windowsVirtualKeyCode()) {
358        case VK_LEFT:
359            frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::AlterationExtend : SelectionController::AlterationMove,
360                    DirectionLeft,
361                    keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
362                    true);
363            return true;
364        case VK_RIGHT:
365            frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::AlterationExtend : SelectionController::AlterationMove,
366                    DirectionRight,
367                    keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
368                    true);
369            return true;
370        case VK_UP:
371            frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::AlterationExtend : SelectionController::AlterationMove,
372                    DirectionBackward,
373                    keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
374                    true);
375            return true;
376        case VK_DOWN:
377            frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::AlterationExtend : SelectionController::AlterationMove,
378                    DirectionForward,
379                    keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
380                    true);
381            return true;
382        }
383    }
384
385    Editor::Command command = frame->editor()->command(interpretKeyEvent(event));
386
387    if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
388        // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
389        // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
390        // (e.g. Tab that inserts a Tab character, or Enter).
391        return !command.isTextInsertion() && command.execute(event);
392    }
393
394    if (command.execute(event))
395        return true;
396
397    // Don't insert null or control characters as they can result in unexpected behaviour
398    if (event->charCode() < ' ')
399        return false;
400
401    // Don't insert anything if a modifier is pressed
402    if (keyEvent->ctrlKey() || keyEvent->altKey())
403        return false;
404
405    return frame->editor()->insertText(event->keyEvent()->text(), event);
406}
407
408void EditorClientWinCE::handleKeyboardEvent(KeyboardEvent* event)
409{
410    if (handleEditingKeyboardEvent(event))
411        event->setDefaultHandled();
412}
413
414void EditorClientWinCE::handleInputMethodKeydown(KeyboardEvent* event)
415{
416    notImplemented();
417}
418
419void EditorClientWinCE::textFieldDidBeginEditing(Element*)
420{
421}
422
423void EditorClientWinCE::textFieldDidEndEditing(Element*)
424{
425}
426
427void EditorClientWinCE::textDidChangeInTextField(Element*)
428{
429}
430
431bool EditorClientWinCE::doTextFieldCommandFromEvent(Element*, KeyboardEvent*)
432{
433    return false;
434}
435
436void EditorClientWinCE::textWillBeDeletedInTextField(Element*)
437{
438    notImplemented();
439}
440
441void EditorClientWinCE::textDidChangeInTextArea(Element*)
442{
443    notImplemented();
444}
445
446void EditorClientWinCE::ignoreWordInSpellDocument(const String& text)
447{
448    notImplemented();
449}
450
451void EditorClientWinCE::learnWord(const String& text)
452{
453    notImplemented();
454}
455
456void EditorClientWinCE::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength)
457{
458    notImplemented();
459}
460
461String EditorClientWinCE::getAutoCorrectSuggestionForMisspelledWord(const String& inputWord)
462{
463    // This method can be implemented using customized algorithms for the particular browser.
464    // Currently, it computes an empty string.
465    return String();
466}
467
468void EditorClientWinCE::checkGrammarOfString(const UChar*, int, Vector<GrammarDetail>&, int*, int*)
469{
470    notImplemented();
471}
472
473void EditorClientWinCE::updateSpellingUIWithGrammarString(const String&, const GrammarDetail&)
474{
475    notImplemented();
476}
477
478void EditorClientWinCE::updateSpellingUIWithMisspelledWord(const String&)
479{
480    notImplemented();
481}
482
483void EditorClientWinCE::showSpellingUI(bool)
484{
485    notImplemented();
486}
487
488bool EditorClientWinCE::spellingUIIsShowing()
489{
490    notImplemented();
491    return false;
492}
493
494void EditorClientWinCE::getGuessesForWord(const String& word, const String& context, WTF::Vector<String>& guesses)
495{
496    notImplemented();
497}
498
499void EditorClientWinCE::willSetInputMethodState()
500{
501    notImplemented();
502}
503
504} // namespace WebKit
505