~ubuntu-branches/ubuntu/maverick/webkit/maverick

« back to all changes in this revision

Viewing changes to WebKit/win/WebEditorClient.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mike Hommey
  • Date: 2007-08-19 15:54:12 UTC
  • Revision ID: james.westby@ubuntu.com-20070819155412-uxxg1h9plpghmtbi
Tags: upstream-0~svn25144
ImportĀ upstreamĀ versionĀ 0~svn25144

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 * 1. Redistributions of source code must retain the above copyright
 
8
 *    notice, this list of conditions and the following disclaimer.
 
9
 * 2. Redistributions in binary form must reproduce the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer in the
 
11
 *    documentation and/or other materials provided with the distribution.
 
12
 *
 
13
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 
24
 */
 
25
 
 
26
#include "config.h"
 
27
#include "WebKitDLL.h"
 
28
#include "WebEditorClient.h"
 
29
 
 
30
#include "IWebEditingDelegate.h"
 
31
#include "IWebUndoTarget.h"
 
32
#include "IWebURLResponse.h"
 
33
#include "WebLocalizableStrings.h"
 
34
#include "WebView.h"
 
35
#include "DOMCoreClasses.h"
 
36
#pragma warning(push, 0)
 
37
#include <WebCore/BString.h>
 
38
#include <WebCore/Document.h>
 
39
#include <WebCore/EditCommand.h>
 
40
#include <WebCore/HTMLElement.h>
 
41
#include <WebCore/HTMLInputElement.h>
 
42
#include <WebCore/HTMLNames.h>
 
43
#include <WebCore/KeyboardEvent.h>
 
44
#include <WebCore/PlatformKeyboardEvent.h>
 
45
#include <WebCore/NotImplemented.h>
 
46
#include <WebCore/Range.h>
 
47
#pragma warning(pop)
 
48
 
 
49
using namespace WebCore;
 
50
using namespace HTMLNames;
 
51
 
 
52
// {09A11D2B-FAFB-4ca0-A6F7-791EE8932C88}
 
53
static const GUID IID_IWebUndoCommand = 
 
54
{ 0x9a11d2b, 0xfafb, 0x4ca0, { 0xa6, 0xf7, 0x79, 0x1e, 0xe8, 0x93, 0x2c, 0x88 } };
 
55
 
 
56
class IWebUndoCommand : public IUnknown {
 
57
public:
 
58
    virtual void execute() = 0;
 
59
};
 
60
 
 
61
// WebEditorUndoTarget -------------------------------------------------------------
 
62
 
 
63
class WebEditorUndoTarget : public IWebUndoTarget
 
64
{
 
65
public:
 
66
    WebEditorUndoTarget();
 
67
 
 
68
    // IUnknown
 
69
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
 
70
    virtual ULONG STDMETHODCALLTYPE AddRef(void);
 
71
    virtual ULONG STDMETHODCALLTYPE Release(void);
 
72
 
 
73
    // IWebUndoTarget
 
74
    virtual HRESULT STDMETHODCALLTYPE invoke( 
 
75
        /* [in] */ BSTR actionName,
 
76
        /* [in] */ IUnknown *obj);
 
77
 
 
78
private:
 
79
    ULONG m_refCount;
 
80
};
 
81
 
 
82
WebEditorUndoTarget::WebEditorUndoTarget()
 
83
: m_refCount(1)
 
84
{
 
85
}
 
86
 
 
87
HRESULT STDMETHODCALLTYPE WebEditorUndoTarget::QueryInterface(REFIID riid, void** ppvObject)
 
88
{
 
89
    *ppvObject = 0;
 
90
    if (IsEqualGUID(riid, IID_IUnknown))
 
91
        *ppvObject = static_cast<IWebUndoTarget*>(this);
 
92
    else if (IsEqualGUID(riid, IID_IWebUndoTarget))
 
93
        *ppvObject = static_cast<IWebUndoTarget*>(this);
 
94
    else
 
95
        return E_NOINTERFACE;
 
96
 
 
97
    AddRef();
 
98
    return S_OK;
 
99
}
 
100
 
 
101
ULONG STDMETHODCALLTYPE WebEditorUndoTarget::AddRef(void)
 
102
{
 
103
    return ++m_refCount;
 
104
}
 
105
 
 
106
ULONG STDMETHODCALLTYPE WebEditorUndoTarget::Release(void)
 
107
{
 
108
    ULONG newRef = --m_refCount;
 
109
    if (!newRef)
 
110
        delete(this);
 
111
 
 
112
    return newRef;
 
113
}
 
