1 /* 2 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #import <sys/stat.h> 27 #import <Cocoa/Cocoa.h> 28 #import <JavaNativeFoundation/JavaNativeFoundation.h> 29 30 #import "CFileDialog.h" 31 #import "ThreadUtilities.h" 32 33 #import "java_awt_FileDialog.h" 34 #import "sun_lwawt_macosx_CFileDialog.h" 35 36 @implementation CFileDialog 37 38 - (id)initWithFilter:(jboolean)inHasFilter 39 fileDialog:(jobject)inDialog 40 title:(NSString *)inTitle 41 directory:(NSString *)inPath 42 file:(NSString *)inFile 43 mode:(jint)inMode 44 multipleMode:(BOOL)inMultipleMode 45 shouldNavigate:(BOOL)inNavigateApps 46 withEnv:(JNIEnv*)env; 47 { 48 if (self == [super init]) { 49 fHasFileFilter = inHasFilter; 50 fFileDialog = JNFNewGlobalRef(env, inDialog); 51 fDirectory = inPath; 52 [fDirectory retain]; 53 fFile = inFile; 54 [fFile retain]; 55 fTitle = inTitle; 56 [fTitle retain]; 57 fMode = inMode; 58 fMultipleMode = inMultipleMode; 59 fNavigateApps = inNavigateApps; 60 fPanelResult = NSCancelButton; 61 } 62 63 return self; 64 } 65 66 -(void) disposer { 67 if (fFileDialog != NULL) { 68 JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; 69 JNFDeleteGlobalRef(env, fFileDialog); 70 fFileDialog = NULL; 71 } 72 } 73 74 -(void) dealloc { 75 [fDirectory release]; 76 fDirectory = nil; 77 78 [fFile release]; 79 fFile = nil; 80 81 [fTitle release]; 82 fTitle = nil; 83 84 [fURLs release]; 85 fURLs = nil; 86 87 [super dealloc]; 88 } 89 //- (void)finalize { [super finalize]; } 90 91 - (void)safeSaveOrLoad { 92 NSSavePanel *thePanel = nil; 93 94 if (fMode == java_awt_FileDialog_SAVE) { 95 thePanel = [NSSavePanel savePanel]; 96 [thePanel setAllowsOtherFileTypes:YES]; 97 } else { 98 thePanel = [NSOpenPanel openPanel]; 99 } 100 101 if (thePanel != nil) { 102 [thePanel setTitle:fTitle]; 103 104 if (fNavigateApps) { 105 [thePanel setTreatsFilePackagesAsDirectories:YES]; 106 } 107 108 if (fMode == java_awt_FileDialog_LOAD) { 109 NSOpenPanel *openPanel = (NSOpenPanel *)thePanel; 110 [openPanel setAllowsMultipleSelection:fMultipleMode]; 111 [openPanel setCanChooseFiles:YES]; 112 [openPanel setCanChooseDirectories:NO]; 113 [openPanel setCanCreateDirectories:YES]; 114 } 115 116 [thePanel setDelegate:self]; 117 fPanelResult = [thePanel runModalForDirectory:fDirectory file:fFile]; 118 [thePanel setDelegate:nil]; 119 120 if ([self userClickedOK]) { 121 if (fMode == java_awt_FileDialog_LOAD) { 122 NSOpenPanel *openPanel = (NSOpenPanel *)thePanel; 123 fURLs = [openPanel URLs]; 124 } else { 125 fURLs = [NSArray arrayWithObject:[thePanel URL]]; 126 } 127 [fURLs retain]; 128 } 129 } 130 131 [self disposer]; 132 } 133 134 - (BOOL) askFilenameFilter:(NSString *)filename { 135 JNIEnv *env = [ThreadUtilities getJNIEnv]; 136 jstring jString = JNFNormalizedJavaStringForPath(env, filename); 137 138 static JNF_CLASS_CACHE(jc_CFileDialog, "sun/lwawt/macosx/CFileDialog"); 139 static JNF_MEMBER_CACHE(jm_queryFF, jc_CFileDialog, "queryFilenameFilter", "(Ljava/lang/String;)Z"); 140 BOOL returnValue = JNFCallBooleanMethod(env, fFileDialog, jm_queryFF, jString); // AWT_THREADING Safe (AWTRunLoopMode) 141 (*env)->DeleteLocalRef(env, jString); 142 143 return returnValue; 144 } 145 146 - (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url { 147 if (!fHasFileFilter) return YES; // no filter, no problem! 148 149 // check if it's not a normal file 150 NSNumber *isFile = nil; 151 if ([url getResourceValue:&isFile forKey:NSURLIsRegularFileKey error:nil]) { 152 if (![isFile boolValue]) return YES; // always show directories and non-file entities (browsing servers/mounts, etc) 153 } 154 155 // if in directory-browsing mode, don't offer files 156 if ((fMode != java_awt_FileDialog_LOAD) && (fMode != java_awt_FileDialog_SAVE)) { 157 return NO; 158 } 159 160 // ask the file filter up in Java 161 CFStringRef filePath = CFURLCopyFileSystemPath((CFURLRef)url, kCFURLPOSIXPathStyle); 162 BOOL shouldEnableFile = [self askFilenameFilter:(NSString *)filePath]; 163 CFRelease(filePath); 164 return shouldEnableFile; 165 } 166 167 - (BOOL) userClickedOK { 168 return fPanelResult == NSOKButton; 169 } 170 171 - (NSArray *)URLs { 172 return [[fURLs retain] autorelease]; 173 } 174 @end 175 176 /* 177 * Class: sun_lwawt_macosx_CFileDialog 178 * Method: nativeRunFileDialog 179 * Signature: (Ljava/lang/String;ILjava/io/FilenameFilter; 180 * Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String; 181 */ 182 JNIEXPORT jobjectArray JNICALL 183 Java_sun_lwawt_macosx_CFileDialog_nativeRunFileDialog 184 (JNIEnv *env, jobject peer, jstring title, jint mode, jboolean multipleMode, 185 jboolean navigateApps, jboolean hasFilter, jstring directory, jstring file) 186 { 187 jobjectArray returnValue = NULL; 188 189 JNF_COCOA_ENTER(env); 190 NSString *dialogTitle = JNFJavaToNSString(env, title); 191 if ([dialogTitle length] == 0) { 192 dialogTitle = @" "; 193 } 194 195 CFileDialog *dialogDelegate = [[CFileDialog alloc] initWithFilter:hasFilter 196 fileDialog:peer 197 title:dialogTitle 198 directory:JNFJavaToNSString(env, directory) 199 file:JNFJavaToNSString(env, file) 200 mode:mode 201 multipleMode:multipleMode 202 shouldNavigate:navigateApps 203 withEnv:env]; 204 205 [JNFRunLoop performOnMainThread:@selector(safeSaveOrLoad) 206 on:dialogDelegate 207 withObject:nil 208 waitUntilDone:YES]; 209 210 if ([dialogDelegate userClickedOK]) { 211 NSArray *urls = [dialogDelegate URLs]; 212 jsize count = [urls count]; 213 214 jclass stringClass = (*env)->FindClass(env, "java/lang/String"); 215 returnValue = (*env)->NewObjectArray(env, count, stringClass, NULL); 216 (*env)->DeleteLocalRef(env, stringClass); 217 218 [urls enumerateObjectsUsingBlock:^(id url, NSUInteger index, BOOL *stop) { 219 jstring filename = JNFNormalizedJavaStringForPath(env, [url path]); 220 (*env)->SetObjectArrayElement(env, returnValue, index, filename); 221 (*env)->DeleteLocalRef(env, filename); 222 }]; 223 } 224 225 [dialogDelegate release]; 226 JNF_COCOA_EXIT(env); 227 return returnValue; 228 }