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 }