1 /* 2 * Copyright (c) 2011, 2014, 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 "common.h" 27 #import "com_sun_glass_ui_mac_MacCommonDialogs.h" 28 29 #import "GlassMacros.h" 30 #import "GlassDialogs.h" 31 #import "GlassApplication.h" 32 #import "GlassHelper.h" 33 34 //#define VERBOSE 35 #ifndef VERBOSE 36 #define LOG(MSG, ...) 37 #else 38 #define LOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 39 #endif 40 41 static BOOL doPerformKeyEquivalent(NSEvent* theEvent, NSWindow* panel) 42 { 43 NSResponder* responder = [panel firstResponder]; 44 if ([responder isKindOfClass:[NSText class]]) 45 { 46 NSText* text = (NSText*)responder; 47 if ([theEvent type] == NSKeyDown 48 && ([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask) 49 { 50 NSRange range = [text selectedRange]; 51 BOOL hasSelectedText = range.length > 0; 52 if ([theEvent keyCode] == 7 && hasSelectedText) // Cmd + X - Cut 53 { 54 [text cut:panel]; 55 return true; 56 } 57 if ([theEvent keyCode] == 8 && hasSelectedText) // Cmd + C - Copy 58 { 59 [text copy:panel]; 60 return true; 61 } 62 if ([theEvent keyCode] == 9) // Cmd + V - Paste 63 { 64 [text paste:panel]; 65 return true; 66 } 67 } 68 } 69 return false; 70 } 71 72 @interface GlassSavePanel : NSSavePanel 73 @end 74 75 @implementation GlassSavePanel 76 77 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent 78 { 79 if (doPerformKeyEquivalent(theEvent, self)) { 80 return true; 81 } 82 return [super performKeyEquivalent:theEvent]; 83 } 84 @end 85 86 @interface GlassOpenPanel : NSOpenPanel 87 @end 88 89 @implementation GlassOpenPanel 90 91 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent 92 { 93 if (doPerformKeyEquivalent(theEvent, self)) { 94 return true; 95 } 96 return [super performKeyEquivalent:theEvent]; 97 } 98 @end 99 100 101 #pragma mark --- Dispatcher 102 103 @interface DialogDispatcher : NSObject 104 { 105 NSSavePanel *panel; 106 NSWindow *owner; 107 NSInteger button; 108 jobject eventLoop; 109 NSArray *m_filters; 110 } 111 112 - initWithPanel:(NSSavePanel*)panel owner:(NSWindow*)owner; 113 - (void)runModally; 114 - (NSInteger)getButton; 115 116 - (void)applyExtensions:(jobjectArray)jExtensionFilters withDefaultIndex:(jint)index withEnv:(JNIEnv*)env; 117 - (void)extensionFilterChanged:(NSPopUpButton*)sender; 118 @end 119 120 @implementation DialogDispatcher 121 122 - (id)initWithPanel:(NSSavePanel*)p owner:(NSWindow*)o 123 { 124 self = [super init]; 125 126 self->panel = p; 127 self->owner = o; 128 129 return self; 130 } 131 132 - (void)exitModalWithEnv:(JNIEnv*)env result:(NSInteger)result 133 { 134 self->button = result; 135 (*env)->CallVoidMethod(env, self->eventLoop, javaIDs.EventLoop.leave, NULL); 136 GLASS_CHECK_EXCEPTION(env); 137 } 138 139 - (void)runModally 140 { 141 GET_MAIN_JENV; 142 DialogDispatcher *dd = self; 143 144 jclass eventLoopCls = [GlassHelper ClassForName:"com.sun.glass.ui.EventLoop" withEnv:env]; 145 if (!eventLoopCls) { 146 return; 147 } 148 jobject jobj = (*env)->NewObject(env, 149 eventLoopCls, 150 javaIDs.EventLoop.init); 151 if ((*env)->ExceptionCheck(env)) return; 152 153 dd->eventLoop = (*env)->NewGlobalRef(env, jobj); 154 155 if (owner) { 156 [panel beginSheetModalForWindow: owner completionHandler:^(NSInteger result) 157 { 158 [dd exitModalWithEnv:env result:result]; 159 } 160 ]; 161 } else { 162 [panel beginWithCompletionHandler:^(NSInteger result) 163 { 164 [dd exitModalWithEnv:env result:result]; 165 } 166 ]; 167 } 168 169 (*env)->CallObjectMethod(env, dd->eventLoop, javaIDs.EventLoop.enter); 170 GLASS_CHECK_EXCEPTION(env); 171 172 (*env)->DeleteGlobalRef(env, dd->eventLoop); 173 } 174 175 - (NSInteger)getButton 176 { 177 return self->button; 178 } 179 180 - (void)applyExtensions:(jobjectArray)jExtensionFilters withDefaultIndex:(jint)index withEnv:(JNIEnv*)env 181 { 182 if (jExtensionFilters != NULL) 183 { 184 NSUInteger itemCount = (*env)->GetArrayLength(env, jExtensionFilters); 185 if (itemCount > 0) 186 { 187 NSMutableArray *filters = [NSMutableArray arrayWithCapacity:itemCount]; 188 NSMutableArray *filterNames = [NSMutableArray arrayWithCapacity:itemCount]; 189 for (int i = 0; i < itemCount; i++) 190 { 191 jobject jFilter = (*env)->GetObjectArrayElement(env, jExtensionFilters, i); 192 193 jstring jDescription = (*env)->CallObjectMethod(env, jFilter, javaIDs.ExtensionFilter.getDescription); 194 [filterNames addObject:[GlassHelper nsStringWithJavaString:jDescription withEnv:env]]; 195 196 jobjectArray jExtensions = (jobjectArray)(*env)->CallObjectMethod(env, jFilter, javaIDs.ExtensionFilter.extensionsToArray); 197 NSUInteger extensionCount = (NSUInteger)(*env)->GetArrayLength(env, jExtensions); 198 NSMutableArray* extensions = [NSMutableArray arrayWithCapacity:extensionCount]; 199 for (int j = 0; j < extensionCount; j++) 200 { 201 NSString* extension = [GlassHelper nsStringWithJavaString:(*env)->GetObjectArrayElement(env, jExtensions, j) 202 withEnv:env]; 203 [extensions addObject:[extension pathExtension]]; 204 } 205 [filters addObject:extensions]; 206 } 207 208 GLASS_CHECK_EXCEPTION(env); 209 210 self->m_filters = filters; 211 212 NSPopUpButton* filterView = [[[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO] autorelease]; 213 [self->panel setAccessoryView:filterView]; 214 [filterView setTarget:self]; 215 [filterView setAction:@selector(extensionFilterChanged:)]; 216 [filterView addItemsWithTitles:filterNames]; 217 [filterView selectItemAtIndex:index]; 218 [self extensionFilterChanged:filterView]; 219 [filterView sizeToFit]; 220 } 221 } 222 223 } 224 225 -(void)extensionFilterChanged:(NSPopUpButton*)sender 226 { 227 NSInteger index = [sender indexOfSelectedItem]; 228 if (index >= 0) 229 { 230 NSArray* extensions = [self->m_filters objectAtIndex:index]; 231 if ([extensions count] == 0 || [extensions containsObject:@"*"]) 232 { 233 [self->panel setAllowedFileTypes:nil]; 234 //Clean up the added extensions when resetting to any file type. 235 NSString* fileName = [[self->panel nameFieldStringValue] stringByDeletingPathExtension]; 236 [self->panel setNameFieldStringValue:fileName]; 237 } 238 else 239 { 240 [self->panel setAllowedFileTypes:extensions]; 241 } 242 [self->panel validateVisibleColumns]; 243 } 244 } 245 246 @end 247 248 static jobject convertNSURLtoFile(JNIEnv *env, NSURL *url) 249 { 250 LOG(" url: %s", [[url path] UTF8String]); 251 jstring path = (*env)->NewStringUTF(env, [[url path] UTF8String]); 252 253 jobject ret = NULL; 254 255 // Make sure the class is initialized before using the methodIDs 256 const jclass MacCommonDialogsCls = [GlassHelper ClassForName:"com.sun.glass.ui.mac.MacCommonDialogs" withEnv:env]; 257 if (!MacCommonDialogsCls) return NULL; 258 259 // Performance doesn't matter here, so call the method every time 260 jboolean result = (*env)->CallStaticBooleanMethod(env, MacCommonDialogsCls, 261 javaIDs.MacCommonDialogs.isFileNSURLEnabled); 262 GLASS_CHECK_EXCEPTION(env); 263 if (result) 264 { 265 [url retain]; //NOTE: an app must call MacFileURL.dispoes() to release it 266 267 const jclass MacFileNSURLCls = [GlassHelper ClassForName:"com.sun.glass.ui.mac.MacFileNSURL" withEnv:env]; 268 if (!MacFileNSURLCls) return NULL; 269 ret = (*env)->NewObject(env, 270 MacFileNSURLCls, 271 javaIDs.MacFileNSURL.init, path, ptr_to_jlong(url)); 272 GLASS_CHECK_EXCEPTION(env); 273 (*env)->DeleteLocalRef(env, MacFileNSURLCls); 274 } 275 else 276 { 277 jclass jcls = (*env)->FindClass(env, "java/io/File"); 278 GLASS_CHECK_EXCEPTION(env); 279 ret = (*env)->NewObject(env, 280 jcls, 281 javaIDs.File.init, path); 282 GLASS_CHECK_EXCEPTION(env); 283 } 284 285 (*env)->DeleteLocalRef(env, MacCommonDialogsCls); 286 return ret; 287 } 288 289 #pragma mark --- JNI 290 291 /* *********** MacFileNSURL *********** */ 292 293 /* 294 * Class: com_sun_glass_ui_mac_MacFileNSURL 295 * Method: _initIDs 296 * Signature: ()V 297 */ 298 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacFileNSURL__1initIDs 299 (JNIEnv *env, jclass cls) 300 { 301 javaIDs.MacFileNSURL.init = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;J)V"); 302 } 303 304 /* 305 * Class: com_sun_glass_ui_mac_MacFileNSURL 306 * Method: _dispose 307 * Signature: (J)V 308 */ 309 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacFileNSURL__1dispose 310 (JNIEnv *env, jobject jMacFileNSURL, jlong ptr) 311 { 312 NSURL * url = (NSURL*)jlong_to_ptr(ptr); 313 [url release]; 314 } 315 316 /* 317 * Class: com_sun_glass_ui_mac_MacFileNSURL 318 * Method: _startAccessingSecurityScopedResource 319 * Signature: (J)Z 320 */ 321 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_mac_MacFileNSURL__1startAccessingSecurityScopedResource 322 (JNIEnv *env, jobject jMacFileNSURL, jlong ptr) 323 { 324 NSURL * url = (NSURL*)jlong_to_ptr(ptr); 325 return [url startAccessingSecurityScopedResource] ? JNI_TRUE : JNI_FALSE; 326 } 327 328 /* 329 * Class: com_sun_glass_ui_mac_MacFileNSURL 330 * Method: _stopAccessingSecurityScopedResource 331 * Signature: (J)V 332 */ 333 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacFileNSURL__1stopAccessingSecurityScopedResource 334 (JNIEnv *env, jobject jMacFileNSURL, jlong ptr) 335 { 336 NSURL * url = (NSURL*)jlong_to_ptr(ptr); 337 [url stopAccessingSecurityScopedResource]; 338 } 339 340 /* 341 * Class: com_sun_glass_ui_mac_MacFileNSURL 342 * Method: _getBookmark 343 * Signature: (JJ)[B 344 */ 345 JNIEXPORT jbyteArray JNICALL Java_com_sun_glass_ui_mac_MacFileNSURL__1getBookmark 346 (JNIEnv *env, jobject jMacFileNSURL, jlong ptr, jlong baseDocumentPtr) 347 { 348 NSURL * url = (NSURL*)jlong_to_ptr(ptr); 349 NSURL * baseUrl = (NSURL*)jlong_to_ptr(baseDocumentPtr); // May be 0L 350 jbyteArray data = NULL; 351 352 GLASS_POOL_ENTER; 353 { 354 NSError *error = nil; 355 356 NSData *nsData = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope 357 includingResourceValuesForKeys:nil relativeToURL:baseUrl error:&error]; 358 359 if (error) { 360 NSLog(@"ERROR in Glass calling bookmarkDataWithOptions: %@", error); 361 } else { 362 const jsize len = (jsize)[nsData length]; 363 364 data = (*env)->NewByteArray(env, len); 365 if (data && len) { 366 void *pData = (*env)->GetPrimitiveArrayCritical(env, data, 0); 367 if (pData) { 368 memcpy(pData, [nsData bytes], len); 369 (*env)->ReleasePrimitiveArrayCritical(env, data, pData, 0); 370 } 371 } 372 } 373 } 374 GLASS_POOL_EXIT; 375 GLASS_CHECK_EXCEPTION(env); 376 377 return data; 378 } 379 380 /* 381 * Class: com_sun_glass_ui_mac_MacFileNSURL 382 * Method: _createFromBookmark 383 * Signature: ([BJ)Lcom/sun/glass/ui/mac/MacFileNSURL; 384 */ 385 JNIEXPORT jobject JNICALL Java_com_sun_glass_ui_mac_MacFileNSURL__1createFromBookmark 386 (JNIEnv *env, jclass cls, jbyteArray data, jlong baseDocumentPtr) 387 { 388 jobject jMacFileNSURL = NULL; 389 NSURL * baseUrl = (NSURL*)jlong_to_ptr(baseDocumentPtr); // May be 0L 390 391 GLASS_POOL_ENTER; 392 { 393 const jsize len = (*env)->GetArrayLength(env, data); 394 395 NSData *nsData = NULL; 396 397 void *pData = (*env)->GetPrimitiveArrayCritical(env, data, 0); 398 if (pData) { 399 nsData = [NSData dataWithBytes:pData length:len]; 400 (*env)->ReleasePrimitiveArrayCritical(env, data, pData, 0); 401 } 402 403 if (nsData) { 404 BOOL isStale = NO; 405 NSError *error = nil; 406 407 NSURL *url = [NSURL URLByResolvingBookmarkData:nsData 408 options:(NSURLBookmarkResolutionWithoutUI | NSURLBookmarkResolutionWithSecurityScope) 409 relativeToURL:baseUrl bookmarkDataIsStale:&isStale error:&error]; 410 411 if (isStale) { 412 NSLog(@"URLByResolvingBookmarkData isStale=%d", isStale); 413 } 414 415 if (error) { 416 NSLog(@"ERROR in Glass calling URLByResolvingBookmarkData: %@", error); 417 } else { 418 jMacFileNSURL = convertNSURLtoFile(env, url); 419 } 420 } 421 } 422 GLASS_POOL_EXIT; 423 GLASS_CHECK_EXCEPTION(env); 424 425 return jMacFileNSURL; 426 } 427 428 429 /* *********** MacCommonDialogs *********** */ 430 431 /* 432 * Class: com_sun_glass_ui_mac_MacCommonDialogs 433 * Method: _initIDs 434 * Signature: ()V 435 */ 436 JNIEXPORT void JNICALL Java_com_sun_glass_ui_mac_MacCommonDialogs__1initIDs 437 (JNIEnv *env, jclass cls) 438 { 439 javaIDs.MacCommonDialogs.isFileNSURLEnabled = (*env)->GetStaticMethodID(env, cls, "isFileNSURLEnabled", "()Z"); 440 if ((*env)->ExceptionCheck(env)) return; 441 442 cls = [GlassHelper ClassForName:"com.sun.glass.ui.EventLoop" withEnv:env]; 443 if (!cls) { 444 return; 445 } 446 javaIDs.EventLoop.init = (*env)->GetMethodID(env, cls, "<init>", "()V"); 447 if ((*env)->ExceptionCheck(env)) return; 448 javaIDs.EventLoop.enter = (*env)->GetMethodID(env, cls, "enter", "()Ljava/lang/Object;"); 449 if ((*env)->ExceptionCheck(env)) return; 450 javaIDs.EventLoop.leave = (*env)->GetMethodID(env, cls, "leave", "(Ljava/lang/Object;)V"); 451 if ((*env)->ExceptionCheck(env)) return; 452 453 initJavaIDsList(env); 454 initJavaIDsArrayList(env); 455 initJavaIDsFile(env); 456 457 cls = [GlassHelper ClassForName:"com.sun.glass.ui.CommonDialogs$ExtensionFilter" withEnv:env]; 458 if (!cls) { 459 return; 460 } 461 javaIDs.ExtensionFilter.getDescription = (*env)->GetMethodID(env, cls, "getDescription", "()Ljava/lang/String;"); 462 if ((*env)->ExceptionCheck(env)) return; 463 javaIDs.ExtensionFilter.extensionsToArray = (*env)->GetMethodID(env, cls, "extensionsToArray", "()[Ljava/lang/String;"); 464 if ((*env)->ExceptionCheck(env)) return; 465 466 cls = [GlassHelper ClassForName:"com.sun.glass.ui.CommonDialogs$FileChooserResult" withEnv:env]; 467 if (!cls) { 468 return; 469 } 470 javaIDs.FileChooserResult.init = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/util/List;Lcom/sun/glass/ui/CommonDialogs$ExtensionFilter;)V"); 471 } 472 473 /* 474 * Class: com_sun_glass_ui_mac_MacCommonDialogs 475 * Method: _showFileOpenChooser 476 * Signature: (JLjava/lang/String;Ljava/lang/String;Z[Lcom/sun/glass/ui/CommonDialogs$ExtensionFilter;I)Lcom.sun.glass.ui.CommonDialogs$FileChooserResult; 477 */ 478 JNIEXPORT jobject JNICALL Java_com_sun_glass_ui_mac_MacCommonDialogs__1showFileOpenChooser 479 (JNIEnv *env, jclass cls, jlong owner, jstring jFolder, jstring jTitle, jboolean jMultipleMode, jobjectArray jExtensionFilters, jint defaultIndex) 480 { 481 LOG("Java_com_sun_glass_ui_mac_MacCommonDialogs__1showFileOpenChooser"); 482 483 jobject result = NULL; 484 485 GLASS_ASSERT_MAIN_JAVA_THREAD(env); 486 GLASS_POOL_ENTER; 487 { 488 NSOpenPanel *panel = [GlassApplication isSandboxed] ? [NSOpenPanel openPanel] : [GlassOpenPanel openPanel]; 489 [panel setAllowsMultipleSelection:(jMultipleMode==JNI_TRUE)]; 490 [panel setTitle:[GlassHelper nsStringWithJavaString:jTitle withEnv:env]]; 491 NSString *folder = [GlassHelper nsStringWithJavaString:jFolder withEnv:env]; 492 if ([folder length] > 0) 493 { 494 [panel setDirectoryURL:[NSURL fileURLWithPath:folder isDirectory:YES]]; 495 } 496 497 [panel setResolvesAliases:YES]; 498 [panel setCanChooseFiles:YES]; 499 [panel setCanChooseDirectories:NO]; 500 [panel setShowsHiddenFiles:YES]; 501 [panel setExtensionHidden:NO]; 502 [panel setCanSelectHiddenExtension:YES]; 503 [panel setAllowsOtherFileTypes:NO]; 504 [panel setCanCreateDirectories:NO]; 505 506 jobject chosenFiles = NULL; 507 jobject chosenFilter = NULL; 508 509 DialogDispatcher *dispatcher = [[DialogDispatcher alloc] initWithPanel:panel owner:(NSWindow*)jlong_to_ptr(owner)]; 510 [dispatcher applyExtensions:jExtensionFilters withDefaultIndex:defaultIndex withEnv:env]; 511 { 512 [dispatcher performSelectorOnMainThread:@selector(runModally) withObject:nil waitUntilDone:YES]; 513 NSArray *urls = [panel URLs]; 514 515 jclass jcls = (*env)->FindClass(env, "java/util/ArrayList"); 516 GLASS_CHECK_EXCEPTION(env); 517 chosenFiles = (*env)->NewObject(env, jcls, javaIDs.ArrayList.init); 518 GLASS_CHECK_EXCEPTION(env); 519 520 if (([dispatcher getButton] == NSFileHandlingPanelOKButton) && ([urls count] > 0)) 521 { 522 for (NSUInteger i=0; i<[urls count]; i++) 523 { 524 NSURL *url = [urls objectAtIndex:i]; 525 (*env)->CallBooleanMethod(env, chosenFiles, javaIDs.List.add, convertNSURLtoFile(env, url)); 526 GLASS_CHECK_EXCEPTION(env); 527 } 528 } 529 530 if (jExtensionFilters != NULL && (*env)->GetArrayLength(env, jExtensionFilters) > 0) 531 { 532 chosenFilter = (*env)->GetObjectArrayElement(env, jExtensionFilters, 533 [(NSPopUpButton*)[panel accessoryView] indexOfSelectedItem]); 534 GLASS_CHECK_EXCEPTION(env); 535 } 536 } 537 [dispatcher release]; 538 539 cls = [GlassHelper ClassForName:"com.sun.glass.ui.CommonDialogs$FileChooserResult" withEnv:env]; 540 if (!cls) return NULL; 541 result = (*env)->NewObject(env, cls, javaIDs.FileChooserResult.init, chosenFiles, chosenFilter); 542 } 543 GLASS_POOL_EXIT; 544 GLASS_CHECK_EXCEPTION(env); 545 546 return result; 547 } 548 549 /* 550 * Class: com_sun_glass_ui_mac_MacCommonDialogs 551 * Method: _showFileSaveChooser 552 * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Lcom/sun/glass/ui/CommonDialogs$ExtensionFilter;I)Lcom.sun.glass.ui.CommonDialogs$FileChooserResult; 553 */ 554 JNIEXPORT jobject JNICALL Java_com_sun_glass_ui_mac_MacCommonDialogs__1showFileSaveChooser 555 (JNIEnv *env, jclass cls, jlong owner, jstring jFolder, jstring jFilename, jstring jTitle, jobjectArray jExtensionFilters, jint defaultIndex) 556 { 557 LOG("Java_com_sun_glass_ui_mac_MacCommonDialogs__1showFileSaveChooser"); 558 559 jobject result = NULL; 560 561 GLASS_ASSERT_MAIN_JAVA_THREAD(env); 562 GLASS_POOL_ENTER; 563 { 564 NSSavePanel *panel = [GlassApplication isSandboxed] ? [NSSavePanel savePanel] : [GlassSavePanel savePanel]; 565 [panel setTitle:[GlassHelper nsStringWithJavaString:jTitle withEnv:env]]; 566 NSString *folder = [GlassHelper nsStringWithJavaString:jFolder withEnv:env]; 567 if ([folder length] > 0) 568 { 569 [panel setDirectoryURL:[NSURL fileURLWithPath:folder isDirectory:YES]]; 570 } 571 572 NSString *filename = [GlassHelper nsStringWithJavaString:jFilename withEnv:env]; 573 if ([filename length] > 0) { 574 [panel setNameFieldStringValue:filename]; 575 } 576 577 [panel setShowsHiddenFiles:YES]; 578 [panel setExtensionHidden:NO]; 579 [panel setCanSelectHiddenExtension:YES]; 580 [panel setAllowsOtherFileTypes:NO]; 581 [panel setCanCreateDirectories:YES]; 582 583 jobject chosenFile = NULL; 584 jobject chosenFilter = NULL; 585 586 DialogDispatcher *dispatcher = [[DialogDispatcher alloc] initWithPanel:panel owner:(NSWindow*)jlong_to_ptr(owner)]; 587 [dispatcher applyExtensions:jExtensionFilters withDefaultIndex:defaultIndex withEnv:env]; 588 { 589 [dispatcher performSelectorOnMainThread:@selector(runModally) withObject:nil waitUntilDone:YES]; 590 NSURL *url = [panel URL]; 591 592 jclass jcls = (*env)->FindClass(env, "java/util/ArrayList"); 593 GLASS_CHECK_EXCEPTION(env); 594 chosenFile = (*env)->NewObject(env, jcls, javaIDs.ArrayList.init); 595 GLASS_CHECK_EXCEPTION(env); 596 if (([dispatcher getButton] == NSFileHandlingPanelOKButton) && (url != nil)) 597 { 598 (*env)->CallBooleanMethod(env, chosenFile, javaIDs.List.add, convertNSURLtoFile(env, url)); 599 GLASS_CHECK_EXCEPTION(env); 600 } 601 602 if (jExtensionFilters != NULL && (*env)->GetArrayLength(env, jExtensionFilters) > 0) 603 { 604 chosenFilter = (*env)->GetObjectArrayElement(env, jExtensionFilters, 605 [(NSPopUpButton*)[panel accessoryView] indexOfSelectedItem]); 606 GLASS_CHECK_EXCEPTION(env); 607 } 608 } 609 [dispatcher release]; 610 611 cls = [GlassHelper ClassForName:"com.sun.glass.ui.CommonDialogs$FileChooserResult" withEnv:env]; 612 if (!cls) return NULL; 613 result = (*env)->NewObject(env, cls, javaIDs.FileChooserResult.init, chosenFile, chosenFilter); 614 } 615 GLASS_POOL_EXIT; 616 GLASS_CHECK_EXCEPTION(env); 617 618 return result; 619 } 620 621 /* 622 * Class: com_sun_glass_ui_mac_MacCommonDialogs 623 * Method: _showFolderChooser 624 * Signature: (JLjava/lang/String;Ljava/lang/String;)Ljava/io/File; 625 */ 626 JNIEXPORT jobject JNICALL Java_com_sun_glass_ui_mac_MacCommonDialogs__1showFolderChooser 627 (JNIEnv *env, jclass cls, jlong owner, jstring jFolder, jstring jTitle) 628 { 629 LOG("Java_com_sun_glass_ui_mac_MacCommonDialogs__1showFolderChooser"); 630 631 jobject chosen = NULL; 632 633 GLASS_ASSERT_MAIN_JAVA_THREAD(env); 634 GLASS_POOL_ENTER; 635 { 636 NSOpenPanel *panel = [GlassApplication isSandboxed] ? [NSOpenPanel openPanel] : [GlassOpenPanel openPanel]; 637 [panel setTitle:[GlassHelper nsStringWithJavaString:jTitle withEnv:env]]; 638 NSString *folder = [GlassHelper nsStringWithJavaString:jFolder withEnv:env]; 639 if ([folder length] > 0) 640 { 641 [panel setDirectoryURL:[NSURL fileURLWithPath:folder isDirectory:YES]]; 642 } 643 644 [panel setAllowsMultipleSelection:NO]; 645 [panel setResolvesAliases:YES]; 646 [panel setCanChooseFiles:NO]; 647 [panel setCanChooseDirectories:YES]; 648 [panel setShowsHiddenFiles:NO]; 649 [panel setExtensionHidden:YES]; 650 [panel setCanSelectHiddenExtension:NO]; 651 [panel setAllowsOtherFileTypes:NO]; 652 [panel setCanCreateDirectories:YES]; 653 654 DialogDispatcher *dispatcher = [[DialogDispatcher alloc] initWithPanel:panel owner:(NSWindow*)jlong_to_ptr(owner)]; 655 { 656 [dispatcher performSelectorOnMainThread:@selector(runModally) withObject:panel waitUntilDone:YES]; 657 NSArray *urls = [panel URLs]; 658 if (([dispatcher getButton] == NSFileHandlingPanelOKButton) && ([urls count] >= 1)) 659 { 660 chosen = convertNSURLtoFile(env, [urls objectAtIndex:0]); 661 } 662 } 663 [dispatcher release]; 664 } 665 GLASS_POOL_EXIT; 666 GLASS_CHECK_EXCEPTION(env); 667 668 return chosen; 669 }