114
 
 
115
HRESULT STDMETHODCALLTYPE WebEditorUndoTarget::invoke( 
 
116
    /* [in] */ BSTR /*actionName*/,
 
117
    /* [in] */ IUnknown *obj)
 
118
{
 
119
    IWebUndoCommand* undoCommand = 0;
 
120
    if (SUCCEEDED(obj->QueryInterface(IID_IWebUndoCommand, (void**)&undoCommand))) {
 
121
        undoCommand->execute();
 
122
        undoCommand->Release();
 
123
    }
 
124
    return S_OK;
 
125
}
 
126
 
 
127
// WebEditorClient ------------------------------------------------------------------
 
128
 
 
129
WebEditorClient::WebEditorClient(WebView* webView)
 
130
    : m_webView(webView)
 
131
    , m_undoTarget(0)
 
132
{
 
133
    m_undoTarget = new WebEditorUndoTarget();
 
134
}
 
135
 
 
136
WebEditorClient::~WebEditorClient()
 
137
{
 
138
    if (m_undoTarget)
 
139
        m_undoTarget->Release();
 
140
}
 
141
 
 
142
void WebEditorClient::pageDestroyed()
 
143
{
 
144
    delete this;
 
145
}
 
146
 
 
147
bool WebEditorClient::isContinuousSpellCheckingEnabled()
 
148
{
 
149
    BOOL enabled;
 
150
    if (FAILED(m_webView->isContinuousSpellCheckingEnabled(&enabled)))
 
151
        return false;
 
152
    return !!enabled;
 
153
}
 
154
 
 
155
void WebEditorClient::toggleContinuousSpellChecking()
 
156
{
 
157
    m_webView->toggleContinuousSpellChecking(0);
 
158
}
 
159
 
 
160
bool WebEditorClient::isGrammarCheckingEnabled()
 
161
{
 
162
    BOOL enabled;
 
163
    if (FAILED(m_webView->isGrammarCheckingEnabled(&enabled)))
 
164
        return false;
 
165
    return !!enabled;
 
166
}
 
167
 
 
168
void WebEditorClient::toggleGrammarChecking()
 
169
{
 
170
    m_webView->toggleGrammarChecking(0);
 
171
}
 
172
 
 
173
static void initViewSpecificSpelling(IWebViewEditing* viewEditing)
 
174
{
 
175
    // we just use this as a flag to indicate that we've spell checked the document
 
176
    // and need to close the spell checker out when the view closes.
 
177
    int tag;
 
178
    viewEditing->spellCheckerDocumentTag(&tag);
 
179
}
 
180
 
 
181
int WebEditorClient::spellCheckerDocumentTag()
 
182
{
 
183
    // we don't use the concept of spelling tags
 
184
    notImplemented();
 
185
    ASSERT_NOT_REACHED();
 
186
    return 0;
 
187
}
 
188
 
 
189
bool WebEditorClient::shouldBeginEditing(Range*)
 
190
{
 
191
    notImplemented();
 
192
    return true;
 
193
}
 
194
 
 
195
bool WebEditorClient::shouldEndEditing(Range*)
 
196
{
 
197
    notImplemented();
 
198
    return true;
 
199
}
 
200
 
 
201
void WebEditorClient::didBeginEditing()
 
202
{
 
203
    notImplemented();
 
204
}
 
205
 
 
206
void WebEditorClient::respondToChangedContents()
 
207
{
 
208
    notImplemented();
 
209
}
 
210
 
 
211
void WebEditorClient::respondToChangedSelection()
 
212
{
 
213
    m_webView->selectionChanged();
 
214
}
 
215
 
 
216
void WebEditorClient::didEndEditing()
 
217
{
 
218
    notImplemented();
 
219
}
 
220
 
 
221
void WebEditorClient::didWriteSelectionToPasteboard()
 
222
{
 
223
    notImplemented();
 
224
}
 
225
 
 
226
void WebEditorClient::didSetSelectionTypesForPasteboard()
 
227
{
 
228
    notImplemented();
 
229
}
 
230
 
 
231
bool WebEditorClient::shouldDeleteRange(Range* /*range*/)
 
