summaryrefslogtreecommitdiffstats
path: root/widget/cocoa/nsFilePicker.mm
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /widget/cocoa/nsFilePicker.mm
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'widget/cocoa/nsFilePicker.mm')
-rw-r--r--widget/cocoa/nsFilePicker.mm676
1 files changed, 676 insertions, 0 deletions
diff --git a/widget/cocoa/nsFilePicker.mm b/widget/cocoa/nsFilePicker.mm
new file mode 100644
index 000000000..5213dee24
--- /dev/null
+++ b/widget/cocoa/nsFilePicker.mm
@@ -0,0 +1,676 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#import <Cocoa/Cocoa.h>
+
+#include "nsFilePicker.h"
+#include "nsCOMPtr.h"
+#include "nsReadableUtils.h"
+#include "nsNetUtil.h"
+#include "nsIComponentManager.h"
+#include "nsIFile.h"
+#include "nsILocalFileMac.h"
+#include "nsIURL.h"
+#include "nsArrayEnumerator.h"
+#include "nsIStringBundle.h"
+#include "nsCocoaUtils.h"
+#include "mozilla/Preferences.h"
+
+// This must be included last:
+#include "nsObjCExceptions.h"
+
+using namespace mozilla;
+
+const float kAccessoryViewPadding = 5;
+const int kSaveTypeControlTag = 1;
+
+static bool gCallSecretHiddenFileAPI = false;
+const char kShowHiddenFilesPref[] = "filepicker.showHiddenFiles";
+
+/**
+ * This class is an observer of NSPopUpButton selection change.
+ */
+@interface NSPopUpButtonObserver : NSObject
+{
+ NSPopUpButton* mPopUpButton;
+ NSOpenPanel* mOpenPanel;
+ nsFilePicker* mFilePicker;
+}
+- (void) setPopUpButton:(NSPopUpButton*)aPopUpButton;
+- (void) setOpenPanel:(NSOpenPanel*)aOpenPanel;
+- (void) setFilePicker:(nsFilePicker*)aFilePicker;
+- (void) menuChangedItem:(NSNotification*)aSender;
+@end
+
+NS_IMPL_ISUPPORTS(nsFilePicker, nsIFilePicker)
+
+// We never want to call the secret show hidden files API unless the pref
+// has been set. Once the pref has been set we always need to call it even
+// if it disappears so that we stop showing hidden files if a user deletes
+// the pref. If the secret API was used once and things worked out it should
+// continue working for subsequent calls so the user is at no more risk.
+static void SetShowHiddenFileState(NSSavePanel* panel)
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+ bool show = false;
+ if (NS_SUCCEEDED(Preferences::GetBool(kShowHiddenFilesPref, &show))) {
+ gCallSecretHiddenFileAPI = true;
+ }
+
+ if (gCallSecretHiddenFileAPI) {
+ // invoke a method to get a Cocoa-internal nav view
+ SEL navViewSelector = @selector(_navView);
+ NSMethodSignature* navViewSignature = [panel methodSignatureForSelector:navViewSelector];
+ if (!navViewSignature)
+ return;
+ NSInvocation* navViewInvocation = [NSInvocation invocationWithMethodSignature:navViewSignature];
+ [navViewInvocation setSelector:navViewSelector];
+ [navViewInvocation setTarget:panel];
+ [navViewInvocation invoke];
+
+ // get the returned nav view
+ id navView = nil;
+ [navViewInvocation getReturnValue:&navView];
+
+ // invoke the secret show hidden file state method on the nav view
+ SEL showHiddenFilesSelector = @selector(setShowsHiddenFiles:);
+ NSMethodSignature* showHiddenFilesSignature = [navView methodSignatureForSelector:showHiddenFilesSelector];
+ if (!showHiddenFilesSignature)
+ return;
+ NSInvocation* showHiddenFilesInvocation = [NSInvocation invocationWithMethodSignature:showHiddenFilesSignature];
+ [showHiddenFilesInvocation setSelector:showHiddenFilesSelector];
+ [showHiddenFilesInvocation setTarget:navView];
+ [showHiddenFilesInvocation setArgument:&show atIndex:2];
+ [showHiddenFilesInvocation invoke];
+ }
+
+ NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+nsFilePicker::nsFilePicker()
+: mSelectedTypeIndex(0)
+{
+}
+
+nsFilePicker::~nsFilePicker()
+{
+}
+
+void
+nsFilePicker::InitNative(nsIWidget *aParent, const nsAString& aTitle)
+{
+ mTitle = aTitle;
+}
+
+NSView* nsFilePicker::GetAccessoryView()
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+ NSView* accessoryView = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)] autorelease];
+
+ // Set a label's default value.
+ NSString* label = @"Format:";
+
+ // Try to get the localized string.
+ nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
+ nsCOMPtr<nsIStringBundle> bundle;
+ nsresult rv = sbs->CreateBundle("chrome://global/locale/filepicker.properties", getter_AddRefs(bundle));
+ if (NS_SUCCEEDED(rv)) {
+ nsXPIDLString locaLabel;
+ bundle->GetStringFromName(u"formatLabel", getter_Copies(locaLabel));
+ if (locaLabel) {
+ label = [NSString stringWithCharacters:reinterpret_cast<const unichar*>(locaLabel.get())
+ length:locaLabel.Length()];
+ }
+ }
+
+ // set up label text field
+ NSTextField* textField = [[[NSTextField alloc] init] autorelease];
+ [textField setEditable:NO];
+ [textField setSelectable:NO];
+ [textField setDrawsBackground:NO];
+ [textField setBezeled:NO];
+ [textField setBordered:NO];
+ [textField setFont:[NSFont labelFontOfSize:13.0]];
+ [textField setStringValue:label];
+ [textField setTag:0];
+ [textField sizeToFit];
+
+ // set up popup button
+ NSPopUpButton* popupButton = [[[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 0, 0) pullsDown:NO] autorelease];
+ uint32_t numMenuItems = mTitles.Length();
+ for (uint32_t i = 0; i < numMenuItems; i++) {
+ const nsString& currentTitle = mTitles[i];
+ NSString *titleString;
+ if (currentTitle.IsEmpty()) {
+ const nsString& currentFilter = mFilters[i];
+ titleString = [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentFilter.get())
+ length:currentFilter.Length()];
+ }
+ else {
+ titleString = [[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(currentTitle.get())
+ length:currentTitle.Length()];
+ }
+ [popupButton addItemWithTitle:titleString];
+ [titleString release];
+ }
+ if (mSelectedTypeIndex >= 0 && (uint32_t)mSelectedTypeIndex < numMenuItems)
+ [popupButton selectItemAtIndex:mSelectedTypeIndex];
+ [popupButton setTag:kSaveTypeControlTag];
+ [popupButton sizeToFit]; // we have to do sizeToFit to get the height calculated for us
+ // This is just a default width that works well, doesn't truncate the vast majority of
+ // things that might end up in the menu.
+ [popupButton setFrameSize:NSMakeSize(180, [popupButton frame].size.height)];
+
+ // position everything based on control sizes with kAccessoryViewPadding pix padding
+ // on each side kAccessoryViewPadding pix horizontal padding between controls
+ float greatestHeight = [textField frame].size.height;
+ if ([popupButton frame].size.height > greatestHeight)
+ greatestHeight = [popupButton frame].size.height;
+ float totalViewHeight = greatestHeight + kAccessoryViewPadding * 2;
+ float totalViewWidth = [textField frame].size.width + [popupButton frame].size.width + kAccessoryViewPadding * 3;
+ [accessoryView setFrameSize:NSMakeSize(totalViewWidth, totalViewHeight)];
+
+ float textFieldOriginY = ((greatestHeight - [textField frame].size.height) / 2 + 1) + kAccessoryViewPadding;
+ [textField setFrameOrigin:NSMakePoint(kAccessoryViewPadding, textFieldOriginY)];
+
+ float popupOriginX = [textField frame].size.width + kAccessoryViewPadding * 2;
+ float popupOriginY = ((greatestHeight - [popupButton frame].size.height) / 2) + kAccessoryViewPadding;
+ [popupButton setFrameOrigin:NSMakePoint(popupOriginX, popupOriginY)];
+
+ [accessoryView addSubview:textField];
+ [accessoryView addSubview:popupButton];
+ return accessoryView;
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+// Display the file dialog
+NS_IMETHODIMP nsFilePicker::Show(int16_t *retval)
+{
+ NS_ENSURE_ARG_POINTER(retval);
+
+ *retval = returnCancel;
+
+ int16_t userClicksOK = returnCancel;
+
+// Random questions from DHH:
+//
+// Why do we pass mTitle, mDefault to the functions? Can GetLocalFile. PutLocalFile,
+// and GetLocalFolder get called someplace else? It generates a bunch of warnings
+// as it is right now.
+//
+// I think we could easily combine GetLocalFile and GetLocalFolder together, just
+// setting panel pick options based on mMode. I didn't do it here b/c I wanted to
+// make this look as much like Carbon nsFilePicker as possible.
+
+ mFiles.Clear();
+ nsCOMPtr<nsIFile> theFile;
+
+ switch (mMode)
+ {
+ case modeOpen:
+ userClicksOK = GetLocalFiles(mTitle, false, mFiles);
+ break;
+
+ case modeOpenMultiple:
+ userClicksOK = GetLocalFiles(mTitle, true, mFiles);
+ break;
+
+ case modeSave:
+ userClicksOK = PutLocalFile(mTitle, mDefault, getter_AddRefs(theFile));
+ break;
+
+ case modeGetFolder:
+ userClicksOK = GetLocalFolder(mTitle, getter_AddRefs(theFile));
+ break;
+
+ default:
+ NS_ERROR("Unknown file picker mode");
+ break;
+ }
+
+ if (theFile)
+ mFiles.AppendObject(theFile);
+
+ *retval = userClicksOK;
+ return NS_OK;
+}
+
+static
+void UpdatePanelFileTypes(NSOpenPanel* aPanel, NSArray* aFilters)
+{
+ // If we show all file types, also "expose" bundles' contents.
+ [aPanel setTreatsFilePackagesAsDirectories:!aFilters];
+
+ [aPanel setAllowedFileTypes:aFilters];
+}
+
+@implementation NSPopUpButtonObserver
+- (void) setPopUpButton:(NSPopUpButton*)aPopUpButton
+{
+ mPopUpButton = aPopUpButton;
+}
+
+- (void) setOpenPanel:(NSOpenPanel*)aOpenPanel
+{
+ mOpenPanel = aOpenPanel;
+}
+
+- (void) setFilePicker:(nsFilePicker*)aFilePicker
+{
+ mFilePicker = aFilePicker;
+}
+
+- (void) menuChangedItem:(NSNotification *)aSender
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
+ int32_t selectedItem = [mPopUpButton indexOfSelectedItem];
+ if (selectedItem < 0) {
+ return;
+ }
+
+ mFilePicker->SetFilterIndex(selectedItem);
+ UpdatePanelFileTypes(mOpenPanel, mFilePicker->GetFilterList());
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_RETURN();
+}
+@end
+
+// Use OpenPanel to do a GetFile. Returns |returnOK| if the user presses OK in the dialog.
+int16_t
+nsFilePicker::GetLocalFiles(const nsString& inTitle, bool inAllowMultiple, nsCOMArray<nsIFile>& outFiles)
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
+
+ int16_t retVal = (int16_t)returnCancel;
+ NSOpenPanel *thePanel = [NSOpenPanel openPanel];
+
+ SetShowHiddenFileState(thePanel);
+
+ // Set the options for how the get file dialog will appear
+ SetDialogTitle(inTitle, thePanel);
+ [thePanel setAllowsMultipleSelection:inAllowMultiple];
+ [thePanel setCanSelectHiddenExtension:YES];
+ [thePanel setCanChooseDirectories:NO];
+ [thePanel setCanChooseFiles:YES];
+ [thePanel setResolvesAliases:YES]; //this is default - probably doesn't need to be set
+
+ // Get filters
+ // filters may be null, if we should allow all file types.
+ NSArray *filters = GetFilterList();
+
+ // set up default directory
+ NSString *theDir = PanelDefaultDirectory();
+
+ // if this is the "Choose application..." dialog, and no other start
+ // dir has been set, then use the Applications folder.
+ if (!theDir) {
+ if (filters && [filters count] == 1 &&
+ [(NSString *)[filters objectAtIndex:0] isEqualToString:@"app"])
+ theDir = @"/Applications/";
+ else
+ theDir = @"";
+ }
+
+ if (theDir) {
+ [thePanel setDirectoryURL:[NSURL fileURLWithPath:theDir isDirectory:YES]];
+ }
+
+ int result;
+ nsCocoaUtils::PrepareForNativeAppModalDialog();
+ if (mFilters.Length() > 1) {
+ // [NSURL initWithString:] (below) throws an exception if URLString is nil.
+
+ NSPopUpButtonObserver* observer = [[NSPopUpButtonObserver alloc] init];
+
+ NSView* accessoryView = GetAccessoryView();
+ [thePanel setAccessoryView:accessoryView];
+
+ [observer setPopUpButton:[accessoryView viewWithTag:kSaveTypeControlTag]];
+ [observer setOpenPanel:thePanel];
+ [observer setFilePicker:this];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:observer
+ selector:@selector(menuChangedItem:)
+ name:NSMenuWillSendActionNotification object:nil];
+
+ UpdatePanelFileTypes(thePanel, filters);
+ result = [thePanel runModal];
+
+ [[NSNotificationCenter defaultCenter] removeObserver:observer];
+ [observer release];
+ } else {
+ // If we show all file types, also "expose" bundles' contents.
+ if (!filters) {
+ [thePanel setTreatsFilePackagesAsDirectories:YES];
+ }
+ [thePanel setAllowedFileTypes:filters];
+ result = [thePanel runModal];
+ }
+ nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
+
+ if (result == NSFileHandlingPanelCancelButton)
+ return retVal;
+
+ // Converts data from a NSArray of NSURL to the returned format.
+ // We should be careful to not call [thePanel URLs] more than once given that
+ // it creates a new array each time.
+ // We are using Fast Enumeration, thus the NSURL array is created once then
+ // iterated.
+ for (NSURL* url in [thePanel URLs]) {
+ if (!url) {
+ continue;
+ }
+
+ nsCOMPtr<nsIFile> localFile;
+ NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
+ nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
+ if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)url))) {
+ outFiles.AppendObject(localFile);
+ }
+ }
+
+ if (outFiles.Count() > 0)
+ retVal = returnOK;
+
+ return retVal;
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
+}
+
+// Use OpenPanel to do a GetFolder. Returns |returnOK| if the user presses OK in the dialog.
+int16_t
+nsFilePicker::GetLocalFolder(const nsString& inTitle, nsIFile** outFile)
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
+ NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer");
+
+ int16_t retVal = (int16_t)returnCancel;
+ NSOpenPanel *thePanel = [NSOpenPanel openPanel];
+
+ SetShowHiddenFileState(thePanel);
+
+ // Set the options for how the get file dialog will appear
+ SetDialogTitle(inTitle, thePanel);
+ [thePanel setAllowsMultipleSelection:NO]; //this is default -probably doesn't need to be set
+ [thePanel setCanSelectHiddenExtension:YES];
+ [thePanel setCanChooseDirectories:YES];
+ [thePanel setCanChooseFiles:NO];
+ [thePanel setResolvesAliases:YES]; //this is default - probably doesn't need to be set
+ [thePanel setCanCreateDirectories:YES];
+
+ // packages != folders
+ [thePanel setTreatsFilePackagesAsDirectories:NO];
+
+ // set up default directory
+ NSString *theDir = PanelDefaultDirectory();
+ if (theDir) {
+ [thePanel setDirectoryURL:[NSURL fileURLWithPath:theDir isDirectory:YES]];
+ }
+ nsCocoaUtils::PrepareForNativeAppModalDialog();
+ int result = [thePanel runModal];
+ nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
+
+ if (result == NSFileHandlingPanelCancelButton)
+ return retVal;
+
+ // get the path for the folder (we allow just 1, so that's all we get)
+ NSURL *theURL = [[thePanel URLs] objectAtIndex:0];
+ if (theURL) {
+ nsCOMPtr<nsIFile> localFile;
+ NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
+ nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
+ if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)theURL))) {
+ *outFile = localFile;
+ NS_ADDREF(*outFile);
+ retVal = returnOK;
+ }
+ }
+
+ return retVal;
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
+}
+
+// Returns |returnOK| if the user presses OK in the dialog.
+int16_t
+nsFilePicker::PutLocalFile(const nsString& inTitle, const nsString& inDefaultName, nsIFile** outFile)
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
+ NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer");
+
+ int16_t retVal = returnCancel;
+ NSSavePanel *thePanel = [NSSavePanel savePanel];
+
+ SetShowHiddenFileState(thePanel);
+
+ SetDialogTitle(inTitle, thePanel);
+
+ // set up accessory view for file format options
+ NSView* accessoryView = GetAccessoryView();
+ [thePanel setAccessoryView:accessoryView];
+
+ // set up default file name
+ NSString* defaultFilename = [NSString stringWithCharacters:(const unichar*)inDefaultName.get() length:inDefaultName.Length()];
+
+ // set up allowed types; this prevents the extension from being selected
+ // use the UTI for the file type to allow alternate extensions (e.g., jpg vs. jpeg)
+ NSString* extension = defaultFilename.pathExtension;
+ if (extension.length != 0) {
+ CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)extension, NULL);
+
+ if (type) {
+ thePanel.allowedFileTypes = @[(NSString*)type];
+ CFRelease(type);
+ } else {
+ // if there's no UTI for the file extension, use the extension itself.
+ thePanel.allowedFileTypes = @[extension];
+ }
+ }
+ // Allow users to change the extension.
+ thePanel.allowsOtherFileTypes = YES;
+
+ // set up default directory
+ NSString *theDir = PanelDefaultDirectory();
+ if (theDir) {
+ [thePanel setDirectoryURL:[NSURL fileURLWithPath:theDir isDirectory:YES]];
+ }
+
+ // load the panel
+ nsCocoaUtils::PrepareForNativeAppModalDialog();
+ [thePanel setNameFieldStringValue:defaultFilename];
+ int result = [thePanel runModal];
+ nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
+ if (result == NSFileHandlingPanelCancelButton)
+ return retVal;
+
+ // get the save type
+ NSPopUpButton* popupButton = [accessoryView viewWithTag:kSaveTypeControlTag];
+ if (popupButton) {
+ mSelectedTypeIndex = [popupButton indexOfSelectedItem];
+ }
+
+ NSURL* fileURL = [thePanel URL];
+ if (fileURL) {
+ nsCOMPtr<nsIFile> localFile;
+ NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
+ nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
+ if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)fileURL))) {
+ *outFile = localFile;
+ NS_ADDREF(*outFile);
+ // We tell if we are replacing or not by just looking to see if the file exists.
+ // The user could not have hit OK and not meant to replace the file.
+ if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]])
+ retVal = returnReplace;
+ else
+ retVal = returnOK;
+ }
+ }
+
+ return retVal;
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
+}
+
+NSArray *
+nsFilePicker::GetFilterList()
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+ if (!mFilters.Length()) {
+ return nil;
+ }
+
+ if (mFilters.Length() <= (uint32_t)mSelectedTypeIndex) {
+ NS_WARNING("An out of range index has been selected. Using the first index instead.");
+ mSelectedTypeIndex = 0;
+ }
+
+ const nsString& filterWide = mFilters[mSelectedTypeIndex];
+ if (!filterWide.Length()) {
+ return nil;
+ }
+
+ if (filterWide.Equals(NS_LITERAL_STRING("*"))) {
+ return nil;
+ }
+
+ // The extensions in filterWide are in the format "*.ext" but are expected
+ // in the format "ext" by NSOpenPanel. So we need to filter some characters.
+ NSMutableString* filterString = [[[NSMutableString alloc] initWithString:
+ [NSString stringWithCharacters:reinterpret_cast<const unichar*>(filterWide.get())
+ length:filterWide.Length()]] autorelease];
+ NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@". *"];
+ NSRange range = [filterString rangeOfCharacterFromSet:set];
+ while (range.length) {
+ [filterString replaceCharactersInRange:range withString:@""];
+ range = [filterString rangeOfCharacterFromSet:set];
+ }
+
+ return [[[NSArray alloc] initWithArray:
+ [filterString componentsSeparatedByString:@";"]] autorelease];
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+// Sets the dialog title to whatever it should be. If it fails, eh,
+// the OS will provide a sensible default.
+void
+nsFilePicker::SetDialogTitle(const nsString& inTitle, id aPanel)
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+ [aPanel setTitle:[NSString stringWithCharacters:(const unichar*)inTitle.get() length:inTitle.Length()]];
+
+ if (!mOkButtonLabel.IsEmpty()) {
+ [aPanel setPrompt:[NSString stringWithCharacters:(const unichar*)mOkButtonLabel.get() length:mOkButtonLabel.Length()]];
+ }
+
+ NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+// Converts path from an nsIFile into a NSString path
+// If it fails, returns an empty string.
+NSString *
+nsFilePicker::PanelDefaultDirectory()
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
+
+ NSString *directory = nil;
+ if (mDisplayDirectory) {
+ nsAutoString pathStr;
+ mDisplayDirectory->GetPath(pathStr);
+ directory = [[[NSString alloc] initWithCharacters:reinterpret_cast<const unichar*>(pathStr.get())
+ length:pathStr.Length()] autorelease];
+ }
+ return directory;
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
+}
+
+NS_IMETHODIMP nsFilePicker::GetFile(nsIFile **aFile)
+{
+ NS_ENSURE_ARG_POINTER(aFile);
+ *aFile = nullptr;
+
+ // just return the first file
+ if (mFiles.Count() > 0) {
+ *aFile = mFiles.ObjectAt(0);
+ NS_IF_ADDREF(*aFile);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsFilePicker::GetFileURL(nsIURI **aFileURL)
+{
+ NS_ENSURE_ARG_POINTER(aFileURL);
+ *aFileURL = nullptr;
+
+ if (mFiles.Count() == 0)
+ return NS_OK;
+
+ return NS_NewFileURI(aFileURL, mFiles.ObjectAt(0));
+}
+
+NS_IMETHODIMP nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
+{
+ return NS_NewArrayEnumerator(aFiles, mFiles);
+}
+
+NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString& aString)
+{
+ mDefault = aString;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString& aString)
+{
+ return NS_ERROR_FAILURE;
+}
+
+// The default extension to use for files
+NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension)
+{
+ aExtension.Truncate();
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString& aExtension)
+{
+ return NS_OK;
+}
+
+// Append an entry to the filters array
+NS_IMETHODIMP
+nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
+{
+ // "..apps" has to be translated with native executable extensions.
+ if (aFilter.EqualsLiteral("..apps")) {
+ mFilters.AppendElement(NS_LITERAL_STRING("*.app"));
+ } else {
+ mFilters.AppendElement(aFilter);
+ }
+ mTitles.AppendElement(aTitle);
+
+ return NS_OK;
+}
+
+// Get the filter index - do we still need this?
+NS_IMETHODIMP nsFilePicker::GetFilterIndex(int32_t *aFilterIndex)
+{
+ *aFilterIndex = mSelectedTypeIndex;
+ return NS_OK;
+}
+
+// Set the filter index - do we still need this?
+NS_IMETHODIMP nsFilePicker::SetFilterIndex(int32_t aFilterIndex)
+{
+ mSelectedTypeIndex = aFilterIndex;
+ return NS_OK;
+}