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 }