232
{
 
233
    notImplemented(); 
 
234
    return true; 
 
235
 
 
236
    // FIXME: calling m_webView->editingDelegate() will cause an assertion failure so we don't want to enable this code until that's implemented. 
 
237
    //BOOL result = false;
 
238
    //IWebViewEditingDelegate* editingDelegate;
 
239
    //// FIXME: DOMRange needs to be implemented before anything meaningful can be done here
 
240
    //IDOMRange* domRange(0);
 
241
    //if (SUCCEEDED(m_webView->editingDelegate(&editingDelegate))) {
 
242
    //    editingDelegate->shouldDeleteDOMRange(m_webView, domRange, &result);
 
243
    //    editingDelegate->Release();
 
244
    //}
 
245
    //return !!result;
 
246
}
 
247
 
 
248
bool WebEditorClient::shouldInsertNode(Node* /*node*/, Range* /*replacingRange*/, EditorInsertAction /*givenAction*/)
 
249
 
250
    notImplemented(); 
 
251
    return true; 
 
252
}
 
253
 
 
254
bool WebEditorClient::shouldInsertText(String /*str*/, Range* /* replacingRange */, EditorInsertAction /*givenAction*/)
 
255
{     
 
256
    notImplemented(); 
 
257
    return true; 
 
258
 
 
259
    // FIXME: calling m_webView->editingDelegate() will cause an assertion failure so we don't want to enable this code until that's implemented. 
 
260
    //BOOL result = false;
 
261
    //IWebViewEditingDelegate* editingDelegate;
 
262
    //// FIXME: DOMRange needs to be implemented before anything meaningful can be done here
 
263
    //IDOMRange* domRange(0); // make a DOMRange from replacingRange
 
264
    //BString text(str);
 
265
    //if (SUCCEEDED(m_webView->editingDelegate(&editingDelegate))) {
 
266
    //    editingDelegate->shouldInsertText(m_webView, text, domRange, (WebViewInsertAction) givenAction, &result);
 
267
    //    editingDelegate->Release();
 
268
    //}
 
269
    //return !!result;
 
270
}
 
271
 
 
272
//bool WebEditorClient::shouldChangeSelectedRange(Range *currentRange, Range *toProposedRange, SelectionAffinity selectionAffinity, bool stillSelecting)
 
273
//{ notImplemented(); return false; }
 
274
 
 
275
bool WebEditorClient::shouldApplyStyle(CSSStyleDeclaration* /*style*/, Range* /*toElementsInDOMRange*/)
 
276
{ notImplemented(); return true; }
 
277
 
 
278
bool WebEditorClient::shouldMoveRangeAfterDelete(Range* /*range*/, Range* /*rangeToBeReplaced*/)
 
279
{ notImplemented(); return true; }
 
280
 
 
281
bool WebEditorClient::shouldChangeTypingStyle(CSSStyleDeclaration* /*currentStyle*/, CSSStyleDeclaration* /*toProposedStyle*/)
 
282
{ notImplemented(); return false; }
 
283
 
 
284
void WebEditorClient::webViewDidChangeTypingStyle(WebNotification* /*notification*/)
 
285
{  notImplemented(); }
 
286
 
 
287
void WebEditorClient::webViewDidChangeSelection(WebNotification* /*notification*/)
 
288
{  notImplemented(); }
 
289
 
 
290
bool WebEditorClient::shouldShowDeleteInterface(HTMLElement* /*element*/)
 
291
{ notImplemented(); return false; }
 
292
 
 
293
bool WebEditorClient::smartInsertDeleteEnabled(void)
 
294
 
295
    BOOL enabled = FALSE; 
 
296
    m_webView->smartInsertDeleteEnabled(&enabled);
 
297
    return !!enabled;
 
298
}
 
299
 
 
300
bool WebEditorClient::shouldChangeSelectedRange(WebCore::Range*, WebCore::Range*, WebCore::EAffinity, bool)
 
301
{ notImplemented(); return true; }
 
302
 
 
303
void WebEditorClient::textFieldDidBeginEditing(Element* e)
 
304
{
 
305
    IWebFormDelegate* formDelegate;
 
306
    if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
 
307
        IDOMElement* domElement = DOMElement::createInstance(e);
 
308
        if (domElement) {
 
309
            IDOMHTMLInputElement* domInputElement;
 
310
            if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
 
311
                formDelegate->textFieldDidBeginEditing(domInputElement, kit(e->document()->frame()));
 
312
                domInputElement->Release();
 
313
            }
 
314
            domElement->Release();
 
315
        }
 
316
        formDelegate->Release();
 
317
    }
 
318
}
 
319
 
 
320
void WebEditorClient::textFieldDidEndEditing(Element* e)
 
