4546ea354e3e608ef2b3ac5675915c48dfec5269
[WebKit-https.git] / WebCore / page / ContextMenuController.cpp
1 /*
2  * Copyright (C) 2006 Apple Computer, 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 "ContextMenuController.h"
28
29 #include "Chrome.h"
30 #include "ContextMenu.h"
31 #include "ContextMenuClient.h"
32 #include "Document.h"
33 #include "DocumentFragment.h"
34 #include "DocumentLoader.h"
35 #include "Editor.h"
36 #include "EditorClient.h"
37 #include "Event.h"
38 #include "EventNames.h"
39 #include "Frame.h"
40 #include "FrameLoader.h"
41 #include "FrameLoadRequest.h"
42 #include "HitTestRequest.h"
43 #include "HitTestResult.h"
44 #include "KURL.h"
45 #include "MouseEvent.h"
46 #include "Node.h"
47 #include "Page.h"
48 #include "RenderLayer.h"
49 #include "RenderObject.h"
50 #include "ReplaceSelectionCommand.h"
51 #include "ResourceRequest.h"
52 #include "SelectionController.h"
53 #include "markup.h"
54
55 namespace WebCore {
56
57 using namespace EventNames;
58
59 ContextMenuController::ContextMenuController(Page* page, ContextMenuClient* client)
60     : m_page(page)
61     , m_client(client)
62     , m_contextMenu(0)
63 {
64 }
65
66 ContextMenuController::~ContextMenuController()
67 {
68     m_client->contextMenuDestroyed();
69 }
70
71 void ContextMenuController::handleContextMenuEvent(Event* event)
72 {
73     ASSERT(event->type() == contextmenuEvent);
74     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
75     HitTestResult result(IntPoint(mouseEvent->pageX(), mouseEvent->pageY()));
76
77     if (RenderObject* renderer = event->target()->renderer())
78         if (RenderLayer* layer = renderer->enclosingLayer())
79             layer->hitTest(HitTestRequest(false, true), result);
80
81     if (!result.innerNonSharedNode())
82         return;
83
84     m_contextMenu.set(new ContextMenu(result));
85     m_contextMenu->populate();
86     m_client->addCustomContextMenuItems(m_contextMenu.get());
87     m_contextMenu->show();
88
89     event->setDefaultHandled();
90 }
91
92 static String makeGoogleSearchURL(String searchString)
93 {
94     searchString.stripWhiteSpace();
95     DeprecatedString encoded = KURL::encode_string(searchString.deprecatedString());
96     encoded.replace(DeprecatedString("%20"), DeprecatedString("+"));
97     
98     String url("http://www.google.com/search?client=safari&q=");
99     url.append(String(encoded));
100     url.append("&ie=UTF-8&oe=UTF-8");
101     return url;
102 }
103
104 void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item)
105 {
106     ASSERT(item->menu() == contextMenu());
107     ASSERT(item->type() == ActionType);
108
109     if (item->action() >= ContextMenuItemBaseApplicationTag) {
110         m_client->contextMenuItemSelected(item);
111         return;
112     }
113
114     Frame* frame = m_contextMenu->hitTestResult().innerNonSharedNode()->document()->frame();
115     if (!frame)
116         return;
117     ASSERT(m_page == frame->page());
118     
119     switch (item->action()) {
120         case ContextMenuItemTagOpenLinkInNewWindow: {
121             ResourceRequest request = ResourceRequest(m_contextMenu->hitTestResult().absoluteLinkURL());
122             String referrer = frame->loader()->referrer();
123             m_page->chrome()->createWindow(FrameLoadRequest(request, referrer));
124             break;
125         }
126         case ContextMenuItemTagDownloadLinkToDisk:
127             // FIXME: Some day we should be able to do this from within WebCore.
128             m_client->downloadURL(m_contextMenu->hitTestResult().absoluteLinkURL());
129             break;
130         case ContextMenuItemTagCopyLinkToClipboard:
131             // FIXME: The Pasteboard class is not written yet. This is what we should be able to do some day:
132             // generalPasteboard()->copy(m_contextMenu->hitTestResult().absoluteLinkURL(), 
133             //      m_contextMenu->hitTestResult.textContent());
134             // For now, call into the client. This is temporary!
135             m_client->copyLinkToClipboard(m_contextMenu->hitTestResult());
136             break;
137         case ContextMenuItemTagOpenImageInNewWindow: {
138             ResourceRequest request = ResourceRequest(m_contextMenu->hitTestResult().absoluteImageURL());
139             String referrer = frame->loader()->referrer();
140             m_page->chrome()->createWindow(FrameLoadRequest(request, referrer));
141             break;
142         }
143         case ContextMenuItemTagDownloadImageToDisk:
144             // FIXME: Some day we should be able to do this from within WebCore.
145             m_client->downloadURL(m_contextMenu->hitTestResult().absoluteImageURL());
146             break;
147         case ContextMenuItemTagCopyImageToClipboard:
148             // FIXME: The Pasteboard class is not written yet
149             // For now, call into the client. This is temporary!
150             m_client->copyImageToClipboard(m_contextMenu->hitTestResult());
151             break;
152         case ContextMenuItemTagOpenFrameInNewWindow: {
153             // FIXME: The DocumentLoader is all-Mac right now
154 #if PLATFORM(MAC)
155             KURL unreachableURL = frame->loader()->documentLoader()->unreachableURL();
156             if (frame && unreachableURL.isEmpty())
157                 unreachableURL = frame->loader()->documentLoader()->URL();
158             ResourceRequest request = ResourceRequest(unreachableURL);
159             String referrer = frame->loader()->referrer();
160             if (m_page)
161                 m_page->chrome()->createWindow(FrameLoadRequest(request, referrer));
162 #endif
163             break;
164         }
165         case ContextMenuItemTagCopy:
166             frame->editor()->copy();
167             break;
168         case ContextMenuItemTagGoBack:
169             frame->loader()->goBackOrForward(-1);
170             break;
171         case ContextMenuItemTagGoForward:
172             frame->loader()->goBackOrForward(1);
173             break;
174         case ContextMenuItemTagStop:
175             frame->loader()->stop();
176             break;
177         case ContextMenuItemTagReload:
178             frame->loader()->reload();
179             break;
180         case ContextMenuItemTagCut:
181             frame->editor()->cut();
182             break;
183         case ContextMenuItemTagPaste:
184             frame->editor()->paste();
185             break;
186         case ContextMenuItemTagSpellingGuess:
187             ASSERT(frame->selectedText().length());
188             if (frame->editor()->shouldInsertText(item->title(), frame->selectionController()->toRange().get(), EditorInsertActionPasted)) {
189                 Document* document = frame->document();
190                 applyCommand(new ReplaceSelectionCommand(document, createFragmentFromMarkup(document, item->title(), ""),
191                     true, false, true));
192                 frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
193             }
194             break;
195         case ContextMenuItemTagIgnoreSpelling:
196             frame->ignoreSpelling();
197             break;
198         case ContextMenuItemTagLearnSpelling:
199             frame->learnSpelling();
200             break;
201         case ContextMenuItemTagSearchInSpotlight:
202 #if PLATFORM(MAC)
203             m_client->searchWithSpotlight();
204 #endif
205             break;
206         case ContextMenuItemTagSearchWeb: {
207             String url = makeGoogleSearchURL(frame->selectedText());
208             ResourceRequest request = ResourceRequest(url);
209             frame->loader()->urlSelected(FrameLoadRequest(request), new Event());
210             break;
211         }
212         case ContextMenuItemTagLookUpInDictionary:
213             // FIXME: Some day we may be able to do this from within WebCore.
214             m_client->lookUpInDictionary(frame);
215             break;
216         // PDF actions. Let's take care of this later. 
217         case ContextMenuItemTagOpenWithDefaultApplication:
218         case ContextMenuItemPDFActualSize:
219         case ContextMenuItemPDFZoomIn:
220         case ContextMenuItemPDFZoomOut:
221         case ContextMenuItemPDFAutoSize:
222         case ContextMenuItemPDFSinglePage:
223         case ContextMenuItemPDFFacingPages:
224         case ContextMenuItemPDFContinuous:
225         case ContextMenuItemPDFNextPage:
226         case ContextMenuItemPDFPreviousPage:
227         default:
228             break;
229     }
230 }
231
232 } // namespace WebCore
233