WebCore:
[WebKit-https.git] / WebCore / platform / ContextMenu.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 "ContextMenu.h"
28
29 #include "ContextMenuController.h"
30 #include "Document.h"
31 #include "Frame.h"
32 #include "FrameLoader.h"
33 #include "KURL.h"
34 #include "Node.h"
35 #include "Page.h"
36 #include "ResourceRequest.h"
37 #include "SelectionController.h"
38
39 namespace WebCore {
40
41 #define MENU_ACTION_ITEM(action, title) static ContextMenuItem action##Item(ActionType, ContextMenuItemTag##action, String(title))
42
43 ContextMenuController* ContextMenu::controller() const
44 {
45     if (Node* node = m_hitTestResult.innerNonSharedNode())
46         if (Frame* frame = node->document()->frame())
47             if (Page* page = frame->page())
48                 return page->contextMenuController();
49     return 0;
50 }
51
52 static void createFontSubMenu(const HitTestResult& result, ContextMenuItem& fontMenuItem)
53 {
54     static ContextMenuItem SeparatorItem(SeparatorType, ContextMenuItemTagNoAction, String());
55
56     MENU_ACTION_ITEM(ShowFonts, "Show Fonts");
57     MENU_ACTION_ITEM(Bold, "Bold");
58     MENU_ACTION_ITEM(Italic, "Italic");
59     MENU_ACTION_ITEM(Underline, "Underline");
60     MENU_ACTION_ITEM(Outline, "Outline");
61     MENU_ACTION_ITEM(Styles, "Styles...");
62     MENU_ACTION_ITEM(ShowColors, "Show Colors");
63     
64     ContextMenu* fontMenu = new ContextMenu(result);
65     fontMenu->appendItem(ShowFontsItem);
66     fontMenu->appendItem(BoldItem);
67     fontMenu->appendItem(ItalicItem);
68     fontMenu->appendItem(UnderlineItem);
69     fontMenu->appendItem(OutlineItem);
70     fontMenu->appendItem(StylesItem);
71     fontMenu->appendItem(SeparatorItem);
72     fontMenu->appendItem(ShowColorsItem);
73     fontMenuItem.setSubMenu(fontMenu);
74 }
75
76 #ifndef BUILDING_ON_TIGER
77 static void createSpellingAndGrammarSubMenu(const HitTestResult& result, ContextMenuItem& spellingAndGrammarMenuItem)
78 {
79     MENU_ACTION_ITEM(ShowSpellingAndGrammar, "Show Spelling and Grammar");
80     MENU_ACTION_ITEM(CheckDocumentNow, "Check Document Now");
81     MENU_ACTION_ITEM(CheckSpellingWhileTyping, "Check Spelling While Typing");
82     MENU_ACTION_ITEM(CheckGrammarWithSpelling, "Check Grammar With Spelling");
83
84     ContextMenu* spellingAndGrammarMenu = new ContextMenu(result);
85     spellingAndGrammarMenu->appendItem(ShowSpellingAndGrammarItem);
86     spellingAndGrammarMenu->appendItem(CheckDocumentNowItem);
87     spellingAndGrammarMenu->appendItem(CheckSpellingWhileTypingItem);
88     spellingAndGrammarMenu->appendItem(CheckGrammarWithSpellingItem);
89     spellingAndGrammarMenuItem.setSubMenu(spellingAndGrammarMenu);
90 }
91 #else
92 static void createSpellingSubMenu(const HitTestResult& result, ContextMenuItem& spellingMenuItem)
93 {
94     MENU_ACTION_ITEM(SpellingMenuItem, "Spelling...");
95     MENU_ACTION_ITEM(CheckSpelling, "Check Spelling");
96     MENU_ACTION_ITEM(CheckSpellingWhileTyping, "Check Spelling as You Type");
97
98     ContextMenu* spellingMenu = new ContextMenu(result);
99     spellingMenu->appendItem(SpellingMenuItemItem);
100     spellingMenu->appendItem(CheckSpellingItem);
101     spellingMenu->appendItem(CheckSpellingWhileTypingItem);
102     spellingMenuItem.setSubMenu(spellingMenu);
103 }
104 #endif
105
106 #if PLATFORM(MAC)
107 static void createSpeechSubMenu(const HitTestResult& result, ContextMenuItem& speechMenuItem)
108 {
109     MENU_ACTION_ITEM(StartSpeaking, "Start Speaking");
110     MENU_ACTION_ITEM(StopSpeaking, "Stop Speaking");
111
112     ContextMenu* speechMenu = new ContextMenu(result);
113     speechMenu->appendItem(StartSpeakingItem);
114     speechMenu->appendItem(StopSpeakingItem);
115     speechMenuItem.setSubMenu(speechMenu);
116 }
117 #endif
118
119 static void createWritingDirectionSubMenu(const HitTestResult& result, ContextMenuItem& writingDirectionMenuItem)
120 {
121     MENU_ACTION_ITEM(DefaultDirection, "Default");
122     MENU_ACTION_ITEM(LeftToRight, "Left to Right");
123     MENU_ACTION_ITEM(RightToLeft, "Right to Left");
124
125     ContextMenu* writingDirectionMenu = new ContextMenu(result);
126     writingDirectionMenu->appendItem(DefaultDirectionItem);
127     writingDirectionMenu->appendItem(LeftToRightItem);
128     writingDirectionMenu->appendItem(RightToLeftItem);
129     writingDirectionMenuItem.setSubMenu(writingDirectionMenu);
130 }
131
132 void ContextMenu::populate()
133 {
134     static ContextMenuItem SeparatorItem(SeparatorType, ContextMenuItemTagNoAction, String());
135
136     MENU_ACTION_ITEM(OpenLinkInNewWindow, "Open Link in New Window");
137     MENU_ACTION_ITEM(DownloadLinkToDisk, "Download Linked File");
138     MENU_ACTION_ITEM(CopyLinkToClipboard, "Copy Link");
139     MENU_ACTION_ITEM(OpenImageInNewWindow, "Open Image in New Window");
140     MENU_ACTION_ITEM(DownloadImageToDisk, "Download Image");
141     MENU_ACTION_ITEM(CopyImageToClipboard, "Copy Image");
142     MENU_ACTION_ITEM(OpenFrameInNewWindow, "Open Frame in New Window");
143     MENU_ACTION_ITEM(Copy, "Copy");
144     MENU_ACTION_ITEM(GoBack, "Back");
145     MENU_ACTION_ITEM(GoForward, "Forward");
146     MENU_ACTION_ITEM(Stop, "Stop");
147     MENU_ACTION_ITEM(Reload, "Reload");
148     MENU_ACTION_ITEM(Cut, "Cut");
149     MENU_ACTION_ITEM(Paste, "Paste");
150     MENU_ACTION_ITEM(SpellingGuess, "");
151     MENU_ACTION_ITEM(NoGuessesFound, "No Guesses Found");
152     MENU_ACTION_ITEM(IgnoreSpelling, "Ignore Spelling");
153     MENU_ACTION_ITEM(LearnSpelling, "Learn Spelling");
154 #if PLATFORM(MAC)
155     MENU_ACTION_ITEM(SearchInSpotlight, "Search in Spotlight");
156 #endif
157     MENU_ACTION_ITEM(SearchWeb, "Search in Google");
158     MENU_ACTION_ITEM(LookUpInDictionary, "Look Up in Dictionary");
159     MENU_ACTION_ITEM(OpenLink, "Open Link");
160
161     HitTestResult result = hitTestResult();
162     
163     Node* node = m_hitTestResult.innerNonSharedNode();
164     if (!node)
165         return;
166     Frame* frame = node->document()->frame();
167     if (!frame)
168         return;
169
170     if (!result.isContentEditable()) {
171         FrameLoader* loader = frame->loader();
172         KURL linkURL = result.absoluteLinkURL();
173         if (!linkURL.isEmpty()) {
174             if (loader->canHandleRequest(ResourceRequest(linkURL))) {
175                 appendItem(OpenLinkItem);
176                 appendItem(OpenLinkInNewWindowItem);
177                 appendItem(DownloadLinkToDiskItem);
178             }
179             appendItem(CopyLinkToClipboardItem);
180         }
181
182         KURL imageURL = result.absoluteImageURL();
183         if (!imageURL.isEmpty()) {
184             if (!linkURL.isEmpty())
185                 appendItem(SeparatorItem);
186
187             appendItem(OpenImageInNewWindowItem);
188             appendItem(DownloadImageToDiskItem);
189             if (imageURL.isLocalFile()) // FIXME: Should be checking if the image is local or we have a file wrapper for it
190                 appendItem(CopyImageToClipboardItem);
191         }
192
193         if (imageURL.isEmpty() && linkURL.isEmpty()) {
194             if (result.isSelected()) {
195 #if PLATFORM(MAC)
196                 appendItem(SearchInSpotlightItem);
197 #endif
198                 appendItem(SearchWebItem);
199                 appendItem(SeparatorItem);
200                 appendItem(LookUpInDictionaryItem);
201                 appendItem(SeparatorItem);
202                 appendItem(CopyItem);
203             } else {
204                 if (loader->canGoBackOrForward(-1))
205                     appendItem(GoBackItem);
206
207                 if (loader->canGoBackOrForward(1))
208                     appendItem(GoForwardItem);
209                 
210                 if (loader->isLoading())
211                     appendItem(StopItem);
212                 else
213                     appendItem(ReloadItem);
214
215                 if (frame->page() && frame != frame->page()->mainFrame())
216                     appendItem(OpenFrameInNewWindowItem);
217             }
218         }
219     } else { // Make an editing context menu
220         SelectionController* selectionController = frame->selectionController();
221         bool inPasswordField = selectionController->isInPasswordField();
222
223         // Add spelling-related context menu items.
224         if (frame->isSelectionMisspelled() && !inPasswordField) {
225             Vector<String> guesses = frame->guessesForMisspelledSelection();
226             unsigned size = guesses.size();
227             if (size == 0)
228                 appendItem(NoGuessesFoundItem);
229             else {
230                 for (unsigned i = 0; i < size; i++) {
231                     String guess = guesses[i];
232                     if (!guess.isNull()) {
233                         ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess);
234                         appendItem(item);
235                     }
236                 }
237             }                
238
239             appendItem(SeparatorItem);
240             appendItem(IgnoreSpellingItem);
241             appendItem(LearnSpellingItem);
242             appendItem(SeparatorItem);
243         }
244
245         if (result.isSelected() && !inPasswordField) {
246 #if PLATFORM(MAC)
247             appendItem(SearchInSpotlightItem);
248 #endif
249             appendItem(SearchWebItem);
250             appendItem(SeparatorItem);
251      
252             appendItem(LookUpInDictionaryItem);
253             appendItem(SeparatorItem);
254         }
255
256         appendItem(CutItem);
257         appendItem(CopyItem);
258         appendItem(PasteItem);
259
260         if (!inPasswordField) {
261             appendItem(SeparatorItem);
262 #ifndef BUILDING_ON_TIGER
263             ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingAndGrammarMenu,
264                 "Spelling and Grammar");
265             createSpellingAndGrammarSubMenu(m_hitTestResult, SpellingAndGrammarMenuItem);
266             appendItem(SpellingAndGrammarMenuItem);
267 #else
268             ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, "Spelling");
269             createSpellingSubMenu(m_hitTestResult, SpellingMenuItem);
270             appendItem(SpellingMenuItem);
271 #endif
272             ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu, "Font");
273             createFontSubMenu(m_hitTestResult, FontMenuItem);
274             appendItem(FontMenuItem);
275 #if PLATFORM(MAC)
276             ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, "Speech");
277             createSpeechSubMenu(m_hitTestResult, SpeechMenuItem);
278             appendItem(SpeechMenuItem);
279 #endif
280             ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu,
281                 "Writing Direction");
282             createWritingDirectionSubMenu(m_hitTestResult, WritingDirectionMenuItem);
283             appendItem(WritingDirectionMenuItem);
284         }
285     }
286 }
287
288 }