321
{
 
322
    IWebFormDelegate* formDelegate;
 
323
    if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
 
324
        IDOMElement* domElement = DOMElement::createInstance(e);
 
325
        if (domElement) {
 
326
            IDOMHTMLInputElement* domInputElement;
 
327
            if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
 
328
                formDelegate->textFieldDidEndEditing(domInputElement, kit(e->document()->frame()));
 
329
                domInputElement->Release();
 
330
            }
 
331
            domElement->Release();
 
332
        }
 
333
        formDelegate->Release();
 
334
    }
 
335
}
 
336
 
 
337
void WebEditorClient::textDidChangeInTextField(Element* e)
 
338
{
 
339
    IWebFormDelegate* formDelegate;
 
340
    if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
 
341
        IDOMElement* domElement = DOMElement::createInstance(e);
 
342
        if (domElement) {
 
343
            IDOMHTMLInputElement* domInputElement;
 
344
            if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
 
345
                formDelegate->textDidChangeInTextField(domInputElement, kit(e->document()->frame()));
 
346
                domInputElement->Release();
 
347
            }
 
348
            domElement->Release();
 
349
        }
 
350
        formDelegate->Release();
 
351
    }
 
352
}
 
353
 
 
354
bool WebEditorClient::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke)
 
355
{
 
356
    BOOL result = FALSE;
 
357
    IWebFormDelegate* formDelegate;
 
358
    if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
 
359
        IDOMElement* domElement = DOMElement::createInstance(e);
 
360
        if (domElement) {
 
361
            IDOMHTMLInputElement* domInputElement;
 
362
            if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
 
363
                String command = m_webView->interpretKeyEvent(ke);
 
364
                // We allow empty commands here because the app code actually depends on this being called for all key presses.
 
365
                // We may want to revisit this later because it doesn't really make sense to send an empty command.
 
366
                formDelegate->doPlatformCommand(domInputElement, BString(command), kit(e->document()->frame()), &result);
 
367
                domInputElement->Release();
 
368
            }
 
369
            domElement->Release();
 
370
        }
 
371
        formDelegate->Release();
 
372
    }
 
373
    return !!result;
 
374
}
 
375
 
 
376
void WebEditorClient::textWillBeDeletedInTextField(Element* e)
 
377
{
 
378
    // We're using the deleteBackward command for all deletion operations since the autofill code treats all deletions the same way.
 
379
    IWebFormDelegate* formDelegate;
 
380
    if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
 
381
        IDOMElement* domElement = DOMElement::createInstance(e);
 
382
        if (domElement) {
 
383
            IDOMHTMLInputElement* domInputElement;
 
384
            if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLInputElement, (void**)&domInputElement))) {
 
385
                BOOL result;
 
386
                formDelegate->doPlatformCommand(domInputElement, BString("BackwardDelete"), kit(e->document()->frame()), &result);
 
387
                domInputElement->Release();
 
388
            }
 
389
            domElement->Release();
 
390
        }
 
391
        formDelegate->Release();
 
392
    }
 
393
}
 
394
 
 
395
void WebEditorClient::textDidChangeInTextArea(Element* e)
 
396
{
 
397
    IWebFormDelegate* formDelegate;
 
398
    if (SUCCEEDED(m_webView->formDelegate(&formDelegate)) && formDelegate) {
 
399
        IDOMElement* domElement = DOMElement::createInstance(e);
 
400
        if (domElement) {
 
401
            IDOMHTMLTextAreaElement* domTextAreaElement;
 
402
            if (SUCCEEDED(domElement->QueryInterface(IID_IDOMHTMLTextAreaElement, (void**)&domTextAreaElement))) {
 
403
                formDelegate->textDidChangeInTextArea(domTextAreaElement, kit(e->document()->frame()));
 
404
                domTextAreaElement->Release();
 
405
            }
 
406
            domElement->Release();
 
407
        }
 
408
        formDelegate->Release();
 
409
    }
 
410
}
 
411
 
 
412
class WebEditorUndoCommand : public IWebUndoCommand
 
413
{
 
414
public:
 
415
    WebEditorUndoCommand(PassRefPtr<EditCommand> editCommand, bool isUndo);
 
416
    void execute();
 
417
 
 
418
    // IUnknown
 
419
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
 
420
    virtual ULONG STDMETHODCALLTYPE AddRef(void);
 
421
    virtual ULONG STDMETHODCALLTYPE Release(void);
 
422
 
 
423
private:
 
424
    ULONG m_refCount;
 
425
    RefPtr<EditCommand> m_editCommand;
 
426
    bool m_isUndo;
 
427
};
 
