Reviewed by Maciej.
[WebKit-https.git] / WebKit / WebView.subproj / WebPDFView.m
1 /*      
2     WebPDFView.m
3     Copyright 2004, Apple, Inc. All rights reserved.
4 */
5
6 #ifndef OMIT_TIGER_FEATURES
7
8 #import <Foundation/NSString_NSURLExtras.h>
9
10 #import <WebKit/WebAssertions.h>
11 #import <WebKit/WebDataSource.h>
12 #import <WebKit/WebLocalizableStrings.h>
13 #import <WebKit/WebNSPasteboardExtras.h>
14 #import <WebKit/WebPDFView.h>
15
16 #import <Quartz/Quartz.h>
17
18 // QuartzPrivate.h doesn't include the PDFKit private headers, so we can't get at PDFViewPriv.h. (3957971)
19 // Even if that was fixed, we'd have to tweak compile options to include QuartzPrivate.h. (3957839)
20
21 @interface PDFDocument (PDFKitSecretsIKnow)
22 - (NSPrintOperation *)getPrintOperationForPrintInfo:(NSPrintInfo *)printInfo autoRotate:(BOOL)doRotate;
23 @end
24
25 NSString *_NSPathForSystemFramework(NSString *framework);
26
27 @implementation WebPDFView
28
29 + (NSBundle *)PDFKitBundle
30 {
31     static NSBundle *PDFKitBundle = nil;
32     if (PDFKitBundle == nil) {
33         NSString *PDFKitPath = [_NSPathForSystemFramework(@"Quartz.framework") stringByAppendingString:@"/Frameworks/PDFKit.framework"];
34         if (PDFKitPath == nil) {
35             ERROR("Couldn't find PDFKit.framework");
36             return nil;
37         }
38         PDFKitBundle = [NSBundle bundleWithPath:PDFKitPath];
39         if (![PDFKitBundle load]) {
40             ERROR("Couldn't load PDFKit.framework");
41         }
42     }
43     return PDFKitBundle;
44 }
45
46 + (Class)PDFViewClass
47 {
48     static Class PDFViewClass = nil;
49     if (PDFViewClass == nil) {
50         PDFViewClass = [[WebPDFView PDFKitBundle] classNamed:@"PDFView"];
51         if (PDFViewClass == nil) {
52             ERROR("Couldn't find PDFView class in PDFKit.framework");
53         }
54     }
55     return PDFViewClass;
56 }
57
58 - (id)initWithFrame:(NSRect)frame
59 {
60     self = [super initWithFrame:frame];
61     if (self) {
62         [self setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
63         PDFSubview = [[[[self class] PDFViewClass] alloc] initWithFrame:frame];
64         [PDFSubview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
65         [self addSubview:PDFSubview];
66         written = NO;
67     }
68     return self;
69 }
70
71 - (void)dealloc
72 {
73     [PDFSubview release];
74     [path release];
75     [super dealloc];
76 }
77
78 - (PDFView *)PDFSubview
79 {
80     return PDFSubview;
81 }
82
83 #define TEMP_PREFIX "/tmp/XXXXXX-"
84 #define OBJC_TEMP_PREFIX @"/tmp/XXXXXX-"
85
86 static void applicationInfoForMIMEType(NSString *type, NSString **name, NSImage **image)
87 {
88     NSURL *appURL = nil;
89     
90     OSStatus error = LSCopyApplicationForMIMEType((CFStringRef)type, kLSRolesAll, (CFURLRef *)&appURL);
91     if(error != noErr){
92         return;
93     }
94
95     NSString *appPath = [appURL path];
96     CFRelease (appURL);
97     
98     *image = [[NSWorkspace sharedWorkspace] iconForFile:appPath];  
99     [*image setSize:NSMakeSize(16.f,16.f)];  
100     
101     NSString *appName = [[NSFileManager defaultManager] displayNameAtPath:appPath];
102     *name = appName;
103 }
104
105
106 - (NSString *)path
107 {
108     // Generate path once.
109     if (path)
110         return path;
111         
112     NSString *filename = [[dataSource response] suggestedFilename];
113     NSFileManager *manager = [NSFileManager defaultManager];    
114     
115     path = [@"/tmp/" stringByAppendingPathComponent: filename];
116     if ([manager fileExistsAtPath:path]) {
117         path = [OBJC_TEMP_PREFIX stringByAppendingString:filename];
118         char *cpath = (char *)[path fileSystemRepresentation];
119         
120         int fd = mkstemps (cpath, strlen(cpath) - strlen(TEMP_PREFIX) + 1);
121         if (fd < 0) {
122             // Couldn't create a temporary file!  Should never happen.  Do
123             // we need an alert here?
124             path = nil;
125         }
126         else {
127             close (fd);
128             path = [manager stringWithFileSystemRepresentation:cpath length:strlen(cpath)];
129         }
130     }
131     
132     [path retain];
133     
134     return path;
135 }
136
137 - (NSView *)hitTest:(NSPoint)point
138 {
139     // Override hitTest so we can override menuForEvent.
140     NSEvent *event = [NSApp currentEvent];
141     NSEventType type = [event type];
142     if (type == NSRightMouseDown || (type == NSLeftMouseDown && ([event modifierFlags] & NSControlKeyMask))) {
143         return self;
144     }
145     return [super hitTest:point];
146 }
147
148 - (NSMenu *)menuForEvent:(NSEvent *)theEvent
149 {
150     NSMenu *menu = [PDFSubview menuForEvent:theEvent];
151     
152     NSString *appName = nil;
153     NSImage *appIcon = nil;
154     
155     applicationInfoForMIMEType([[dataSource response] MIMEType], &appName, &appIcon);
156     if (!appName)
157         appName = UI_STRING("Finder", "Default application name for Open With context menu");
158     
159     NSString *title = [NSString stringWithFormat:UI_STRING("Open with %@", "Open document using the Finder"), appName];
160     
161     NSMenuItem *item = [menu insertItemWithTitle:title action:@selector(openWithFinder:) keyEquivalent:@"" atIndex:0];
162     if (appIcon)
163         [item setImage:appIcon];
164         
165     [menu insertItem:[NSMenuItem separatorItem] atIndex:1];
166     
167     return menu;
168 }
169
170 - (void)setDataSource:(WebDataSource *)ds
171 {
172     dataSource = ds;
173     [self setFrame:[[self superview] frame]];
174 }
175
176 - (void)dataSourceUpdated:(WebDataSource *)dataSource
177 {
178 }
179
180 - (void)setNeedsLayout:(BOOL)flag
181 {
182 }
183
184 - (void)layout
185 {
186 }
187
188 - (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
189 {
190 }
191
192 - (void)viewDidMoveToHostWindow
193 {
194 }
195
196 - (void)openWithFinder:(id)sender
197 {
198     NSString *opath = [self path];
199     
200     if (opath) {
201         if (!written) {
202             [[dataSource data] writeToFile:opath atomically:YES];
203             written = YES;
204         }
205     
206         if (![[NSWorkspace sharedWorkspace] openFile:opath]) {
207             // NSWorkspace couldn't open file.  Do we need an alert
208             // here?  We ignore the error elsewhere.
209         }
210     }
211 }
212
213 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag;
214 {
215     int options = 0;
216     if (!forward) {
217         options |= NSBackwardsSearch;
218     }
219     if (!caseFlag) {
220         options |= NSCaseInsensitiveSearch;
221     }
222     PDFDocument *document = [PDFSubview document];
223     PDFSelection *selection = [document findString:string fromSelection:[PDFSubview currentSelection] withOptions:options];
224     if (selection == nil && wrapFlag) {
225         selection = [document findString:string fromSelection:nil withOptions:options];
226     }
227     if (selection != nil) {
228         [PDFSubview setCurrentSelection:selection];
229         [PDFSubview scrollSelectionToVisible:nil];
230         return YES;
231     }
232     return NO;
233 }
234
235 - (void)takeFindStringFromSelection:(id)sender
236 {
237     [NSPasteboard _web_setFindPasteboardString:[[PDFSubview currentSelection] string] withOwner:self];
238 }
239
240 - (void)jumpToSelection:(id)sender
241 {
242     [PDFSubview scrollSelectionToVisible:nil];
243 }
244
245 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item 
246 {
247     SEL action = [item action];    
248     if (action == @selector(takeFindStringFromSelection:) || action == @selector(jumpToSelection:)) {
249         return [PDFSubview currentSelection] != nil;
250     }
251     return YES;
252 }
253
254 - (BOOL)canPrintHeadersAndFooters
255 {
256     return NO;
257 }
258
259 - (NSPrintOperation *)printOperationWithPrintInfo:(NSPrintInfo *)printInfo
260 {
261     return [[PDFSubview document] getPrintOperationForPrintInfo:printInfo autoRotate:YES];
262 }
263
264 @end
265
266 #endif // OMIT_TIGER_FEATURES