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