Fixed Panther build (missing ifdef)
[WebKit-https.git] / WebKit / WebView.subproj / WebDefaultContextMenuDelegate.m
1 /*
2       WebDefaultContextMenuDelegate.m
3       Copyright 2002, Apple, Inc. All rights reserved.
4 */
5
6 #import <WebKit/WebDefaultContextMenuDelegate.h>
7
8 #import <WebKit/WebAssertions.h>
9 #import <WebKit/DOM.h>
10 #import <WebKit/WebBridge.h>
11 #import <WebKit/WebDataSourcePrivate.h>
12 #import <WebKit/WebDefaultUIDelegate.h>
13 #import <WebKit/WebDOMOperations.h>
14 #import <WebKit/WebFramePrivate.h>
15 #import <WebKit/WebHTMLViewPrivate.h>
16 #import <WebKit/WebLocalizableStrings.h>
17 #import <WebKit/WebNSPasteboardExtras.h>
18 #import <WebKit/WebFrameView.h>
19 #import <WebKit/WebPolicyDelegate.h>
20 #import <WebKit/WebViewPrivate.h>
21 #import <WebKit/WebUIDelegate.h>
22 #import <WebKit/WebUIDelegatePrivate.h>
23
24 #import <WebCore/WebCoreBridge.h>
25
26 #import <Foundation/NSURLConnection.h>
27 #import <Foundation/NSURLRequest.h>
28 #import <Foundation/NSURLRequestPrivate.h>
29
30 @implementation WebDefaultUIDelegate (WebContextMenu)
31
32 #ifndef OMIT_TIGER_FEATURES
33 static NSString *localizedMenuTitleFromAppKit(NSString *key, NSString *comment)
34 {
35     NSBundle *appKitBundle = [NSBundle bundleWithIdentifier:@"com.apple.AppKit"];
36     if (!appKitBundle) {
37         return key;
38     }
39     return NSLocalizedStringFromTableInBundle(key, @"MenuCommands", appKitBundle, comment);
40 }
41 #endif
42
43 - (NSMenuItem *)menuItemWithTag:(int)tag
44 {
45     NSMenuItem *menuItem = [[[NSMenuItem alloc] init] autorelease];
46     [menuItem setTag:tag];
47     
48     NSString *title = nil;
49     SEL action = NULL;
50     
51     switch(tag) {
52         case WebMenuItemTagOpenLinkInNewWindow:
53             title = UI_STRING("Open Link in New Window", "Open in New Window context menu item");
54             action = @selector(openLinkInNewWindow:);
55             [menuItem setTarget:self];
56             break;
57         case WebMenuItemTagDownloadLinkToDisk:
58             title = UI_STRING("Download Linked File", "Download Linked File context menu item");
59             action = @selector(downloadLinkToDisk:);
60             [menuItem setTarget:self];
61             break;
62         case WebMenuItemTagCopyLinkToClipboard:
63             title = UI_STRING("Copy Link", "Copy Link context menu item");
64             action = @selector(copyLinkToClipboard:);
65             [menuItem setTarget:self];
66             break;
67         case WebMenuItemTagOpenImageInNewWindow:
68             title = UI_STRING("Open Image in New Window", "Open Image in New Window context menu item");
69             action = @selector(openImageInNewWindow:);
70             [menuItem setTarget:self];
71             break;
72         case WebMenuItemTagDownloadImageToDisk:
73             title = UI_STRING("Download Image", "Download Image context menu item");
74             action = @selector(downloadImageToDisk:);
75             [menuItem setTarget:self];
76             break;
77         case WebMenuItemTagCopyImageToClipboard:
78             title = UI_STRING("Copy Image", "Copy Image context menu item");
79             action = @selector(copyImageToClipboard:);
80             [menuItem setTarget:self];
81             break;
82         case WebMenuItemTagOpenFrameInNewWindow:
83             title = UI_STRING("Open Frame in New Window", "Open Frame in New Window context menu item");
84             action = @selector(openFrameInNewWindow:);
85             [menuItem setTarget:self];
86             break;
87         case WebMenuItemTagCopy:
88             title = UI_STRING("Copy", "Copy context menu item");
89             action = @selector(copy:);
90             break;
91         case WebMenuItemTagGoBack:
92             title = UI_STRING("Back", "Back context menu item");
93             action = @selector(goBack:);
94             break;
95         case WebMenuItemTagGoForward:
96             title = UI_STRING("Forward", "Forward context menu item");
97             action = @selector(goForward:);
98             break;
99         case WebMenuItemTagStop:
100             title = UI_STRING("Stop", "Stop context menu item");
101             action = @selector(stopLoading:);
102             break;
103         case WebMenuItemTagReload:
104             title = UI_STRING("Reload", "Reload context menu item");
105             action = @selector(reload:);
106             break;
107         case WebMenuItemTagCut:
108             title = UI_STRING("Cut", "Cut context menu item");
109             action = @selector(cut:);
110             break;
111         case WebMenuItemTagPaste:
112             title = UI_STRING("Paste", "Paste context menu item");
113             action = @selector(paste:);
114             break;
115         case WebMenuItemTagSpellingGuess:
116             action = @selector(_changeSpellingFromMenu:);
117             break;
118         case WebMenuItemTagNoGuessesFound:
119             title = UI_STRING("No Guesses Found", "No Guesses Found context menu item");
120             break;
121         case WebMenuItemTagIgnoreSpelling:
122             title = UI_STRING("Ignore Spelling", "Ignore Spelling context menu item");
123             action = @selector(_ignoreSpellingFromMenu:);
124             break;
125         case WebMenuItemTagLearnSpelling:
126             title = UI_STRING("Learn Spelling", "Learn Spelling context menu item");
127             action = @selector(_learnSpellingFromMenu:);
128             break;
129 #ifndef OMIT_TIGER_FEATURES
130         case WebMenuItemTagSearchInSpotlight:
131             // FIXME: Perhaps move this string into WebKit directly when we're not in localization freeze
132             title = localizedMenuTitleFromAppKit(@"Search in Spotlight", @"Search in Spotlight menu title.");
133             action = @selector(_searchWithSpotlightFromMenu:);
134             break;
135         case WebMenuItemTagSearchInGoogle:
136             // FIXME: Perhaps move this string into WebKit directly when we're not in localization freeze
137             title = localizedMenuTitleFromAppKit(@"Search in Google", @"Search in Google menu title.");
138             action = @selector(_searchWithGoogleFromMenu:);
139             break;
140 #endif
141         default:
142             return nil;
143     }
144
145     if (title != nil) {
146         [menuItem setTitle:title];
147     }
148     [menuItem setAction:action];
149     
150     return menuItem;
151 }
152
153 - (NSArray *)contextMenuItemsForElement:(NSDictionary *)element
154 {
155     NSMutableArray *menuItems = [NSMutableArray array];
156     
157     NSURL *linkURL = [element objectForKey:WebElementLinkURLKey];
158     
159     if (linkURL) {
160         if([WebView _canHandleRequest:[NSURLRequest requestWithURL:linkURL]]) {
161             [menuItems addObject:[self menuItemWithTag:WebMenuItemTagOpenLinkInNewWindow]];
162             [menuItems addObject:[self menuItemWithTag:WebMenuItemTagDownloadLinkToDisk]];
163         }
164         [menuItems addObject:[self menuItemWithTag:WebMenuItemTagCopyLinkToClipboard]];
165     }
166     
167     WebFrame *webFrame = [element objectForKey:WebElementFrameKey];
168     NSURL *imageURL = [element objectForKey:WebElementImageURLKey];
169     
170     if (imageURL) {
171         if (linkURL) {
172             [menuItems addObject:[NSMenuItem separatorItem]];
173         }
174         [menuItems addObject:[self menuItemWithTag:WebMenuItemTagOpenImageInNewWindow]];
175         [menuItems addObject:[self menuItemWithTag:WebMenuItemTagDownloadImageToDisk]];
176         if ([imageURL isFileURL] || [[webFrame dataSource] _fileWrapperForURL:imageURL]) {
177             [menuItems addObject:[self menuItemWithTag:WebMenuItemTagCopyImageToClipboard]];
178         }
179     }
180     
181     if (!imageURL && !linkURL) {
182         if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) {
183 #ifndef OMIT_TIGER_FEATURES
184             // Add Tiger-only items that act on selected text. Google search needn't be Tiger-only technically,
185             // but it's a new Tiger-only feature to have it in the context menu by default.
186             [menuItems addObject:[self menuItemWithTag:WebMenuItemTagSearchInSpotlight]];
187             [menuItems addObject:[self menuItemWithTag:WebMenuItemTagSearchInGoogle]];
188             [menuItems addObject:[NSMenuItem separatorItem]];
189 #endif
190             [menuItems addObject:[self menuItemWithTag:WebMenuItemTagCopy]];
191         } else {
192             WebView *wv = [webFrame webView];
193             if ([wv canGoBack]) {
194                 [menuItems addObject:[self menuItemWithTag:WebMenuItemTagGoBack]];
195             }
196             if ([wv canGoForward]) {
197                 [menuItems addObject:[self menuItemWithTag:WebMenuItemTagGoForward]];
198             }
199             if ([wv isLoading]) {
200                 [menuItems addObject:[self menuItemWithTag:WebMenuItemTagStop]];
201             } else {
202                 [menuItems addObject:[self menuItemWithTag:WebMenuItemTagReload]];
203             }
204             
205             if (webFrame != [wv mainFrame]) {
206                 [menuItems addObject:[self menuItemWithTag:WebMenuItemTagOpenFrameInNewWindow]];
207             }
208         }
209     }
210     
211     // Attach element as the represented object to each item.
212     [menuItems makeObjectsPerformSelector:@selector(setRepresentedObject:) withObject:element];
213     
214     return menuItems;
215 }
216
217 - (NSArray *)editingContextMenuItemsForElement:(NSDictionary *)element
218 {
219     NSMenuItem *item;
220     NSMutableArray *menuItems = [NSMutableArray array];
221     WebHTMLView *HTMLView = (WebHTMLView *)[[[element objectForKey:WebElementFrameKey] frameView] documentView];
222     ASSERT([HTMLView isKindOfClass:[WebHTMLView class]]);
223     
224     // Add spelling related context menu items.
225     if ([HTMLView _isSelectionMisspelled]) {
226         NSArray *guesses = [HTMLView _guessesForMisspelledSelection];
227         unsigned count = [guesses count];
228         if (count > 0) {
229             NSEnumerator *enumerator = [guesses objectEnumerator];
230             NSString *guess;
231             while ((guess = [enumerator nextObject]) != nil) {
232                 item = [self menuItemWithTag:WebMenuItemTagSpellingGuess];
233                 [item setTitle:guess];
234                 [menuItems addObject:item];
235             }
236         } else {
237             [menuItems addObject:[self menuItemWithTag:WebMenuItemTagNoGuessesFound]];
238         }
239         [menuItems addObject:[NSMenuItem separatorItem]];
240         [menuItems addObject:[self menuItemWithTag:WebMenuItemTagIgnoreSpelling]];
241         [menuItems addObject:[self menuItemWithTag:WebMenuItemTagLearnSpelling]];
242         [menuItems addObject:[NSMenuItem separatorItem]];
243     }
244     
245 #ifndef OMIT_TIGER_FEATURES
246     // Add Tiger-only items that aren't in our nib.
247     // FIXME: When we're not building for Panther anymore we should update the nib to include these.
248     [menuItems addObject:[self menuItemWithTag:WebMenuItemTagSearchInSpotlight]];
249     [menuItems addObject:[self menuItemWithTag:WebMenuItemTagSearchInGoogle]];
250     [menuItems addObject:[NSMenuItem separatorItem]];
251 #endif
252     
253     // Load our NSTextView-like context menu nib.
254     if (defaultMenu == nil) {
255         static NSNib *textViewMenuNib = nil;
256         if (textViewMenuNib == nil) {
257             textViewMenuNib = [[NSNib alloc] initWithNibNamed:@"WebViewEditingContextMenu" bundle:[NSBundle bundleForClass:[self class]]];
258         }
259         [textViewMenuNib instantiateNibWithOwner:self topLevelObjects:nil];
260     }
261     
262     // Add tags to the menu items because this is what the WebUIDelegate expects.
263     NSEnumerator *enumerator = [[defaultMenu itemArray] objectEnumerator];
264     while ((item = [enumerator nextObject]) != nil) {
265         item = [item copy];
266         SEL action = [item action];
267         int tag;
268         if (action == @selector(cut:)) {
269             tag = WebMenuItemTagCut;
270         } else if (action == @selector(copy:)) {
271             tag = WebMenuItemTagCopy;
272         } else if (action == @selector(paste:)) {
273             tag = WebMenuItemTagPaste;
274         } else {
275             tag = WebMenuItemTagOther;
276         }
277         [item setTag:tag];
278         [menuItems addObject:item];
279         [item release];
280     }
281     
282     return menuItems;
283 }
284
285 - (NSArray *)webView:(WebView *)wv contextMenuItemsForElement:(NSDictionary *)element  defaultMenuItems:(NSArray *)defaultMenuItems
286 {
287     WebHTMLView *HTMLView = (WebHTMLView *)[[[element objectForKey:WebElementFrameKey] frameView] documentView];
288     if ([HTMLView isKindOfClass:[WebHTMLView class]] && [HTMLView _isEditable]) {
289         return [self editingContextMenuItemsForElement:element];
290     } else {
291         return [self contextMenuItemsForElement:element];
292     }
293 }
294
295 - (void)openNewWindowWithURL:(NSURL *)URL element:(NSDictionary *)element
296 {
297     WebFrame *webFrame = [element objectForKey:WebElementFrameKey];
298     WebView *webView = [webFrame webView];
299     
300     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
301     NSString *referrer = [[webFrame _bridge] referrer];
302     if (referrer) {
303         [request setHTTPReferrer:referrer];
304     }
305     
306     [webView _openNewWindowWithRequest:request];
307 }
308
309 - (void)downloadURL:(NSURL *)URL element:(NSDictionary *)element
310 {
311     WebFrame *webFrame = [element objectForKey:WebElementFrameKey];
312     WebView *webView = [webFrame webView];
313     [webView _downloadURL:URL];
314 }
315
316 - (void)openLinkInNewWindow:(id)sender
317 {
318     NSDictionary *element = [sender representedObject];
319     [self openNewWindowWithURL:[element objectForKey:WebElementLinkURLKey] element:element];
320 }
321
322 - (void)downloadLinkToDisk:(id)sender
323 {
324     NSDictionary *element = [sender representedObject];
325     [self downloadURL:[element objectForKey:WebElementLinkURLKey] element:element];
326 }
327
328 - (void)copyLinkToClipboard:(id)sender
329 {
330     NSDictionary *element = [sender representedObject];
331     NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
332     NSArray *types = [NSPasteboard _web_writableTypesForURL];
333     [pasteboard declareTypes:types owner:self];    
334     [[[element objectForKey:WebElementFrameKey] webView] _writeLinkElement:element 
335                                                        withPasteboardTypes:types
336                                                               toPasteboard:pasteboard];
337 }
338
339 - (void)openImageInNewWindow:(id)sender
340 {
341     NSDictionary *element = [sender representedObject];
342     [self openNewWindowWithURL:[element objectForKey:WebElementImageURLKey] element:element];
343 }
344
345 - (void)downloadImageToDisk:(id)sender
346 {
347     NSDictionary *element = [sender representedObject];
348     [self downloadURL:[element objectForKey:WebElementImageURLKey] element:element];
349 }
350
351 - (void)copyImageToClipboard:(id)sender
352 {
353     NSDictionary *element = [sender representedObject];
354     NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
355     NSArray *types = [NSPasteboard _web_writableTypesForImage];
356     [pasteboard declareTypes:types owner:self];
357     [[[element objectForKey:WebElementFrameKey] webView] _writeImageElement:element 
358                                                         withPasteboardTypes:types 
359                                                                toPasteboard:pasteboard];
360 }
361
362 - (void)openFrameInNewWindow:(id)sender
363 {
364     NSDictionary *element = [sender representedObject];
365     WebDataSource *dataSource = [[element objectForKey:WebElementFrameKey] dataSource];
366     NSURL *URL = [dataSource unreachableURL];
367     if (URL == nil) {
368         URL = [[dataSource request] URL];
369     }    
370     [self openNewWindowWithURL:URL element:element];
371 }
372
373 @end