428
 
 
429
WebEditorUndoCommand::WebEditorUndoCommand(PassRefPtr<EditCommand> editCommand, bool isUndo)
 
430
    : m_editCommand(editCommand)
 
431
    , m_isUndo(isUndo) 
 
432
    , m_refCount(1)
 
433
 
434
}
 
435
 
 
436
void WebEditorUndoCommand::execute()
 
437
{
 
438
    if (m_isUndo)
 
439
        m_editCommand->unapply();
 
440
    else
 
441
        m_editCommand->reapply();
 
442
}
 
443
 
 
444
HRESULT STDMETHODCALLTYPE WebEditorUndoCommand::QueryInterface(REFIID riid, void** ppvObject)
 
445
{
 
446
    *ppvObject = 0;
 
447
    if (IsEqualGUID(riid, IID_IUnknown))
 
448
        *ppvObject = static_cast<IWebUndoCommand*>(this);
 
449
    else if (IsEqualGUID(riid, IID_IWebUndoCommand))
 
450
        *ppvObject = static_cast<IWebUndoCommand*>(this);
 
451
    else
 
452
        return E_NOINTERFACE;
 
453
 
 
454
    AddRef();
 
455
    return S_OK;
 
456
}
 
457
 
 
458
ULONG STDMETHODCALLTYPE WebEditorUndoCommand::AddRef(void)
 
459
{
 
460
    return ++m_refCount;
 
461
}
 
462
 
 
463
ULONG STDMETHODCALLTYPE WebEditorUndoCommand::Release(void)
 
464
{
 
465
    ULONG newRef = --m_refCount;
 
466
    if (!newRef)
 
467
        delete(this);
 
468
 
 
469
    return newRef;
 
470
}
 
471
 
 
472
static LPCTSTR undoNameForEditAction(EditAction editAction)
 
