widget/cocoa/nsFilePicker.mm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #import <Cocoa/Cocoa.h>
     8 #include "nsFilePicker.h"
     9 #include "nsCOMPtr.h"
    10 #include "nsReadableUtils.h"
    11 #include "nsNetUtil.h"
    12 #include "nsIComponentManager.h"
    13 #include "nsIFile.h"
    14 #include "nsILocalFileMac.h"
    15 #include "nsIURL.h"
    16 #include "nsArrayEnumerator.h"
    17 #include "nsIStringBundle.h"
    18 #include "nsCocoaFeatures.h"
    19 #include "nsCocoaUtils.h"
    20 #include "mozilla/Preferences.h"
    22 // This must be included last:
    23 #include "nsObjCExceptions.h"
    25 using namespace mozilla;
    27 const float kAccessoryViewPadding = 5;
    28 const int   kSaveTypeControlTag = 1;
    30 static bool gCallSecretHiddenFileAPI = false;
    31 const char kShowHiddenFilesPref[] = "filepicker.showHiddenFiles";
    33 /**
    34  * This class is an observer of NSPopUpButton selection change.
    35  */
    36 @interface NSPopUpButtonObserver : NSObject
    37 {
    38   NSPopUpButton* mPopUpButton;
    39   NSOpenPanel*   mOpenPanel;
    40   nsFilePicker*  mFilePicker;
    41 }
    42 - (void) setPopUpButton:(NSPopUpButton*)aPopUpButton;
    43 - (void) setOpenPanel:(NSOpenPanel*)aOpenPanel;
    44 - (void) setFilePicker:(nsFilePicker*)aFilePicker;
    45 - (void) menuChangedItem:(NSNotification*)aSender;
    46 @end
    48 NS_IMPL_ISUPPORTS(nsFilePicker, nsIFilePicker)
    50 // We never want to call the secret show hidden files API unless the pref
    51 // has been set. Once the pref has been set we always need to call it even
    52 // if it disappears so that we stop showing hidden files if a user deletes
    53 // the pref. If the secret API was used once and things worked out it should
    54 // continue working for subsequent calls so the user is at no more risk.
    55 static void SetShowHiddenFileState(NSSavePanel* panel)
    56 {
    57   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
    59   bool show = false;
    60   if (NS_SUCCEEDED(Preferences::GetBool(kShowHiddenFilesPref, &show))) {
    61     gCallSecretHiddenFileAPI = true;
    62   }
    64   if (gCallSecretHiddenFileAPI) {
    65     // invoke a method to get a Cocoa-internal nav view
    66     SEL navViewSelector = @selector(_navView);
    67     NSMethodSignature* navViewSignature = [panel methodSignatureForSelector:navViewSelector];
    68     if (!navViewSignature)
    69       return;
    70     NSInvocation* navViewInvocation = [NSInvocation invocationWithMethodSignature:navViewSignature];
    71     [navViewInvocation setSelector:navViewSelector];
    72     [navViewInvocation setTarget:panel];
    73     [navViewInvocation invoke];
    75     // get the returned nav view
    76     id navView = nil;
    77     [navViewInvocation getReturnValue:&navView];
    79     // invoke the secret show hidden file state method on the nav view
    80     SEL showHiddenFilesSelector = @selector(setShowsHiddenFiles:);
    81     NSMethodSignature* showHiddenFilesSignature = [navView methodSignatureForSelector:showHiddenFilesSelector];
    82     if (!showHiddenFilesSignature)
    83       return;
    84     NSInvocation* showHiddenFilesInvocation = [NSInvocation invocationWithMethodSignature:showHiddenFilesSignature];
    85     [showHiddenFilesInvocation setSelector:showHiddenFilesSelector];
    86     [showHiddenFilesInvocation setTarget:navView];
    87     [showHiddenFilesInvocation setArgument:&show atIndex:2];
    88     [showHiddenFilesInvocation invoke];
    89   }
    91   NS_OBJC_END_TRY_ABORT_BLOCK;
    92 }
    94 nsFilePicker::nsFilePicker()
    95 : mSelectedTypeIndex(0)
    96 {
    97 }
    99 nsFilePicker::~nsFilePicker()
   100 {
   101 }
   103 void
   104 nsFilePicker::InitNative(nsIWidget *aParent, const nsAString& aTitle)
   105 {
   106   mTitle = aTitle;
   107 }
   109 NSView* nsFilePicker::GetAccessoryView()
   110 {
   111   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   113   NSView* accessoryView = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)] autorelease];
   115   // Set a label's default value.
   116   NSString* label = @"Format:";
   118   // Try to get the localized string.
   119   nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
   120   nsCOMPtr<nsIStringBundle> bundle;
   121   nsresult rv = sbs->CreateBundle("chrome://global/locale/filepicker.properties", getter_AddRefs(bundle));
   122   if (NS_SUCCEEDED(rv)) {
   123     nsXPIDLString locaLabel;
   124     bundle->GetStringFromName(NS_LITERAL_STRING("formatLabel").get(),
   125 			      getter_Copies(locaLabel));
   126     if (locaLabel) {
   127       label = [NSString stringWithCharacters:reinterpret_cast<const unichar*>(locaLabel.get())
   128                                       length:locaLabel.Length()];
   129     }
   130   }
   132   // set up label text field
   133   NSTextField* textField = [[[NSTextField alloc] init] autorelease];
   134   [textField setEditable:NO];
   135   [textField setSelectable:NO];
   136   [textField setDrawsBackground:NO];
   137   [textField setBezeled:NO];
   138   [textField setBordered:NO];
   139   [textField setFont:[NSFont labelFontOfSize:13.0]];
   140   [textField setStringValue:label];
   141   [textField setTag:0];
   142   [textField sizeToFit];
   144   // set up popup button
   145   NSPopUpButton* popupButton = [[[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 0, 0) pullsDown:NO] autorelease];
   146   uint32_t numMenuItems = mTitles.Length();
   147   for (uint32_t i = 0; i < numMenuItems; i++) {
   148     const nsString& currentTitle = mTitles[i];
   149     NSString *titleString;
   150     if (currentTitle.IsEmpty()) {
   151       const nsString& currentFilter = mFilters[i];
   152       titleString = [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentFilter.get())
   153                                                   length:currentFilter.Length()];
   154     }
   155     else {
   156       titleString = [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentTitle.get())
   157                                                   length:currentTitle.Length()];
   158     }
   159     [popupButton addItemWithTitle:titleString];
   160     [titleString release];
   161   }
   162   if (mSelectedTypeIndex >= 0 && (uint32_t)mSelectedTypeIndex < numMenuItems)
   163     [popupButton selectItemAtIndex:mSelectedTypeIndex];
   164   [popupButton setTag:kSaveTypeControlTag];
   165   [popupButton sizeToFit]; // we have to do sizeToFit to get the height calculated for us
   166   // This is just a default width that works well, doesn't truncate the vast majority of
   167   // things that might end up in the menu.
   168   [popupButton setFrameSize:NSMakeSize(180, [popupButton frame].size.height)];
   170   // position everything based on control sizes with kAccessoryViewPadding pix padding
   171   // on each side kAccessoryViewPadding pix horizontal padding between controls
   172   float greatestHeight = [textField frame].size.height;
   173   if ([popupButton frame].size.height > greatestHeight)
   174     greatestHeight = [popupButton frame].size.height;
   175   float totalViewHeight = greatestHeight + kAccessoryViewPadding * 2;
   176   float totalViewWidth  = [textField frame].size.width + [popupButton frame].size.width + kAccessoryViewPadding * 3;
   177   [accessoryView setFrameSize:NSMakeSize(totalViewWidth, totalViewHeight)];
   179   float textFieldOriginY = ((greatestHeight - [textField frame].size.height) / 2 + 1) + kAccessoryViewPadding;
   180   [textField setFrameOrigin:NSMakePoint(kAccessoryViewPadding, textFieldOriginY)];
   182   float popupOriginX = [textField frame].size.width + kAccessoryViewPadding * 2;
   183   float popupOriginY = ((greatestHeight - [popupButton frame].size.height) / 2) + kAccessoryViewPadding;
   184   [popupButton setFrameOrigin:NSMakePoint(popupOriginX, popupOriginY)];
   186   [accessoryView addSubview:textField];
   187   [accessoryView addSubview:popupButton];
   188   return accessoryView;
   190   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   191 }
   193 // Display the file dialog
   194 NS_IMETHODIMP nsFilePicker::Show(int16_t *retval)
   195 {
   196   NS_ENSURE_ARG_POINTER(retval);
   198   *retval = returnCancel;
   200   int16_t userClicksOK = returnCancel;
   202 // Random questions from DHH:
   203 //
   204 // Why do we pass mTitle, mDefault to the functions?  Can GetLocalFile. PutLocalFile,
   205 // and GetLocalFolder get called someplace else?  It generates a bunch of warnings
   206 // as it is right now.
   207 //
   208 // I think we could easily combine GetLocalFile and GetLocalFolder together, just
   209 // setting panel pick options based on mMode.  I didn't do it here b/c I wanted to 
   210 // make this look as much like Carbon nsFilePicker as possible.  
   212   mFiles.Clear();
   213   nsCOMPtr<nsIFile> theFile;
   215   switch (mMode)
   216   {
   217     case modeOpen:
   218       userClicksOK = GetLocalFiles(mTitle, false, mFiles);
   219       break;
   221     case modeOpenMultiple:
   222       userClicksOK = GetLocalFiles(mTitle, true, mFiles);
   223       break;
   225     case modeSave:
   226       userClicksOK = PutLocalFile(mTitle, mDefault, getter_AddRefs(theFile));
   227       break;
   229     case modeGetFolder:
   230       userClicksOK = GetLocalFolder(mTitle, getter_AddRefs(theFile));
   231       break;
   233     default:
   234       NS_ERROR("Unknown file picker mode");
   235       break;
   236   }
   238   if (theFile)
   239     mFiles.AppendObject(theFile);
   241   *retval = userClicksOK;
   242   return NS_OK;
   243 }
   245 static
   246 void UpdatePanelFileTypes(NSOpenPanel* aPanel, NSArray* aFilters)
   247 {
   248   // If we show all file types, also "expose" bundles' contents.
   249   [aPanel setTreatsFilePackagesAsDirectories:!aFilters];
   251   [aPanel setAllowedFileTypes:aFilters];
   252 }
   254 @implementation NSPopUpButtonObserver
   255 - (void) setPopUpButton:(NSPopUpButton*)aPopUpButton
   256 {
   257   mPopUpButton = aPopUpButton;
   258 }
   260 - (void) setOpenPanel:(NSOpenPanel*)aOpenPanel
   261 {
   262   mOpenPanel = aOpenPanel;
   263 }
   265 - (void) setFilePicker:(nsFilePicker*)aFilePicker
   266 {
   267   mFilePicker = aFilePicker;
   268 }
   270 - (void) menuChangedItem:(NSNotification *)aSender
   271 {
   272   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
   273   int32_t selectedItem = [mPopUpButton indexOfSelectedItem];
   274   if (selectedItem < 0) {
   275     return;
   276   }
   278   mFilePicker->SetFilterIndex(selectedItem);
   279   UpdatePanelFileTypes(mOpenPanel, mFilePicker->GetFilterList());
   281   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN();
   282 }
   283 @end
   285 // Use OpenPanel to do a GetFile. Returns |returnOK| if the user presses OK in the dialog. 
   286 int16_t
   287 nsFilePicker::GetLocalFiles(const nsString& inTitle, bool inAllowMultiple, nsCOMArray<nsIFile>& outFiles)
   288 {
   289   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
   291   int16_t retVal = (int16_t)returnCancel;
   292   NSOpenPanel *thePanel = [NSOpenPanel openPanel];
   294   SetShowHiddenFileState(thePanel);
   296   // Set the options for how the get file dialog will appear
   297   SetDialogTitle(inTitle, thePanel);
   298   [thePanel setAllowsMultipleSelection:inAllowMultiple];
   299   [thePanel setCanSelectHiddenExtension:YES];
   300   [thePanel setCanChooseDirectories:NO];
   301   [thePanel setCanChooseFiles:YES];
   302   [thePanel setResolvesAliases:YES]; //this is default - probably doesn't need to be set
   304   // Get filters
   305   // filters may be null, if we should allow all file types.
   306   NSArray *filters = GetFilterList();
   308   // set up default directory
   309   NSString *theDir = PanelDefaultDirectory();
   311   // if this is the "Choose application..." dialog, and no other start
   312   // dir has been set, then use the Applications folder.
   313   if (!theDir) {
   314     if (filters && [filters count] == 1 &&
   315         [(NSString *)[filters objectAtIndex:0] isEqualToString:@"app"])
   316       theDir = @"/Applications/";
   317     else
   318       theDir = @"";
   319   }
   321   if (theDir) {
   322     [thePanel setDirectoryURL:[NSURL fileURLWithPath:theDir isDirectory:YES]];
   323   }
   325   int result;
   326   nsCocoaUtils::PrepareForNativeAppModalDialog();
   327   if (mFilters.Length() > 1) {
   328     // [NSURL initWithString:] (below) throws an exception if URLString is nil.
   330     NSPopUpButtonObserver* observer = [[NSPopUpButtonObserver alloc] init];
   332     NSView* accessoryView = GetAccessoryView();
   333     [thePanel setAccessoryView:accessoryView];
   335     [observer setPopUpButton:[accessoryView viewWithTag:kSaveTypeControlTag]];
   336     [observer setOpenPanel:thePanel];
   337     [observer setFilePicker:this];
   339     [[NSNotificationCenter defaultCenter]
   340       addObserver:observer
   341       selector:@selector(menuChangedItem:)
   342       name:NSMenuWillSendActionNotification object:nil];
   344     UpdatePanelFileTypes(thePanel, filters);
   345     result = [thePanel runModal];
   347     [[NSNotificationCenter defaultCenter] removeObserver:observer];
   348     [observer release];
   349   } else {
   350     // If we show all file types, also "expose" bundles' contents.
   351     if (!filters) {
   352       [thePanel setTreatsFilePackagesAsDirectories:YES];
   353     }
   354     [thePanel setAllowedFileTypes:filters];
   355     result = [thePanel runModal];
   356   }
   357   nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
   359   if (result == NSFileHandlingPanelCancelButton)
   360     return retVal;
   362   // Converts data from a NSArray of NSURL to the returned format.
   363   // We should be careful to not call [thePanel URLs] more than once given that
   364   // it creates a new array each time.
   365   // We are using Fast Enumeration, thus the NSURL array is created once then
   366   // iterated.
   367   for (NSURL* url in [thePanel URLs]) {
   368     if (!url) {
   369       continue;
   370     }
   372     nsCOMPtr<nsIFile> localFile;
   373     NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
   374     nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
   375     if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)url))) {
   376       outFiles.AppendObject(localFile);
   377     }
   378   }
   380   if (outFiles.Count() > 0)
   381     retVal = returnOK;
   383   return retVal;
   385   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
   386 }
   388 // Use OpenPanel to do a GetFolder. Returns |returnOK| if the user presses OK in the dialog.
   389 int16_t
   390 nsFilePicker::GetLocalFolder(const nsString& inTitle, nsIFile** outFile)
   391 {
   392   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
   393   NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer");
   395   int16_t retVal = (int16_t)returnCancel;
   396   NSOpenPanel *thePanel = [NSOpenPanel openPanel];
   398   SetShowHiddenFileState(thePanel);
   400   // Set the options for how the get file dialog will appear
   401   SetDialogTitle(inTitle, thePanel);
   402   [thePanel setAllowsMultipleSelection:NO];   //this is default -probably doesn't need to be set
   403   [thePanel setCanSelectHiddenExtension:YES];
   404   [thePanel setCanChooseDirectories:YES];
   405   [thePanel setCanChooseFiles:NO];
   406   [thePanel setResolvesAliases:YES];          //this is default - probably doesn't need to be set
   407   [thePanel setCanCreateDirectories:YES];
   409   // packages != folders
   410   [thePanel setTreatsFilePackagesAsDirectories:NO];
   412   // set up default directory
   413   NSString *theDir = PanelDefaultDirectory();
   414   if (theDir) {
   415     [thePanel setDirectoryURL:[NSURL fileURLWithPath:theDir isDirectory:YES]];
   416   }
   417   nsCocoaUtils::PrepareForNativeAppModalDialog();
   418   int result = [thePanel runModal];
   419   nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
   421   if (result == NSFileHandlingPanelCancelButton)
   422     return retVal;
   424   // get the path for the folder (we allow just 1, so that's all we get)
   425   NSURL *theURL = [[thePanel URLs] objectAtIndex:0];
   426   if (theURL) {
   427     nsCOMPtr<nsIFile> localFile;
   428     NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
   429     nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
   430     if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)theURL))) {
   431       *outFile = localFile;
   432       NS_ADDREF(*outFile);
   433       retVal = returnOK;
   434     }
   435   }
   437   return retVal;
   439   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
   440 }
   442 // Returns |returnOK| if the user presses OK in the dialog.
   443 int16_t
   444 nsFilePicker::PutLocalFile(const nsString& inTitle, const nsString& inDefaultName, nsIFile** outFile)
   445 {
   446   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
   447   NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer");
   449   int16_t retVal = returnCancel;
   450   NSSavePanel *thePanel = [NSSavePanel savePanel];
   452   SetShowHiddenFileState(thePanel);
   454   SetDialogTitle(inTitle, thePanel);
   456   // set up accessory view for file format options
   457   NSView* accessoryView = GetAccessoryView();
   458   [thePanel setAccessoryView:accessoryView];
   460   // set up default file name
   461   NSString* defaultFilename = [NSString stringWithCharacters:(const unichar*)inDefaultName.get() length:inDefaultName.Length()];
   463   // set up default directory
   464   NSString *theDir = PanelDefaultDirectory();
   465   if (theDir) {
   466     [thePanel setDirectoryURL:[NSURL fileURLWithPath:theDir isDirectory:YES]];
   467   }
   469   // load the panel
   470   nsCocoaUtils::PrepareForNativeAppModalDialog();
   471   [thePanel setNameFieldStringValue:defaultFilename];
   472   int result = [thePanel runModal];
   473   nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
   474   if (result == NSFileHandlingPanelCancelButton)
   475     return retVal;
   477   // get the save type
   478   NSPopUpButton* popupButton = [accessoryView viewWithTag:kSaveTypeControlTag];
   479   if (popupButton) {
   480     mSelectedTypeIndex = [popupButton indexOfSelectedItem];
   481   }
   483   NSURL* fileURL = [thePanel URL];
   484   if (fileURL) { 
   485     nsCOMPtr<nsIFile> localFile;
   486     NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
   487     nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
   488     if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)fileURL))) {
   489       *outFile = localFile;
   490       NS_ADDREF(*outFile);
   491       // We tell if we are replacing or not by just looking to see if the file exists.
   492       // The user could not have hit OK and not meant to replace the file.
   493       if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]])
   494         retVal = returnReplace;
   495       else
   496         retVal = returnOK;
   497     }
   498   }
   500   return retVal;
   502   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
   503 }
   505 NSArray *
   506 nsFilePicker::GetFilterList()
   507 {
   508   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   510   if (!mFilters.Length()) {
   511     return nil;
   512   }
   514   if (mFilters.Length() <= (uint32_t)mSelectedTypeIndex) {
   515     NS_WARNING("An out of range index has been selected. Using the first index instead.");
   516     mSelectedTypeIndex = 0;
   517   }
   519   const nsString& filterWide = mFilters[mSelectedTypeIndex];
   520   if (!filterWide.Length()) {
   521     return nil;
   522   }
   524   if (filterWide.Equals(NS_LITERAL_STRING("*"))) {
   525     return nil;
   526   }
   528   // The extensions in filterWide are in the format "*.ext" but are expected
   529   // in the format "ext" by NSOpenPanel. So we need to filter some characters.
   530   NSMutableString* filterString = [[[NSMutableString alloc] initWithString:
   531                                     [NSString stringWithCharacters:reinterpret_cast<const unichar*>(filterWide.get())
   532                                                             length:filterWide.Length()]] autorelease];
   533   NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@". *"];
   534   NSRange range = [filterString rangeOfCharacterFromSet:set];
   535   while (range.length) {
   536     [filterString replaceCharactersInRange:range withString:@""];
   537     range = [filterString rangeOfCharacterFromSet:set];
   538   }
   540   return [[[NSArray alloc] initWithArray:
   541            [filterString componentsSeparatedByString:@";"]] autorelease];
   543   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   544 }
   546 // Sets the dialog title to whatever it should be.  If it fails, eh,
   547 // the OS will provide a sensible default.
   548 void
   549 nsFilePicker::SetDialogTitle(const nsString& inTitle, id aPanel)
   550 {
   551   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   553   [aPanel setTitle:[NSString stringWithCharacters:(const unichar*)inTitle.get() length:inTitle.Length()]];
   555   NS_OBJC_END_TRY_ABORT_BLOCK;
   556 } 
   558 // Converts path from an nsIFile into a NSString path
   559 // If it fails, returns an empty string.
   560 NSString *
   561 nsFilePicker::PanelDefaultDirectory()
   562 {
   563   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   565   NSString *directory = nil;
   566   if (mDisplayDirectory) {
   567     nsAutoString pathStr;
   568     mDisplayDirectory->GetPath(pathStr);
   569     directory = [[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(pathStr.get())
   570                                                length:pathStr.Length()] autorelease];
   571   }
   572   return directory;
   574   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   575 }
   577 NS_IMETHODIMP nsFilePicker::GetFile(nsIFile **aFile)
   578 {
   579   NS_ENSURE_ARG_POINTER(aFile);
   580   *aFile = nullptr;
   582   // just return the first file
   583   if (mFiles.Count() > 0) {
   584     *aFile = mFiles.ObjectAt(0);
   585     NS_IF_ADDREF(*aFile);
   586   }
   588   return NS_OK;
   589 }
   591 NS_IMETHODIMP nsFilePicker::GetFileURL(nsIURI **aFileURL)
   592 {
   593   NS_ENSURE_ARG_POINTER(aFileURL);
   594   *aFileURL = nullptr;
   596   if (mFiles.Count() == 0)
   597     return NS_OK;
   599   return NS_NewFileURI(aFileURL, mFiles.ObjectAt(0));
   600 }
   602 NS_IMETHODIMP nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
   603 {
   604   return NS_NewArrayEnumerator(aFiles, mFiles);
   605 }
   607 NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString& aString)
   608 {
   609   mDefault = aString;
   610   return NS_OK;
   611 }
   613 NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString& aString)
   614 {
   615   return NS_ERROR_FAILURE;
   616 }
   618 // The default extension to use for files
   619 NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension)
   620 {
   621   aExtension.Truncate();
   622   return NS_OK;
   623 }
   625 NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString& aExtension)
   626 {
   627   return NS_OK;
   628 }
   630 // Append an entry to the filters array
   631 NS_IMETHODIMP
   632 nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
   633 {
   634   // "..apps" has to be translated with native executable extensions.
   635   if (aFilter.EqualsLiteral("..apps")) {
   636     mFilters.AppendElement(NS_LITERAL_STRING("*.app"));
   637   } else {
   638     mFilters.AppendElement(aFilter);
   639   }
   640   mTitles.AppendElement(aTitle);
   642   return NS_OK;
   643 }
   645 // Get the filter index - do we still need this?
   646 NS_IMETHODIMP nsFilePicker::GetFilterIndex(int32_t *aFilterIndex)
   647 {
   648   *aFilterIndex = mSelectedTypeIndex;
   649   return NS_OK;
   650 }
   652 // Set the filter index - do we still need this?
   653 NS_IMETHODIMP nsFilePicker::SetFilterIndex(int32_t aFilterIndex)
   654 {
   655   mSelectedTypeIndex = aFilterIndex;
   656   return NS_OK;
   657 }

mercurial