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