473
{
 
474
    switch (editAction) {
 
475
        case EditActionUnspecified: return 0;
 
476
        case EditActionSetColor: return LPCTSTR_UI_STRING_KEY("Set Color", "Set Color (Undo action name)", "Undo action name");
 
477
        case EditActionSetBackgroundColor: return LPCTSTR_UI_STRING_KEY("Set Background Color", "Set Background Color (Undo action name)", "Undo action name");
 
478
        case EditActionTurnOffKerning: return LPCTSTR_UI_STRING_KEY("Turn Off Kerning", "Turn Off Kerning (Undo action name)", "Undo action name");
 
479
        case EditActionTightenKerning: return LPCTSTR_UI_STRING_KEY("Tighten Kerning", "Tighten Kerning (Undo action name)", "Undo action name");
 
480
        case EditActionLoosenKerning: return LPCTSTR_UI_STRING_KEY("Loosen Kerning", "Loosen Kerning (Undo action name)", "Undo action name");
 
481
        case EditActionUseStandardKerning: return LPCTSTR_UI_STRING_KEY("Use Standard Kerning", "Use Standard Kerning (Undo action name)", "Undo action name");
 
482
        case EditActionTurnOffLigatures: return LPCTSTR_UI_STRING_KEY("Turn Off Ligatures", "Turn Off Ligatures (Undo action name)", "Undo action name");
 
483
        case EditActionUseStandardLigatures: return LPCTSTR_UI_STRING_KEY("Use Standard Ligatures", "Use Standard Ligatures (Undo action name)", "Undo action name");
 
484
        case EditActionUseAllLigatures: return LPCTSTR_UI_STRING_KEY("Use All Ligatures", "Use All Ligatures (Undo action name)", "Undo action name");
 
485
        case EditActionRaiseBaseline: return LPCTSTR_UI_STRING_KEY("Raise Baseline", "Raise Baseline (Undo action name)", "Undo action name");
 
486
        case EditActionLowerBaseline: return LPCTSTR_UI_STRING_KEY("Lower Baseline", "Lower Baseline (Undo action name)", "Undo action name");
 
487
        case EditActionSetTraditionalCharacterShape: return LPCTSTR_UI_STRING_KEY("Set Traditional Character Shape", "Set Traditional Character Shape (Undo action name)", "Undo action name");
 
488
        case EditActionSetFont: return LPCTSTR_UI_STRING_KEY("Set Font", "Set Font (Undo action name)", "Undo action name");
 
489
        case EditActionChangeAttributes: return LPCTSTR_UI_STRING_KEY("Change Attributes", "Change Attributes (Undo action name)", "Undo action name");
 
490
        case EditActionAlignLeft: return LPCTSTR_UI_STRING_KEY("Align Left", "Align Left (Undo action name)", "Undo action name");
 
491
        case EditActionAlignRight: return LPCTSTR_UI_STRING_KEY("Align Right", "Align Right (Undo action name)", "Undo action name");
 
492
        case EditActionCenter: return LPCTSTR_UI_STRING_KEY("Center", "Center (Undo action name)", "Undo action name");
 
493
        case EditActionJustify: return LPCTSTR_UI_STRING_KEY("Justify", "Justify (Undo action name)", "Undo action name");
 
494
        case EditActionSetWritingDirection: return LPCTSTR_UI_STRING_KEY("Set Writing Direction", "Set Writing Direction (Undo action name)", "Undo action name");
 
495
        case EditActionSubscript: return LPCTSTR_UI_STRING_KEY("Subscript", "Subscript (Undo action name)", "Undo action name");
 
496
        case EditActionSuperscript: return LPCTSTR_UI_STRING_KEY("Superscript", "Superscript (Undo action name)", "Undo action name");
 
497
        case EditActionUnderline: return LPCTSTR_UI_STRING_KEY("Underline", "Underline (Undo action name)", "Undo action name");
 
498
        case EditActionOutline: return LPCTSTR_UI_STRING_KEY("Outline", "Outline (Undo action name)", "Undo action name");
 
499
        case EditActionUnscript: return LPCTSTR_UI_STRING_KEY("Unscript", "Unscript (Undo action name)", "Undo action name");
 
500
        case EditActionDrag: return LPCTSTR_UI_STRING_KEY("Drag", "Drag (Undo action name)", "Undo action name");
 
501
        case EditActionCut: return LPCTSTR_UI_STRING_KEY("Cut", "Cut (Undo action name)", "Undo action name");
 
502
        case EditActionPaste: return LPCTSTR_UI_STRING_KEY("Paste", "Paste (Undo action name)", "Undo action name");
 
503
        case EditActionPasteFont: return LPCTSTR_UI_STRING_KEY("Paste Font", "Paste Font (Undo action name)", "Undo action name");
 
504
        case EditActionPasteRuler: return LPCTSTR_UI_STRING_KEY("Paste Ruler", "Paste Ruler (Undo action name)", "Undo action name");
 
505
        case EditActionTyping: return LPCTSTR_UI_STRING_KEY("Typing", "Typing (Undo action name)", "Undo action name");
 
506
        case EditActionCreateLink: return LPCTSTR_UI_STRING_KEY("Create Link", "Create Link (Undo action name)", "Undo action name");
 
507
        case EditActionUnlink: return LPCTSTR_UI_STRING_KEY("Unlink", "Unlink (Undo action name)", "Undo action name");
 
508
        case EditActionInsertList: return LPCTSTR_UI_STRING_KEY("Insert List", "Insert List (Undo action name)", "Undo action name");
 
509
        case EditActionFormatBlock: return LPCTSTR_UI_STRING_KEY("Formatting", "Format Block (Undo action name)", "Undo action name");
 
510
        case EditActionIndent: return LPCTSTR_UI_STRING_KEY("Indent", "Indent (Undo action name)", "Undo action name");
 
511
        case EditActionOutdent: return LPCTSTR_UI_STRING_KEY("Outdent", "Outdent (Undo action name)", "Undo action name");
 
512
    }
 
513
    return 0;
 
514
}
 
515
 
 
516
void WebEditorClient::registerCommandForUndo(PassRefPtr<EditCommand> command)
 
517
{
 
518
    IWebUIDelegate* uiDelegate = 0;
 
519
    if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
 
520
        LPCTSTR actionName = undoNameForEditAction(command->editingAction());
 
521
        WebEditorUndoCommand* undoCommand = new WebEditorUndoCommand(command, true);
 
522
        if (!undoCommand)
 
523
            return;
 
524
        uiDelegate->registerUndoWithTarget(m_undoTarget, 0, undoCommand);
 
525
        undoCommand->Release(); // the undo manager owns the reference
 
526
        BSTR actionNameBSTR = SysAllocString(actionName);
 
527
        if (actionNameBSTR) {
 
528
            uiDelegate->setActionTitle(actionNameBSTR);
 
529
            SysFreeString(actionNameBSTR);
 
530
        }
 
531
        uiDelegate->Release();
 
532
    }
 
533
}
 
534
 
 
535
void WebEditorClient::registerCommandForRedo(PassRefPtr<EditCommand> command)
 
