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