Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / widget / cocoa / nsFilePicker.mm
blob1214992fd7efc8b4a5411e77390785ed65f12157
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
38   NSPopUpButton* mPopUpButton;
39   NSOpenPanel*   mOpenPanel;
40   nsFilePicker*  mFilePicker;
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)
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;
94 nsFilePicker::nsFilePicker()
95 : mSelectedTypeIndex(0)
99 nsFilePicker::~nsFilePicker()
103 void
104 nsFilePicker::InitNative(nsIWidget *aParent, const nsAString& aTitle)
106   mTitle = aTitle;
109 NSView* nsFilePicker::GetAccessoryView()
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)];
181   
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;
193 // Display the file dialog
194 NS_IMETHODIMP nsFilePicker::Show(int16_t *retval)
196   NS_ENSURE_ARG_POINTER(retval);
198   *retval = returnCancel;
200   int16_t userClicksOK = returnCancel;
202 // Random questions from DHH:
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.
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;
220     
221     case modeOpenMultiple:
222       userClicksOK = GetLocalFiles(mTitle, true, mFiles);
223       break;
224       
225     case modeSave:
226       userClicksOK = PutLocalFile(mTitle, mDefault, getter_AddRefs(theFile));
227       break;
228       
229     case modeGetFolder:
230       userClicksOK = GetLocalFolder(mTitle, getter_AddRefs(theFile));
231       break;
232     
233     default:
234       NS_ERROR("Unknown file picker mode");
235       break;
236   }
238   if (theFile)
239     mFiles.AppendObject(theFile);
240   
241   *retval = userClicksOK;
242   return NS_OK;
245 static
246 void UpdatePanelFileTypes(NSOpenPanel* aPanel, NSArray* aFilters)
248   // If we show all file types, also "expose" bundles' contents.
249   [aPanel setTreatsFilePackagesAsDirectories:!aFilters];
251   [aPanel setAllowedFileTypes:aFilters];
254 @implementation NSPopUpButtonObserver
255 - (void) setPopUpButton:(NSPopUpButton*)aPopUpButton
257   mPopUpButton = aPopUpButton;
260 - (void) setOpenPanel:(NSOpenPanel*)aOpenPanel
262   mOpenPanel = aOpenPanel;
265 - (void) setFilePicker:(nsFilePicker*)aFilePicker
267   mFilePicker = aFilePicker;
270 - (void) menuChangedItem:(NSNotification *)aSender
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();
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)
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
303   
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();
310   
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();
358   
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);
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)
392   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
393   NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer");
394   
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];
408   
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);
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)
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);
505 NSArray *
506 nsFilePicker::GetFilterList()
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;
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)
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;
558 // Converts path from an nsIFile into a NSString path
559 // If it fails, returns an empty string.
560 NSString *
561 nsFilePicker::PanelDefaultDirectory()
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;
577 NS_IMETHODIMP nsFilePicker::GetFile(nsIFile **aFile)
579   NS_ENSURE_ARG_POINTER(aFile);
580   *aFile = nullptr;
581   
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;
591 NS_IMETHODIMP nsFilePicker::GetFileURL(nsIURI **aFileURL)
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));
602 NS_IMETHODIMP nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
604   return NS_NewArrayEnumerator(aFiles, mFiles);
607 NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString& aString)
609   mDefault = aString;
610   return NS_OK;
613 NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString& aString)
615   return NS_ERROR_FAILURE;
618 // The default extension to use for files
619 NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension)
621   aExtension.Truncate();
622   return NS_OK;
625 NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString& aExtension)
627   return NS_OK;
630 // Append an entry to the filters array
631 NS_IMETHODIMP
632 nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
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);
641   
642   return NS_OK;
645 // Get the filter index - do we still need this?
646 NS_IMETHODIMP nsFilePicker::GetFilterIndex(int32_t *aFilterIndex)
648   *aFilterIndex = mSelectedTypeIndex;
649   return NS_OK;
652 // Set the filter index - do we still need this?
653 NS_IMETHODIMP nsFilePicker::SetFilterIndex(int32_t aFilterIndex)
655   mSelectedTypeIndex = aFilterIndex;
656   return NS_OK;