536
{
 
537
    IWebUIDelegate* uiDelegate = 0;
 
538
    if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
 
539
        WebEditorUndoCommand* undoCommand = new WebEditorUndoCommand(command, false);
 
540
        if (!undoCommand)
 
541
            return;
 
542
        uiDelegate->registerUndoWithTarget(m_undoTarget, 0, undoCommand);
 
543
        undoCommand->Release(); // the undo manager owns the reference
 
544
        uiDelegate->Release();
 
545
    }
 
546
}
 
547
 
 
548
void WebEditorClient::clearUndoRedoOperations()
 
549
{
 
550
    IWebUIDelegate* uiDelegate = 0;
 
551
    if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
 
552
        uiDelegate->removeAllActionsWithTarget(m_undoTarget);
 
553
        uiDelegate->Release();
 
554
    }
 
555
}
 
556
 
 
557
bool WebEditorClient::canUndo() const
 
558
{
 
559
    BOOL result = FALSE;
 
560
    IWebUIDelegate* uiDelegate = 0;
 
561
    if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
 
562
        uiDelegate->canUndo(&result);
 
563
        uiDelegate->Release();
 
564
    }
 
565
    return !!result;
 
566
}
 
567
 
 
568
bool WebEditorClient::canRedo() const
 
569
{
 
570
    BOOL result = FALSE;
 
571
    IWebUIDelegate* uiDelegate = 0;
 
572
    if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
 
573
        uiDelegate->canRedo(&result);
 
574
        uiDelegate->Release();
 
575
    }
 
576
    return !!result;
 
577
}
 
578
 
 
579
void WebEditorClient::undo()
 
580
{
 
581
    IWebUIDelegate* uiDelegate = 0;
 
582
    if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
 
583
        uiDelegate->undo();
 
584
        uiDelegate->Release();
 
585
    }
 
586
}
 
587
 
 
588
void WebEditorClient::redo()
 
589
{
 
590
    IWebUIDelegate* uiDelegate = 0;
 
591
    if (SUCCEEDED(m_webView->uiDelegate(&uiDelegate))) {
 
592
        uiDelegate->redo();
 
593
        uiDelegate->Release();
 
594
    }
 
595
}
 
596
 
 
597
void WebEditorClient::handleKeypress(KeyboardEvent* evt)
 
598
{
 
599
    if (m_webView->handleEditingKeyboardEvent(evt))
 
600
        evt->setDefaultHandled();
 
601
}
 
602
 
 
603
void WebEditorClient::handleInputMethodKeypress(KeyboardEvent* evt)
 
604
{
 
605
    if (m_webView->inIMEKeyDown())
 
606
        evt->setDefaultHandled();
 
607
}
 
608
 
 
609
bool WebEditorClient::isEditable()
 
610
{
 
611
    return false;
 
612
}
 
613
 
 
614
void WebEditorClient::ignoreWordInSpellDocument(const String& word)
 
615
{
 
616
    COMPtr<IWebEditingDelegate> ed;
 
617
    if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
 
618
        return;
 
619
 
 
620
    initViewSpecificSpelling(m_webView);
 
621
    ed->ignoreWordInSpellDocument(m_webView, BString(word));
 
622
}
 
623
 
 
624
void WebEditorClient::learnWord(const String& word)
 
625
{
 
626
    COMPtr<IWebEditingDelegate> ed;
 
627
    if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
 
628
        return;
 
629
 
 
630
    ed->learnWord(BString(word));
 
631
}
 
632
 
 
633
void WebEditorClient::checkSpellingOfString(const UChar* text, int length, int* misspellingLocation, int* misspellingLength)
 
634
{
 
635
    *misspellingLocation = -1;
 
636
    *misspellingLength = 0;
 
637
 
 
638
    COMPtr<IWebEditingDelegate> ed;
 
639
    if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
 
640
        return;
 
641
 
 
642
    initViewSpecificSpelling(m_webView);
 
643
    ed->checkSpellingOfString(m_webView, text, length, misspellingLocation, misspellingLength);
 
644
}
 
645
 
 
646
void WebEditorClient::checkGrammarOfString(const UChar* text, int length, Vector<GrammarDetail>& details, int* badGrammarLocation, int* badGrammarLength)
 
