2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla browser.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1999 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Stuart Parmenter <pavlov@netscape.com>
|
|
|
|
* Steve Dagley <sdagley@netscape.com>
|
|
|
|
* David Haas <haasd@cae.wisc.edu>
|
|
|
|
* Simon Fraser <sfraser@netscape.com>
|
|
|
|
* Josh Aas <josh@mozilla.com>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#import <Cocoa/Cocoa.h>
|
|
|
|
|
2008-02-28 21:36:35 -08:00
|
|
|
#include "nsFilePicker.h"
|
2008-02-19 12:58:01 -08:00
|
|
|
#include "nsObjCExceptions.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsReadableUtils.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsIComponentManager.h"
|
|
|
|
#include "nsILocalFile.h"
|
|
|
|
#include "nsILocalFileMac.h"
|
|
|
|
#include "nsIURL.h"
|
|
|
|
#include "nsArrayEnumerator.h"
|
|
|
|
#include "nsIStringBundle.h"
|
2008-03-26 20:42:57 -07:00
|
|
|
#include "nsCocoaUtils.h"
|
2011-04-21 10:39:12 -07:00
|
|
|
#include "nsToolkit.h"
|
2011-05-27 01:15:20 -07:00
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
|
|
|
|
using namespace mozilla;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
const float kAccessoryViewPadding = 5;
|
|
|
|
const int kSaveTypeControlTag = 1;
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool gCallSecretHiddenFileAPI = false;
|
2009-05-02 11:12:27 -07:00
|
|
|
const char kShowHiddenFilesPref[] = "filepicker.showHiddenFiles";
|
|
|
|
|
2011-04-21 10:39:12 -07:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_ISUPPORTS1(nsFilePicker, nsIFilePicker)
|
|
|
|
|
2009-05-02 11:12:27 -07:00
|
|
|
// 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;
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool show = false;
|
2011-05-27 01:15:20 -07:00
|
|
|
if (NS_SUCCEEDED(Preferences::GetBool(kShowHiddenFilesPref, &show))) {
|
2011-09-30 17:20:33 -07:00
|
|
|
gCallSecretHiddenFileAPI = true;
|
2009-05-02 11:12:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2008-02-28 21:36:35 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsFilePicker::nsFilePicker()
|
2008-02-28 21:36:35 -08:00
|
|
|
: mMode(0)
|
|
|
|
, mSelectedTypeIndex(0)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsFilePicker::~nsFilePicker()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsFilePicker::InitNative(nsIWidget *aParent, const nsAString& aTitle,
|
|
|
|
PRInt16 aMode)
|
|
|
|
{
|
|
|
|
mTitle = aTitle;
|
|
|
|
mMode = aMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSView* nsFilePicker::GetAccessoryView()
|
|
|
|
{
|
2008-02-19 12:58:01 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NSView* accessoryView = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)] autorelease];
|
|
|
|
|
2011-04-21 10:39:12 -07:00
|
|
|
// Set a label's default value.
|
|
|
|
NSString* label = @"Format:";
|
|
|
|
|
|
|
|
// Try to get the localized string.
|
2007-03-22 10:30:00 -07:00
|
|
|
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)) {
|
2011-04-21 10:39:12 -07:00
|
|
|
nsXPIDLString locaLabel;
|
|
|
|
bundle->GetStringFromName(NS_LITERAL_STRING("formatLabel").get(),
|
|
|
|
getter_Copies(locaLabel));
|
|
|
|
if (locaLabel) {
|
|
|
|
label = [NSString stringWithCharacters:locaLabel.get() length:locaLabel.Length()];
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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]];
|
2011-04-21 10:39:12 -07:00
|
|
|
[textField setStringValue:label];
|
2007-03-22 10:30:00 -07:00
|
|
|
[textField setTag:0];
|
|
|
|
[textField sizeToFit];
|
|
|
|
|
|
|
|
// set up popup button
|
|
|
|
NSPopUpButton* popupButton = [[[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 0, 0) pullsDown:NO] autorelease];
|
2009-02-10 12:39:43 -08:00
|
|
|
PRUint32 numMenuItems = mTitles.Length();
|
|
|
|
for (PRUint32 i = 0; i < numMenuItems; i++) {
|
2009-01-18 12:14:14 -08:00
|
|
|
const nsString& currentTitle = mTitles[i];
|
2008-02-12 19:38:06 -08:00
|
|
|
NSString *titleString;
|
|
|
|
if (currentTitle.IsEmpty()) {
|
2009-01-18 12:14:14 -08:00
|
|
|
const nsString& currentFilter = mFilters[i];
|
2008-02-12 19:38:06 -08:00
|
|
|
titleString = [[NSString alloc] initWithCharacters:currentFilter.get()
|
|
|
|
length:currentFilter.Length()];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
titleString = [[NSString alloc] initWithCharacters:currentTitle.get()
|
|
|
|
length:currentTitle.Length()];
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
[popupButton addItemWithTitle:titleString];
|
|
|
|
[titleString release];
|
|
|
|
}
|
2009-06-27 18:42:50 -07:00
|
|
|
if (mSelectedTypeIndex >= 0 && (PRUint32)mSelectedTypeIndex < numMenuItems)
|
2008-02-28 21:36:35 -08:00
|
|
|
[popupButton selectItemAtIndex:mSelectedTypeIndex];
|
2007-03-22 10:30:00 -07:00
|
|
|
[popupButton setTag:kSaveTypeControlTag];
|
2008-02-12 19:38:06 -08:00
|
|
|
[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)];
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// 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;
|
2008-02-19 12:58:01 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-02-28 21:36:35 -08:00
|
|
|
// Display the file dialog
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP nsFilePicker::Show(PRInt16 *retval)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(retval);
|
|
|
|
|
|
|
|
*retval = returnCancel;
|
|
|
|
|
|
|
|
PRInt16 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<nsILocalFile> theFile;
|
|
|
|
|
|
|
|
switch (mMode)
|
|
|
|
{
|
|
|
|
case modeOpen:
|
2011-09-30 17:20:33 -07:00
|
|
|
userClicksOK = GetLocalFiles(mTitle, false, mFiles);
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case modeOpenMultiple:
|
2011-09-30 17:20:33 -07:00
|
|
|
userClicksOK = GetLocalFiles(mTitle, true, mFiles);
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case modeSave:
|
|
|
|
userClicksOK = PutLocalFile(mTitle, mDefault, getter_AddRefs(theFile));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case modeGetFolder:
|
|
|
|
userClicksOK = GetLocalFolder(mTitle, getter_AddRefs(theFile));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-08-14 07:09:00 -07:00
|
|
|
NS_ERROR("Unknown file picker mode");
|
2007-03-22 10:30:00 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (theFile)
|
|
|
|
mFiles.AppendObject(theFile);
|
|
|
|
|
|
|
|
*retval = userClicksOK;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-05-11 05:46:59 -07:00
|
|
|
static
|
|
|
|
void UpdatePanelFileTypes(NSOpenPanel* aPanel, NSArray* aFilters)
|
|
|
|
{
|
|
|
|
// If we show all file types, also "expose" bundles' contents.
|
2011-05-11 09:00:04 -07:00
|
|
|
[aPanel setTreatsFilePackagesAsDirectories:!aFilters];
|
2011-05-11 05:46:59 -07:00
|
|
|
|
|
|
|
[aPanel setAllowedFileTypes:aFilters];
|
|
|
|
}
|
|
|
|
|
2011-04-21 10:39:12 -07:00
|
|
|
@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;
|
|
|
|
PRInt32 selectedItem = [mPopUpButton indexOfSelectedItem];
|
|
|
|
if (selectedItem < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mFilePicker->SetFilterIndex(selectedItem);
|
2011-05-11 05:46:59 -07:00
|
|
|
UpdatePanelFileTypes(mOpenPanel, mFilePicker->GetFilterList());
|
2011-04-21 10:39:12 -07:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN();
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Use OpenPanel to do a GetFile. Returns |returnOK| if the user presses OK in the dialog.
|
|
|
|
PRInt16
|
2011-09-28 23:19:26 -07:00
|
|
|
nsFilePicker::GetLocalFiles(const nsString& inTitle, bool inAllowMultiple, nsCOMArray<nsILocalFile>& outFiles)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-19 12:58:01 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt16 retVal = (PRInt16)returnCancel;
|
|
|
|
NSOpenPanel *thePanel = [NSOpenPanel openPanel];
|
|
|
|
|
2009-05-02 11:12:27 -07:00
|
|
|
SetShowHiddenFileState(thePanel);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// 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
|
|
|
|
|
2011-05-11 05:46:59 -07:00
|
|
|
// Get filters
|
|
|
|
// filters may be null, if we should allow all file types.
|
|
|
|
NSArray *filters = GetFilterList();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// 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 && filters && [filters count] == 1 &&
|
|
|
|
[(NSString *)[filters objectAtIndex:0] isEqualToString:@"app"]) {
|
|
|
|
theDir = @"/Applications/";
|
|
|
|
}
|
2008-03-26 20:42:57 -07:00
|
|
|
|
2011-04-21 10:39:12 -07:00
|
|
|
// On 10.6+, we let users change the filters. Unfortunately, some methods
|
|
|
|
// are not available on 10.5 and without using them it happens to be buggy.
|
|
|
|
int result;
|
2008-03-26 20:42:57 -07:00
|
|
|
nsCocoaUtils::PrepareForNativeAppModalDialog();
|
2011-05-09 07:47:51 -07:00
|
|
|
if (mFilters.Length() > 1 && nsToolkit::OnSnowLeopardOrLater()) {
|
2011-04-29 05:21:43 -07:00
|
|
|
// [NSURL initWithString:] (below) throws an exception if URLString is nil.
|
|
|
|
if (!theDir) {
|
|
|
|
theDir = @"";
|
|
|
|
}
|
|
|
|
|
2011-04-21 10:39:12 -07:00
|
|
|
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];
|
|
|
|
|
|
|
|
[thePanel setDirectoryURL:[[NSURL alloc] initWithString:theDir]];
|
2011-05-11 05:46:59 -07:00
|
|
|
UpdatePanelFileTypes(thePanel, filters);
|
2011-04-21 10:39:12 -07:00
|
|
|
result = [thePanel runModal];
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:observer];
|
|
|
|
[observer release];
|
|
|
|
} else {
|
2011-05-11 05:46:59 -07:00
|
|
|
// If we show all file types, also "expose" bundles' contents.
|
|
|
|
if (!filters) {
|
2011-05-11 09:00:04 -07:00
|
|
|
[thePanel setTreatsFilePackagesAsDirectories:YES];
|
2011-05-11 05:46:59 -07:00
|
|
|
}
|
2011-04-21 10:39:12 -07:00
|
|
|
result = [thePanel runModalForDirectory:theDir file:nil types:filters];
|
|
|
|
}
|
2008-03-26 20:42:57 -07:00
|
|
|
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (result == NSFileHandlingPanelCancelButton)
|
|
|
|
return retVal;
|
2011-06-02 15:36:11 -07:00
|
|
|
|
|
|
|
// 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.
|
2011-06-09 02:28:16 -07:00
|
|
|
// We are using Fast Enumeration, thus the NSURL array is created once then
|
|
|
|
// iterated.
|
|
|
|
for (NSURL* url in [thePanel URLs]) {
|
2011-06-02 15:36:11 -07:00
|
|
|
if (!url) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsILocalFile> localFile;
|
2011-09-30 17:20:33 -07:00
|
|
|
NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
|
2011-06-02 15:36:11 -07:00
|
|
|
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
|
|
|
|
if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)url))) {
|
|
|
|
outFiles.AppendObject(localFile);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (outFiles.Count() > 0)
|
|
|
|
retVal = returnOK;
|
|
|
|
|
|
|
|
return retVal;
|
2008-02-19 12:58:01 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
|
2008-02-28 21:36:35 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Use OpenPanel to do a GetFolder. Returns |returnOK| if the user presses OK in the dialog.
|
|
|
|
PRInt16
|
|
|
|
nsFilePicker::GetLocalFolder(const nsString& inTitle, nsILocalFile** outFile)
|
|
|
|
{
|
2008-02-19 12:58:01 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
2010-07-07 02:48:17 -07:00
|
|
|
NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
PRInt16 retVal = (PRInt16)returnCancel;
|
|
|
|
NSOpenPanel *thePanel = [NSOpenPanel openPanel];
|
|
|
|
|
2009-05-02 11:12:27 -07:00
|
|
|
SetShowHiddenFileState(thePanel);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// 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();
|
2008-03-26 20:42:57 -07:00
|
|
|
nsCocoaUtils::PrepareForNativeAppModalDialog();
|
2007-03-22 10:30:00 -07:00
|
|
|
int result = [thePanel runModalForDirectory:theDir file:nil types:nil];
|
2008-03-26 20:42:57 -07:00
|
|
|
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
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<nsILocalFile> localFile;
|
2011-09-30 17:20:33 -07:00
|
|
|
NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(localFile);
|
|
|
|
if (macLocalFile && NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)theURL))) {
|
|
|
|
*outFile = localFile;
|
|
|
|
NS_ADDREF(*outFile);
|
|
|
|
retVal = returnOK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retVal;
|
2008-02-19 12:58:01 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
|
2008-02-28 21:36:35 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-02-28 21:36:35 -08:00
|
|
|
// Returns |returnOK| if the user presses OK in the dialog.
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt16
|
|
|
|
nsFilePicker::PutLocalFile(const nsString& inTitle, const nsString& inDefaultName, nsILocalFile** outFile)
|
|
|
|
{
|
2008-02-19 12:58:01 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
2010-07-07 02:48:17 -07:00
|
|
|
NS_ASSERTION(outFile, "this protected member function expects a null initialized out pointer");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
PRInt16 retVal = returnCancel;
|
|
|
|
NSSavePanel *thePanel = [NSSavePanel savePanel];
|
|
|
|
|
2009-05-02 11:12:27 -07:00
|
|
|
SetShowHiddenFileState(thePanel);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
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 default directory
|
|
|
|
NSString *theDir = PanelDefaultDirectory();
|
|
|
|
|
|
|
|
// load the panel
|
2008-03-26 20:42:57 -07:00
|
|
|
nsCocoaUtils::PrepareForNativeAppModalDialog();
|
|
|
|
int result = [thePanel runModalForDirectory:theDir file:defaultFilename];
|
|
|
|
nsCocoaUtils::CleanUpAfterNativeAppModalDialog();
|
|
|
|
if (result == NSFileHandlingPanelCancelButton)
|
2007-03-22 10:30:00 -07:00
|
|
|
return retVal;
|
|
|
|
|
|
|
|
// get the save type
|
|
|
|
NSPopUpButton* popupButton = [accessoryView viewWithTag:kSaveTypeControlTag];
|
2008-02-28 21:36:35 -08:00
|
|
|
if (popupButton) {
|
|
|
|
mSelectedTypeIndex = [popupButton indexOfSelectedItem];
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NSURL* fileURL = [thePanel URL];
|
|
|
|
if (fileURL) {
|
|
|
|
nsCOMPtr<nsILocalFile> localFile;
|
2011-09-30 17:20:33 -07:00
|
|
|
NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localFile));
|
2007-03-22 10:30:00 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-19 12:58:01 -08:00
|
|
|
return retVal;
|
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NSArray *
|
2011-04-21 10:39:12 -07:00
|
|
|
nsFilePicker::GetFilterList()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-02-19 12:58:01 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2011-06-14 07:14:56 -07:00
|
|
|
if (!mFilters.Length()) {
|
2011-04-01 07:30:00 -07:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2011-06-14 07:14:56 -07:00
|
|
|
if (mFilters.Length() <= (PRUint32)mSelectedTypeIndex) {
|
|
|
|
NS_WARNING("An out of range index has been selected. Using the first index instead.");
|
|
|
|
mSelectedTypeIndex = 0;
|
|
|
|
}
|
|
|
|
|
2011-04-01 07:30:00 -07:00
|
|
|
const nsString& filterWide = mFilters[mSelectedTypeIndex];
|
|
|
|
if (!filterWide.Length()) {
|
|
|
|
return nil;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-04-01 07:30:00 -07:00
|
|
|
|
|
|
|
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:filterWide.get()
|
|
|
|
length:filterWide.Length()]] autorelease];
|
|
|
|
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:
|
|
|
|
[NSString stringWithString:@". *"]];
|
|
|
|
NSRange range = [filterString rangeOfCharacterFromSet:set];
|
|
|
|
while (range.length) {
|
|
|
|
[filterString replaceCharactersInRange:range withString:@""];
|
|
|
|
range = [filterString rangeOfCharacterFromSet:set];
|
|
|
|
}
|
|
|
|
|
|
|
|
return [[[NSArray alloc] initWithArray:
|
|
|
|
[filterString componentsSeparatedByString:@";"]] autorelease];
|
2008-02-19 12:58:01 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2008-02-28 21:36:35 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// 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)
|
|
|
|
{
|
2008-02-19 12:58:01 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
[aPanel setTitle:[NSString stringWithCharacters:(const unichar*)inTitle.get() length:inTitle.Length()]];
|
2008-02-19 12:58:01 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Converts path from an nsILocalFile into a NSString path
|
|
|
|
// If it fails, returns an empty string.
|
|
|
|
NSString *
|
|
|
|
nsFilePicker::PanelDefaultDirectory()
|
|
|
|
{
|
2008-02-19 12:58:01 -08:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NSString *directory = nil;
|
|
|
|
if (mDisplayDirectory) {
|
|
|
|
nsAutoString pathStr;
|
|
|
|
mDisplayDirectory->GetPath(pathStr);
|
|
|
|
directory = [[[NSString alloc] initWithCharacters:pathStr.get() length:pathStr.Length()] autorelease];
|
|
|
|
}
|
|
|
|
return directory;
|
2008-02-19 12:58:01 -08:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsFilePicker::GetFile(nsILocalFile **aFile)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aFile);
|
|
|
|
*aFile = nsnull;
|
|
|
|
|
|
|
|
// just return the first file
|
2008-02-28 21:36:35 -08:00
|
|
|
if (mFiles.Count() > 0) {
|
2007-03-22 10:30:00 -07:00
|
|
|
*aFile = mFiles.ObjectAt(0);
|
|
|
|
NS_IF_ADDREF(*aFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-02-26 08:12:17 -08:00
|
|
|
NS_IMETHODIMP nsFilePicker::GetFileURL(nsIURI **aFileURL)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aFileURL);
|
|
|
|
*aFileURL = nsnull;
|
|
|
|
|
|
|
|
if (mFiles.Count() == 0)
|
|
|
|
return NS_OK;
|
|
|
|
|
2008-02-26 08:12:17 -08:00
|
|
|
return NS_NewFileURI(aFileURL, mFiles.ObjectAt(0));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2011-04-01 07:30:00 -07:00
|
|
|
// "..apps" has to be translated with native executable extensions.
|
|
|
|
if (aFilter.EqualsLiteral("..apps")) {
|
|
|
|
mFilters.AppendElement(NS_LITERAL_STRING("*.app"));
|
|
|
|
} else {
|
|
|
|
mFilters.AppendElement(aFilter);
|
|
|
|
}
|
2009-01-18 12:14:14 -08:00
|
|
|
mTitles.AppendElement(aTitle);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the filter index - do we still need this?
|
|
|
|
NS_IMETHODIMP nsFilePicker::GetFilterIndex(PRInt32 *aFilterIndex)
|
|
|
|
{
|
2008-02-28 21:36:35 -08:00
|
|
|
*aFilterIndex = mSelectedTypeIndex;
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the filter index - do we still need this?
|
|
|
|
NS_IMETHODIMP nsFilePicker::SetFilterIndex(PRInt32 aFilterIndex)
|
|
|
|
{
|
2008-02-28 21:36:35 -08:00
|
|
|
mSelectedTypeIndex = aFilterIndex;
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|