root/trunk/WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp

Revision 38738, 16.5 KB (checked in by darin@chromium.org, 7 days ago)

2008-11-24 Darin Fisher <darin@chromium.org>

Fix bustage.

http://bugs.webkit.org/show_bug.cgi?id=15643

  • WebCoreSupport/EditorClientQt.cpp: (WebCore::EditorClientQt::isSelectTrailingWhitespaceEnabled):
  • WebCoreSupport/EditorClientQt.h:
  • Property svn:eol-style set to native
Line 
1/*
2 *  Copyright (C) 2007 Alp Toker <alp@atoker.com>
3 *  Copyright (C) 2008 Nuanti Ltd.
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include "config.h"
21#include "EditorClientGtk.h"
22
23#include "CString.h"
24#include "EditCommand.h"
25#include "Editor.h"
26#include "FocusController.h"
27#include "Frame.h"
28#include "KeyboardCodes.h"
29#include "KeyboardEvent.h"
30#include "NotImplemented.h"
31#include "Page.h"
32#include "PlatformKeyboardEvent.h"
33#include "markup.h"
34#include "webkitprivate.h"
35
36using namespace WebCore;
37
38namespace WebKit {
39
40static void imContextCommitted(GtkIMContext* context, const gchar* str, EditorClient* client)
41{
42    Frame* targetFrame = core(client->m_webView)->focusController()->focusedOrMainFrame();
43
44    if (!targetFrame || !targetFrame->editor()->canEdit())
45        return;
46
47    Editor* editor = targetFrame->editor();
48
49    String commitString = String::fromUTF8(str);
50    editor->confirmComposition(commitString);
51}
52
53static void imContextPreeditChanged(GtkIMContext* context, EditorClient* client)
54{
55    Frame* frame = core(client->m_webView)->focusController()->focusedOrMainFrame();
56    Editor* editor = frame->editor();
57
58    gchar* preedit = NULL;
59    gint cursorPos = 0;
60    // We ignore the provided PangoAttrList for now.
61    gtk_im_context_get_preedit_string(context, &preedit, NULL, &cursorPos);
62    String preeditString = String::fromUTF8(preedit);
63    g_free(preedit);
64
65    // setComposition() will replace the user selection if passed an empty
66    // preedit. We don't want this to happen.
67    if (preeditString.isEmpty() && !editor->hasComposition())
68        return;
69
70    Vector<CompositionUnderline> underlines;
71    underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
72    editor->setComposition(preeditString, underlines, cursorPos, 0);
73}
74
75void EditorClient::setInputMethodState(bool active)
76{
77    WebKitWebViewPrivate* priv = m_webView->priv;
78
79    if (active)
80        gtk_im_context_focus_in(priv->imContext);
81    else
82        gtk_im_context_focus_out(priv->imContext);
83
84#ifdef MAEMO_CHANGES
85    if (active)
86        hildon_gtk_im_context_show(priv->imContext);
87    else
88        hildon_gtk_im_context_hide(priv->imContext);
89#endif
90}
91
92bool EditorClient::shouldDeleteRange(Range*)
93{
94    notImplemented();
95    return true;
96}
97
98bool EditorClient::shouldShowDeleteInterface(HTMLElement*)
99{
100    return false;
101}
102
103bool EditorClient::isContinuousSpellCheckingEnabled()
104{
105    notImplemented();
106    return false;
107}
108
109bool EditorClient::isGrammarCheckingEnabled()
110{
111    notImplemented();
112    return false;
113}
114
115int EditorClient::spellCheckerDocumentTag()
116{
117    notImplemented();
118    return 0;
119}
120
121bool EditorClient::shouldBeginEditing(WebCore::Range*)
122{
123    notImplemented();
124    return true;
125}
126
127bool EditorClient::shouldEndEditing(WebCore::Range*)
128{
129    notImplemented();
130    return true;
131}
132
133bool EditorClient::shouldInsertText(const String&, Range*, EditorInsertAction)
134{
135    notImplemented();
136    return true;
137}
138
139bool EditorClient::shouldChangeSelectedRange(Range*, Range*, EAffinity, bool)
140{
141    notImplemented();
142    return true;
143}
144
145bool EditorClient::shouldApplyStyle(WebCore::CSSStyleDeclaration*, WebCore::Range*)
146{
147    notImplemented();
148    return true;
149}
150
151bool EditorClient::shouldMoveRangeAfterDelete(WebCore::Range*, WebCore::Range*)
152{
153    notImplemented();
154    return true;
155}
156
157void EditorClient::didBeginEditing()
158{
159    notImplemented();
160}
161
162void EditorClient::respondToChangedContents()
163{
164    notImplemented();
165}
166
167#if GTK_CHECK_VERSION(2,10,0)
168static void clipboard_get_contents_cb(GtkClipboard* clipboard, GtkSelectionData* selection_data, guint info, gpointer data)
169{
170    WebKitWebView* webView = reinterpret_cast<WebKitWebView*>(data);
171    Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
172    PassRefPtr<Range> selectedRange = frame->selection()->toRange();
173
174    if (static_cast<gint>(info) == WEBKIT_WEB_VIEW_TARGET_INFO_HTML) {
175        String markup = createMarkup(selectedRange.get(), 0, AnnotateForInterchange);
176        gtk_selection_data_set(selection_data, selection_data->target, 8,
177                               reinterpret_cast<const guchar*>(markup.utf8().data()), markup.utf8().length());
178    } else {
179        String text = selectedRange->text();
180        gtk_selection_data_set_text(selection_data, text.utf8().data(), text.utf8().length());
181    }
182}
183
184static void clipboard_clear_contents_cb(GtkClipboard* clipboard, gpointer data)
185{
186    WebKitWebView* webView = reinterpret_cast<WebKitWebView*>(data);
187    Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
188
189    // Collapse the selection without clearing it
190    frame->selection()->setBase(frame->selection()->extent(), frame->selection()->affinity());
191}
192#endif
193
194void EditorClient::respondToChangedSelection()
195{
196    WebKitWebViewPrivate* priv = m_webView->priv;
197    Frame* targetFrame = core(m_webView)->focusController()->focusedOrMainFrame();
198
199    if (!targetFrame)
200        return;
201
202    if (targetFrame->editor()->ignoreCompositionSelectionChange())
203        return;
204
205#if GTK_CHECK_VERSION(2,10,0)
206    GtkClipboard* clipboard = gtk_widget_get_clipboard(GTK_WIDGET(m_webView), GDK_SELECTION_PRIMARY);
207    if (targetFrame->selection()->isRange()) {
208        GtkTargetList* targetList = webkit_web_view_get_copy_target_list(m_webView);
209        gint targetCount;
210        GtkTargetEntry* targets = gtk_target_table_new_from_list(targetList, &targetCount);
211        gtk_clipboard_set_with_owner(clipboard, targets, targetCount,
212                                     clipboard_get_contents_cb, clipboard_clear_contents_cb, G_OBJECT(m_webView));
213        gtk_target_table_free(targets, targetCount);
214    } else if (gtk_clipboard_get_owner(clipboard) == G_OBJECT(m_webView))
215        gtk_clipboard_clear(clipboard);
216#endif
217
218    if (!targetFrame->editor()->hasComposition())
219        return;
220
221    unsigned start;
222    unsigned end;
223    if (!targetFrame->editor()->getCompositionSelection(start, end)) {
224        // gtk_im_context_reset() clears the composition for us.
225        gtk_im_context_reset(priv->imContext);
226        targetFrame->editor()->confirmCompositionWithoutDisturbingSelection();
227    }
228}
229
230void EditorClient::didEndEditing()
231{
232    notImplemented();
233}
234
235void EditorClient::didWriteSelectionToPasteboard()
236{
237    notImplemented();
238}
239
240void EditorClient::didSetSelectionTypesForPasteboard()
241{
242    notImplemented();
243}
244
245bool EditorClient::isEditable()
246{
247    return webkit_web_view_get_editable(m_webView);
248}
249
250void EditorClient::registerCommandForUndo(WTF::PassRefPtr<WebCore::EditCommand>)
251{
252    notImplemented();
253}
254
255void EditorClient::registerCommandForRedo(WTF::PassRefPtr<WebCore::EditCommand>)
256{
257    notImplemented();
258}
259
260void EditorClient::clearUndoRedoOperations()
261{
262    notImplemented();
263}
264
265bool EditorClient::canUndo() const
266{
267    notImplemented();
268    return false;
269}
270
271bool EditorClient::canRedo() const
272{
273    notImplemented();
274    return false;
275}
276
277void EditorClient::undo()
278{
279    notImplemented();
280}
281
282void EditorClient::redo()
283{
284    notImplemented();
285}
286
287bool EditorClient::shouldInsertNode(Node*, Range*, EditorInsertAction)
288{
289    notImplemented();
290    return true;
291}
292
293void EditorClient::pageDestroyed()
294{
295    delete this;
296}
297
298bool EditorClient::smartInsertDeleteEnabled()
299{
300    notImplemented();
301    return false;
302}
303
304bool EditorClient::isSelectTrailingWhitespaceEnabled()
305{
306    notImplemented();
307    return false;
308}
309
310void EditorClient::toggleContinuousSpellChecking()
311{
312    notImplemented();
313}
314
315void EditorClient::toggleGrammarChecking()
316{
317}
318
319void EditorClient::handleKeyboardEvent(KeyboardEvent* event)
320{
321    Frame* frame = core(m_webView)->focusController()->focusedOrMainFrame();
322    if (!frame || !frame->document()->focusedNode())
323        return;
324
325    const PlatformKeyboardEvent* kevent = event->keyEvent();
326    if (!kevent || kevent->type() == PlatformKeyboardEvent::KeyUp)
327        return;
328
329    Node* start = frame->selection()->start().node();
330    if (!start)
331        return;
332
333    // FIXME: Use GtkBindingSet instead of this hard-coded switch
334    // http://bugs.webkit.org/show_bug.cgi?id=15911
335
336    if (start->isContentEditable()) {
337        switch (kevent->windowsVirtualKeyCode()) {
338            case VK_BACK:
339                frame->editor()->deleteWithDirection(SelectionController::BACKWARD,
340                        kevent->ctrlKey() ? WordGranularity : CharacterGranularity, false, true);
341                break;
342            case VK_DELETE:
343                frame->editor()->deleteWithDirection(SelectionController::FORWARD,
344                        kevent->ctrlKey() ? WordGranularity : CharacterGranularity, false, true);
345                break;
346            case VK_LEFT:
347                frame->selection()->modify(kevent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
348                        SelectionController::LEFT,
349                        kevent->ctrlKey() ? WordGranularity : CharacterGranularity,
350                        true);
351                break;
352            case VK_RIGHT:
353                frame->selection()->modify(kevent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
354                        SelectionController::RIGHT,
355                        kevent->ctrlKey() ? WordGranularity : CharacterGranularity,
356                        true);
357                break;
358            case VK_UP:
359                frame->selection()->modify(kevent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
360                        SelectionController::BACKWARD,
361                        kevent->ctrlKey() ? ParagraphGranularity : LineGranularity,
362                        true);
363                break;
364            case VK_DOWN:
365                frame->selection()->modify(kevent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
366                        SelectionController::FORWARD,
367                        kevent->ctrlKey() ? ParagraphGranularity : LineGranularity,
368                        true);
369                break;
370            case VK_PRIOR:  // PageUp
371                frame->editor()->command(kevent->shiftKey() ? "MovePageUpAndModifySelection" : "MovePageUp").execute();
372                break;
373            case VK_NEXT:  // PageDown
374                frame->editor()->command(kevent->shiftKey() ? "MovePageDownAndModifySelection" : "MovePageDown").execute();
375                break;
376            case VK_HOME:
377                if (kevent->ctrlKey() && kevent->shiftKey())
378                    frame->editor()->command("MoveToBeginningOfDocumentAndModifySelection").execute();
379                else if (kevent->ctrlKey())
380                    frame->editor()->command("MoveToBeginningOfDocument").execute();
381                else if (kevent->shiftKey())
382                    frame->editor()->command("MoveToBeginningOfLineAndModifySelection").execute();
383                else
384                    frame->editor()->command("MoveToBeginningOfLine").execute();
385                break;
386            case VK_END:
387                if (kevent->ctrlKey() && kevent->shiftKey())
388                    frame->editor()->command("MoveToEndOfDocumentAndModifySelection").execute();
389                else if (kevent->ctrlKey())
390                    frame->editor()->command("MoveToEndOfDocument").execute();
391                else if (kevent->shiftKey())
392                    frame->editor()->command("MoveToEndOfLineAndModifySelection").execute();
393                else
394                    frame->editor()->command("MoveToEndOfLine").execute();
395                break;
396            case VK_RETURN:
397                frame->editor()->command("InsertLineBreak").execute();
398                break;
399            case VK_TAB:
400                return;
401            default:
402                if (!kevent->ctrlKey() && !kevent->altKey() && !kevent->text().isEmpty()) {
403                    if (kevent->text().length() == 1) {
404                        UChar ch = kevent->text()[0];
405                        // Don't insert null or control characters as they can result in unexpected behaviour
406                        if (ch < ' ')
407                            break;
408                    }
409                    frame->editor()->insertText(kevent->text(), event);
410                } else if (kevent->ctrlKey()) {
411                    switch (kevent->windowsVirtualKeyCode()) {
412                        case VK_B:
413                            frame->editor()->command("ToggleBold").execute();
414                            break;
415                        case VK_I:
416                            frame->editor()->command("ToggleItalic").execute();
417                            break;
418                        case VK_Y:
419                            frame->editor()->command("Redo").execute();
420                            break;
421                        case VK_Z:
422                            frame->editor()->command("Undo").execute();
423                            break;
424                        default:
425                            return;
426                    }
427                } else return;
428        }
429    } else {
430        switch (kevent->windowsVirtualKeyCode()) {
431            case VK_UP:
432                frame->editor()->command("MoveUp").execute();
433                break;
434            case VK_DOWN:
435                frame->editor()->command("MoveDown").execute();
436                break;
437            case VK_PRIOR:  // PageUp
438                frame->editor()->command("MovePageUp").execute();
439                break;
440            case VK_NEXT:  // PageDown
441                frame->editor()->command("MovePageDown").execute();
442                break;
443            case VK_HOME:
444                if (kevent->ctrlKey())
445                    frame->editor()->command("MoveToBeginningOfDocument").execute();
446                break;
447            case VK_END:
448                if (kevent->ctrlKey())
449                    frame->editor()->command("MoveToEndOfDocument").execute();
450                break;
451            default:
452                return;
453        }
454    }
455    event->setDefaultHandled();
456}
457
458void EditorClient::handleInputMethodKeydown(KeyboardEvent* event)
459{
460    WebKitWebViewPrivate* priv = m_webView->priv;
461
462    // TODO: Dispatch IE-compatible text input events for IM events.
463    if (gtk_im_context_filter_keypress(priv->imContext, event->keyEvent()->gdkEventKey()))
464        event->setDefaultHandled();
465}
466
467EditorClient::EditorClient(WebKitWebView* webView)
468    : m_webView(webView)
469{
470    WebKitWebViewPrivate* priv = m_webView->priv;
471    g_signal_connect(priv->imContext, "commit", G_CALLBACK(imContextCommitted), this);
472    g_signal_connect(priv->imContext, "preedit-changed", G_CALLBACK(imContextPreeditChanged), this);
473}
474
475EditorClient::~EditorClient()
476{
477    WebKitWebViewPrivate* priv = m_webView->priv;
478    g_signal_handlers_disconnect_by_func(priv->imContext, (gpointer)imContextCommitted, this);
479    g_signal_handlers_disconnect_by_func(priv->imContext, (gpointer)imContextPreeditChanged, this);
480}
481
482void EditorClient::textFieldDidBeginEditing(Element*)
483{
484}
485
486void EditorClient::textFieldDidEndEditing(Element*)
487{
488}
489
490void EditorClient::textDidChangeInTextField(Element*)
491{
492}
493
494bool EditorClient::doTextFieldCommandFromEvent(Element*, KeyboardEvent*)
495{
496    return false;
497}
498
499void EditorClient::textWillBeDeletedInTextField(Element*)
500{
501    notImplemented();
502}
503
504void EditorClient::textDidChangeInTextArea(Element*)
505{
506    notImplemented();
507}
508
509void EditorClient::ignoreWordInSpellDocument(const String&)
510{
511    notImplemented();
512}
513
514void EditorClient::learnWord(const String&)
515{
516    notImplemented();
517}
518
519void EditorClient::checkSpellingOfString(const UChar*, int, int*, int*)
520{
521    notImplemented();
522}
523
524void EditorClient::checkGrammarOfString(const UChar*, int, Vector<GrammarDetail>&, int*, int*)
525{
526    notImplemented();
527}
528
529void EditorClient::updateSpellingUIWithGrammarString(const String&, const GrammarDetail&)
530{
531    notImplemented();
532}
533
534void EditorClient::updateSpellingUIWithMisspelledWord(const String&)
535{
536    notImplemented();
537}
538
539void EditorClient::showSpellingUI(bool)
540{
541    notImplemented();
542}
543
544bool EditorClient::spellingUIIsShowing()
545{
546    notImplemented();
547    return false;
548}
549
550void EditorClient::getGuessesForWord(const String&, Vector<String>&)
551{
552    notImplemented();
553}
554
555}
Note: See TracBrowser for help on using the browser.