647
{
 
648
    details.clear();
 
649
    *badGrammarLocation = -1;
 
650
    *badGrammarLength = 0;
 
651
 
 
652
    COMPtr<IWebEditingDelegate> ed;
 
653
    if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
 
654
        return;
 
655
 
 
656
    initViewSpecificSpelling(m_webView);
 
657
    COMPtr<IEnumWebGrammarDetails> enumDetailsObj;
 
658
    if (FAILED(ed->checkGrammarOfString(m_webView, text, length, &enumDetailsObj, badGrammarLocation, badGrammarLength)))
 
659
        return;
 
660
 
 
661
    while (true) {
 
662
        ULONG fetched;
 
663
        COMPtr<IWebGrammarDetail> detailObj;
 
664
        if (enumDetailsObj->Next(1, &detailObj, &fetched) != S_OK)
 
665
            break;
 
666
 
 
667
        GrammarDetail detail;
 
668
        if (FAILED(detailObj->length(&detail.length)))
 
669
            continue;
 
670
        if (FAILED(detailObj->location(&detail.location)))
 
671
            continue;
 
672
        BSTR userDesc;
 
673
        if (FAILED(detailObj->userDescription(&userDesc)))
 
674
            continue;
 
675
        detail.userDescription = String(userDesc, SysStringLen(userDesc));
 
676
        SysFreeString(userDesc);
 
677
 
 
678
        COMPtr<IEnumSpellingGuesses> enumGuessesObj;
 
679
        if (FAILED(detailObj->guesses(&enumGuessesObj)))
 
680
            continue;
 
681
        while (true) {
 
682
            BSTR guess;
 
683
            if (enumGuessesObj->Next(1, &guess, &fetched) != S_OK)
 
684
                break;
 
685
            detail.guesses.append(String(guess, SysStringLen(guess)));
 
686
            SysFreeString(guess);
 
687
        }
 
688
 
 
689
        details.append(detail);
 
690
    }
 
691
}
 
692
 
 
693
void WebEditorClient::updateSpellingUIWithGrammarString(const String& string, const WebCore::GrammarDetail& detail)
 
694
{
 
695
    COMPtr<IWebEditingDelegate> ed;
 
696
    if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
 
697
        return;
 
698
 
 
699
    Vector<BSTR> guessesBSTRs;
 
700
    for (unsigned i = 0; i < detail.guesses.size(); i++) {
 
701
        BString guess(detail.guesses[i]);
 
702
        guessesBSTRs.append(guess.release());
 
703
    }
 
704
    BString userDescriptionBSTR(detail.userDescription);
 
705
    ed->updateSpellingUIWithGrammarString(BString(string), detail.location, detail.length, userDescriptionBSTR, guessesBSTRs.data(), (int)guessesBSTRs.size());
 
706
    for (unsigned i = 0; i < guessesBSTRs.size(); i++)
 
707
        SysFreeString(guessesBSTRs[i]);
 
708
}
 
709
 
 
710
void WebEditorClient::updateSpellingUIWithMisspelledWord(const String& word)
 
711
{
 
712
    COMPtr<IWebEditingDelegate> ed;
 
713
    if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
 
714
        return;
 
715
 
 
716
    ed->updateSpellingUIWithMisspelledWord(BString(word));
 
717
}
 
718
 
 
719
void WebEditorClient::showSpellingUI(bool show)
 
720
{
 
721
    COMPtr<IWebEditingDelegate> ed;
 
722
    if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
 
723
        return;
 
724
    
 
725
    ed->showSpellingUI(show);
 
726
}
 
727
 
 
728
bool WebEditorClient::spellingUIIsShowing()
 
729
{
 
730
    COMPtr<IWebEditingDelegate> ed;
 
731
    if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
 
732
        return false;
 
733
 
 
734
    BOOL showing;
 
735
    if (FAILED(ed->spellingUIIsShowing(&showing)))
 
736
        return false;
 
737
 
 
738
    return !!showing;
 
739
}
 
740
 
 
741
void WebEditorClient::getGuessesForWord(const String& word, Vector<String>& guesses)
 
742
{
 
743
    guesses.clear();
 
744
 
 
745
    COMPtr<IWebEditingDelegate> ed;
 
746
    if (FAILED(m_webView->editingDelegate(&ed)) || !ed.get())
 
747
        return;
 
748
 
 
749
    COMPtr<IEnumSpellingGuesses> enumGuessesObj;
 
750
    if (FAILED(ed->guessesForWord(BString(word), &enumGuessesObj)))
 
751
        return;
 
752
 
 
753
    while (true) {
 
754
        ULONG fetched;
 
755
        BSTR guess;
 
756
        if (enumGuessesObj->Next(1, &guess, &fetched) != S_OK)
 
757
            break;
 
758
        guesses.append(String(guess, SysStringLen(guess)));
 
759
        SysFreeString(guess);
 
760
    }
 
761
}
 
762