mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 661991 - Cleanup win widget nsFilePicker. r=neil, a=ehsan
This commit is contained in:
parent
6d31dbe14a
commit
549f766a5a
@ -23,6 +23,7 @@
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <pavlov@netscape.com>
|
||||
* Seth Spitzer <sspitzer@netscape.com>
|
||||
* Jim Mathies <jmathies@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
|
||||
@ -61,13 +62,109 @@
|
||||
#include "nsString.h"
|
||||
#include "nsToolkit.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsFilePicker, nsIFilePicker)
|
||||
|
||||
PRUnichar *nsFilePicker::mLastUsedUnicodeDirectory;
|
||||
char nsFilePicker::mLastUsedDirectory[MAX_PATH+1] = { 0 };
|
||||
|
||||
#define MAX_EXTENSION_LENGTH 10
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Helper classes
|
||||
|
||||
// Manages matching SuppressBlurEvents calls on the parent widget.
|
||||
class AutoSuppressEvents
|
||||
{
|
||||
public:
|
||||
explicit AutoSuppressEvents(nsIWidget* aWidget) :
|
||||
mWindow(static_cast<nsWindow *>(aWidget)) {
|
||||
SuppressWidgetEvents(true);
|
||||
}
|
||||
|
||||
~AutoSuppressEvents() {
|
||||
SuppressWidgetEvents(false);
|
||||
}
|
||||
private:
|
||||
void SuppressWidgetEvents(bool aFlag) {
|
||||
if (mWindow) {
|
||||
mWindow->SuppressBlurEvents(aFlag);
|
||||
}
|
||||
}
|
||||
nsRefPtr<nsWindow> mWindow;
|
||||
};
|
||||
|
||||
// Manages the current working path.
|
||||
class AutoRestoreWorkingPath
|
||||
{
|
||||
public:
|
||||
AutoRestoreWorkingPath() {
|
||||
DWORD bufferLength = GetCurrentDirectoryW(0, NULL);
|
||||
mWorkingPath = new PRUnichar[bufferLength];
|
||||
if (GetCurrentDirectoryW(bufferLength, mWorkingPath) == 0) {
|
||||
mWorkingPath = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
~AutoRestoreWorkingPath() {
|
||||
if (HasWorkingPath()) {
|
||||
::SetCurrentDirectoryW(mWorkingPath);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool HasWorkingPath() const {
|
||||
return mWorkingPath != NULL;
|
||||
}
|
||||
private:
|
||||
nsAutoArrayPtr<PRUnichar> mWorkingPath;
|
||||
};
|
||||
|
||||
// Manages NS_NATIVE_TMP_WINDOW child windows. NS_NATIVE_TMP_WINDOWs are
|
||||
// temporary child windows of mParentWidget created to address RTL issues
|
||||
// in picker dialogs. We are responsible for destroying these.
|
||||
class AutoDestroyTmpWindow
|
||||
{
|
||||
public:
|
||||
explicit AutoDestroyTmpWindow(HWND aTmpWnd) :
|
||||
mWnd(aTmpWnd) {
|
||||
}
|
||||
|
||||
~AutoDestroyTmpWindow() {
|
||||
if (mWnd)
|
||||
DestroyWindow(mWnd);
|
||||
}
|
||||
|
||||
inline HWND get() const { return mWnd; }
|
||||
private:
|
||||
HWND mWnd;
|
||||
};
|
||||
|
||||
// Manages matching PickerOpen/PickerClosed calls on the parent widget.
|
||||
class AutoWidgetPickerState
|
||||
{
|
||||
public:
|
||||
explicit AutoWidgetPickerState(nsIWidget* aWidget) :
|
||||
mWindow(static_cast<nsWindow *>(aWidget)) {
|
||||
PickerState(true);
|
||||
}
|
||||
|
||||
~AutoWidgetPickerState() {
|
||||
PickerState(false);
|
||||
}
|
||||
private:
|
||||
void PickerState(bool aFlag) {
|
||||
if (mWindow) {
|
||||
if (aFlag)
|
||||
mWindow->PickerOpen();
|
||||
else
|
||||
mWindow->PickerClosed();
|
||||
}
|
||||
}
|
||||
nsRefPtr<nsWindow> mWindow;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// nsIFilePicker
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsFilePicker, nsIFilePicker)
|
||||
|
||||
nsFilePicker::nsFilePicker()
|
||||
{
|
||||
mSelectedType = 1;
|
||||
@ -82,7 +179,8 @@ nsFilePicker::~nsFilePicker()
|
||||
}
|
||||
|
||||
// Show - Display the file dialog
|
||||
int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
||||
int CALLBACK
|
||||
BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
||||
{
|
||||
if (uMsg == BFFM_INITIALIZED)
|
||||
{
|
||||
@ -95,7 +193,8 @@ int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpDa
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void EnsureWindowVisible(HWND hwnd)
|
||||
static void
|
||||
EnsureWindowVisible(HWND hwnd)
|
||||
{
|
||||
// Obtain the monitor which has the largest area of intersection
|
||||
// with the window, or NULL if there is no intersection.
|
||||
@ -114,8 +213,8 @@ static void EnsureWindowVisible(HWND hwnd)
|
||||
|
||||
// Callback hook which will ensure that the window is visible. Currently
|
||||
// only in use on os <= XP.
|
||||
static UINT_PTR CALLBACK FilePickerHook(HWND hwnd, UINT msg,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
static UINT_PTR CALLBACK
|
||||
FilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (msg == WM_NOTIFY) {
|
||||
LPOFNOTIFYW lpofn = (LPOFNOTIFYW) lParam;
|
||||
@ -138,8 +237,8 @@ static UINT_PTR CALLBACK FilePickerHook(HWND hwnd, UINT msg,
|
||||
|
||||
// Callback hook which will dynamically allocate a buffer large enough
|
||||
// for the file picker dialog. Currently only in use on os <= XP.
|
||||
static UINT_PTR CALLBACK MultiFilePickerHook(HWND hwnd, UINT msg,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
static UINT_PTR CALLBACK
|
||||
MultiFilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_INITDIALOG:
|
||||
@ -207,16 +306,57 @@ static UINT_PTR CALLBACK MultiFilePickerHook(HWND hwnd, UINT msg,
|
||||
|
||||
return FilePickerHook(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
bool nsFilePicker::GetFileName(OPENFILENAMEW* ofn, PickerType aType)
|
||||
|
||||
bool
|
||||
nsFilePicker::ShowFolderPicker(const nsString& aInitialDir)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(ofn);
|
||||
bool result = false;
|
||||
// This should be safe, we have mParentWidget ref'd
|
||||
nsWindow* win = static_cast<nsWindow*>(mParentWidget.get());
|
||||
if (win) {
|
||||
win->PickerOpen();
|
||||
|
||||
nsAutoArrayPtr<PRUnichar> dirBuffer(new PRUnichar[FILE_BUFFER_SIZE]);
|
||||
wcsncpy(dirBuffer, aInitialDir.get(), FILE_BUFFER_SIZE);
|
||||
dirBuffer[FILE_BUFFER_SIZE-1] = '\0';
|
||||
|
||||
AutoDestroyTmpWindow adtw((HWND)(mParentWidget.get() ?
|
||||
mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : NULL));
|
||||
|
||||
BROWSEINFOW browserInfo = {0};
|
||||
browserInfo.pidlRoot = nsnull;
|
||||
browserInfo.pszDisplayName = (LPWSTR)dirBuffer;
|
||||
browserInfo.lpszTitle = mTitle.get();
|
||||
browserInfo.ulFlags = BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
|
||||
browserInfo.hwndOwner = adtw.get();
|
||||
browserInfo.iImage = nsnull;
|
||||
|
||||
if (!aInitialDir.IsEmpty()) {
|
||||
// the dialog is modal so that |initialDir.get()| will be valid in
|
||||
// BrowserCallbackProc. Thus, we don't need to clone it.
|
||||
browserInfo.lParam = (LPARAM) aInitialDir.get();
|
||||
browserInfo.lpfn = &BrowseCallbackProc;
|
||||
} else {
|
||||
browserInfo.lParam = nsnull;
|
||||
browserInfo.lpfn = nsnull;
|
||||
}
|
||||
|
||||
LPITEMIDLIST list = ::SHBrowseForFolderW(&browserInfo);
|
||||
if (list) {
|
||||
result = ::SHGetPathFromIDListW(list, (LPWSTR)dirBuffer);
|
||||
if (result)
|
||||
mUnicodeFile.Assign(dirBuffer);
|
||||
// free PIDL
|
||||
CoTaskMemFree(list);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
nsFilePicker::FilePickerWrapper(OPENFILENAMEW* ofn, PickerType aType)
|
||||
{
|
||||
if (!ofn)
|
||||
return false;
|
||||
|
||||
bool result = false;
|
||||
AutoWidgetPickerState awps(mParentWidget);
|
||||
MOZ_SEH_TRY {
|
||||
if (aType == PICKER_TYPE_OPEN)
|
||||
result = ::GetOpenFileNameW(ofn);
|
||||
@ -225,167 +365,90 @@ bool nsFilePicker::GetFileName(OPENFILENAMEW* ofn, PickerType aType)
|
||||
} MOZ_SEH_EXCEPT(true) {
|
||||
NS_ERROR("nsFilePicker GetFileName win32 call generated an exception! This is bad!");
|
||||
}
|
||||
if (win) {
|
||||
win->PickerClosed();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::ShowW(PRInt16 *aReturnVal)
|
||||
bool
|
||||
nsFilePicker::ShowFilePicker(const nsString& aInitialDir)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aReturnVal);
|
||||
OPENFILENAMEW ofn = {0};
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
nsString filterBuffer = mFilterList;
|
||||
|
||||
nsAutoArrayPtr<PRUnichar> fileBuffer(new PRUnichar[FILE_BUFFER_SIZE]);
|
||||
wcsncpy(fileBuffer, mDefault.get(), FILE_BUFFER_SIZE);
|
||||
fileBuffer[FILE_BUFFER_SIZE-1] = '\0'; // null terminate in case copy truncated
|
||||
|
||||
// suppress blur events
|
||||
if (mParentWidget) {
|
||||
nsIWidget *tmp = mParentWidget;
|
||||
nsWindow *parent = static_cast<nsWindow *>(tmp);
|
||||
parent->SuppressBlurEvents(true);
|
||||
if (!aInitialDir.IsEmpty()) {
|
||||
ofn.lpstrInitialDir = aInitialDir.get();
|
||||
}
|
||||
|
||||
AutoDestroyTmpWindow adtw((HWND) (mParentWidget.get() ?
|
||||
mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : NULL));
|
||||
|
||||
ofn.lpstrTitle = (LPCWSTR)mTitle.get();
|
||||
ofn.lpstrFilter = (LPCWSTR)filterBuffer.get();
|
||||
ofn.nFilterIndex = mSelectedType;
|
||||
ofn.lpstrFile = fileBuffer;
|
||||
ofn.nMaxFile = FILE_BUFFER_SIZE;
|
||||
ofn.hwndOwner = adtw.get();
|
||||
ofn.Flags = OFN_SHAREAWARE | OFN_LONGNAMES | OFN_OVERWRITEPROMPT |
|
||||
OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_ENABLESIZING |
|
||||
OFN_EXPLORER;
|
||||
|
||||
// Windows Vista and up won't allow you to use the new looking dialogs with
|
||||
// a hook procedure. The hook procedure fixes a problem on XP dialogs for
|
||||
// file picker visibility. Vista and up automatically ensures the file
|
||||
// picker is always visible.
|
||||
if (nsWindow::GetWindowsVersion() < VISTA_VERSION) {
|
||||
ofn.lpfnHook = FilePickerHook;
|
||||
ofn.Flags |= OFN_ENABLEHOOK;
|
||||
}
|
||||
|
||||
// Handle add to recent docs settings
|
||||
if (IsPrivacyModeEnabled() || !mAddToRecentDocs) {
|
||||
ofn.Flags |= OFN_DONTADDTORECENT;
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_STRING(htmExt, "html");
|
||||
|
||||
if (!mDefaultExtension.IsEmpty()) {
|
||||
ofn.lpstrDefExt = mDefaultExtension.get();
|
||||
} else {
|
||||
// Get file extension from suggested filename to detect if we are
|
||||
// saving an html file.
|
||||
if (IsDefaultPathHtml()) {
|
||||
// This is supposed to append ".htm" if user doesn't supply an
|
||||
// extension but the behavior is sort of weird:
|
||||
// - Often appends ".html" even if you have an extension
|
||||
// - It obeys your extension if you put quotes around name
|
||||
ofn.lpstrDefExt = htmExt.get();
|
||||
}
|
||||
}
|
||||
|
||||
// When possible, instead of using OFN_NOCHANGEDIR to ensure the current
|
||||
// working directory will not change from this call, we will retrieve the
|
||||
// current working directory before the call and restore it after the
|
||||
// call. This flag causes problems on Windows XP for paths that are
|
||||
// selected like C:test.txt where the user is currently at C:\somepath
|
||||
// In which case expected result should be C:\somepath\test.txt
|
||||
AutoRestoreWorkingPath restoreWorkingPath;
|
||||
// If we can't get the current working directory, the best case is to
|
||||
// use the OFN_NOCHANGEDIR flag
|
||||
if (!restoreWorkingPath.HasWorkingPath()) {
|
||||
ofn.Flags |= OFN_NOCHANGEDIR;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
nsAutoArrayPtr<PRUnichar> fileBuffer(new PRUnichar[FILE_BUFFER_SIZE+1]);
|
||||
|
||||
wcsncpy(fileBuffer, mDefault.get(), FILE_BUFFER_SIZE);
|
||||
fileBuffer[FILE_BUFFER_SIZE] = '\0'; // null terminate in case copy truncated
|
||||
|
||||
NS_NAMED_LITERAL_STRING(htmExt, "html");
|
||||
nsAutoString initialDir;
|
||||
if (mDisplayDirectory)
|
||||
mDisplayDirectory->GetPath(initialDir);
|
||||
|
||||
// If no display directory, re-use the last one.
|
||||
if(initialDir.IsEmpty()) {
|
||||
// Allocate copy of last used dir.
|
||||
initialDir = mLastUsedUnicodeDirectory;
|
||||
}
|
||||
|
||||
mUnicodeFile.Truncate();
|
||||
|
||||
if (mMode == modeGetFolder) {
|
||||
PRUnichar dirBuffer[MAX_PATH+1];
|
||||
wcsncpy(dirBuffer, initialDir.get(), MAX_PATH);
|
||||
|
||||
BROWSEINFOW browserInfo;
|
||||
browserInfo.hwndOwner = (HWND)
|
||||
(mParentWidget.get() ? mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : 0);
|
||||
browserInfo.pidlRoot = nsnull;
|
||||
browserInfo.pszDisplayName = (LPWSTR)dirBuffer;
|
||||
browserInfo.lpszTitle = mTitle.get();
|
||||
browserInfo.ulFlags = BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
|
||||
if (initialDir.Length()) {
|
||||
// the dialog is modal so that |initialDir.get()| will be valid in
|
||||
// BrowserCallbackProc. Thus, we don't need to clone it.
|
||||
browserInfo.lParam = (LPARAM) initialDir.get();
|
||||
browserInfo.lpfn = &BrowseCallbackProc;
|
||||
} else {
|
||||
browserInfo.lParam = nsnull;
|
||||
browserInfo.lpfn = nsnull;
|
||||
}
|
||||
browserInfo.iImage = nsnull;
|
||||
|
||||
LPITEMIDLIST list = ::SHBrowseForFolderW(&browserInfo);
|
||||
if (list != NULL) {
|
||||
result = ::SHGetPathFromIDListW(list, (LPWSTR)fileBuffer);
|
||||
if (result) {
|
||||
mUnicodeFile.Assign(fileBuffer);
|
||||
}
|
||||
|
||||
// free PIDL
|
||||
CoTaskMemFree(list);
|
||||
}
|
||||
} else {
|
||||
|
||||
OPENFILENAMEW ofn;
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
nsString filterBuffer = mFilterList;
|
||||
|
||||
if (!initialDir.IsEmpty()) {
|
||||
// The initial directory
|
||||
ofn.lpstrInitialDir = initialDir.get();
|
||||
}
|
||||
|
||||
// A string to be placed in the title bar of the dialog box
|
||||
ofn.lpstrTitle = (LPCWSTR)mTitle.get();
|
||||
// A buffer containing pairs of null-terminated filter strings
|
||||
ofn.lpstrFilter = (LPCWSTR)filterBuffer.get();
|
||||
// The index of the currently selected filter in the File Types control
|
||||
ofn.nFilterIndex = mSelectedType;
|
||||
// The file name used to initialize the File Name edit control
|
||||
ofn.lpstrFile = fileBuffer;
|
||||
// The max length of lpstrFile
|
||||
ofn.nMaxFile = FILE_BUFFER_SIZE;
|
||||
ofn.hwndOwner = (HWND) (mParentWidget.get() ?
|
||||
mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : 0);
|
||||
ofn.Flags = OFN_SHAREAWARE | OFN_LONGNAMES | OFN_OVERWRITEPROMPT |
|
||||
OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_ENABLESIZING |
|
||||
OFN_EXPLORER;
|
||||
|
||||
// Windows Vista and up won't allow you to use the new looking dialogs with
|
||||
// a hook procedure. The hook procedure fixes a problem on XP dialogs for
|
||||
// file picker visibility. Vista and up automatically ensures the file
|
||||
// picker is always visible.
|
||||
if (nsWindow::GetWindowsVersion() < VISTA_VERSION) {
|
||||
ofn.lpfnHook = FilePickerHook;
|
||||
ofn.Flags |= OFN_ENABLEHOOK;
|
||||
}
|
||||
|
||||
// Handle add to recent docs settings
|
||||
nsCOMPtr<nsIPrivateBrowsingService> pbs =
|
||||
do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
|
||||
bool privacyModeEnabled = false;
|
||||
if (pbs) {
|
||||
pbs->GetPrivateBrowsingEnabled(&privacyModeEnabled);
|
||||
}
|
||||
if (privacyModeEnabled || !mAddToRecentDocs) {
|
||||
ofn.Flags |= OFN_DONTADDTORECENT;
|
||||
}
|
||||
|
||||
if (!mDefaultExtension.IsEmpty()) {
|
||||
ofn.lpstrDefExt = mDefaultExtension.get();
|
||||
}
|
||||
else {
|
||||
// Get file extension from suggested filename
|
||||
// to detect if we are saving an html file
|
||||
//XXX: nsIFile SHOULD HAVE A GetExtension() METHOD!
|
||||
PRInt32 extIndex = mDefault.RFind(".");
|
||||
if ( extIndex >= 0) {
|
||||
nsAutoString ext;
|
||||
mDefault.Right(ext, mDefault.Length() - extIndex);
|
||||
// Should we test for ".cgi", ".asp", ".jsp" and other
|
||||
// "generated" html pages?
|
||||
|
||||
if ( ext.LowerCaseEqualsLiteral(".htm") ||
|
||||
ext.LowerCaseEqualsLiteral(".html") ||
|
||||
ext.LowerCaseEqualsLiteral(".shtml") ) {
|
||||
// This is supposed to append ".htm" if user doesn't supply an extension
|
||||
//XXX Actually, behavior is sort of weird:
|
||||
// often appends ".html" even if you have an extension
|
||||
// It obeys your extension if you put quotes around name
|
||||
ofn.lpstrDefExt = htmExt.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When possible, instead of using OFN_NOCHANGEDIR to ensure the current
|
||||
// working directory will not change from this call, we will retrieve the
|
||||
// current working directory before the call and restore it after the
|
||||
// call. This flag causes problems on Windows XP for paths that are
|
||||
// selected like C:test.txt where the user is currently at C:\somepath
|
||||
// In which case expected result should be C:\somepath\test.txt
|
||||
AutoRestoreWorkingPath restoreWorkingPath;
|
||||
// If we can't get the current working directory, the best case is to
|
||||
// use the OFN_NOCHANGEDIR flag
|
||||
if (!restoreWorkingPath.HasWorkingPath()) {
|
||||
ofn.Flags |= OFN_NOCHANGEDIR;
|
||||
}
|
||||
|
||||
if (mMode == modeOpen) {
|
||||
switch(mMode) {
|
||||
case modeOpen:
|
||||
// FILE MUST EXIST!
|
||||
ofn.Flags |= OFN_FILEMUSTEXIST;
|
||||
result = GetFileName(&ofn, PICKER_TYPE_OPEN);
|
||||
}
|
||||
else if (mMode == modeOpenMultiple) {
|
||||
result = FilePickerWrapper(&ofn, PICKER_TYPE_OPEN);
|
||||
break;
|
||||
|
||||
case modeOpenMultiple:
|
||||
ofn.Flags |= OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT;
|
||||
|
||||
// The hook set here ensures that the buffer returned will always be
|
||||
@ -401,172 +464,165 @@ NS_IMETHODIMP nsFilePicker::ShowW(PRInt16 *aReturnVal)
|
||||
if (nsWindow::GetWindowsVersion() < VISTA_VERSION) {
|
||||
ofn.lpfnHook = MultiFilePickerHook;
|
||||
fileBuffer.forget();
|
||||
result = GetFileName(&ofn, PICKER_TYPE_OPEN);
|
||||
result = FilePickerWrapper(&ofn, PICKER_TYPE_OPEN);
|
||||
fileBuffer = ofn.lpstrFile;
|
||||
}
|
||||
else {
|
||||
result = GetFileName(&ofn, PICKER_TYPE_OPEN);
|
||||
}
|
||||
}
|
||||
else if (mMode == modeSave) {
|
||||
ofn.Flags |= OFN_NOREADONLYRETURN;
|
||||
|
||||
// Don't follow shortcuts when saving a shortcut, this can be used
|
||||
// to trick users (bug 271732)
|
||||
NS_ConvertUTF16toUTF8 ext(mDefault);
|
||||
ext.Trim(" .", false, true); // watch out for trailing space and dots
|
||||
ToLowerCase(ext);
|
||||
if (StringEndsWith(ext, NS_LITERAL_CSTRING(".lnk")) ||
|
||||
StringEndsWith(ext, NS_LITERAL_CSTRING(".pif")) ||
|
||||
StringEndsWith(ext, NS_LITERAL_CSTRING(".url")))
|
||||
ofn.Flags |= OFN_NODEREFERENCELINKS;
|
||||
|
||||
result = GetFileName(&ofn, PICKER_TYPE_SAVE);
|
||||
if (!result) {
|
||||
// Error, find out what kind.
|
||||
if (::GetLastError() == ERROR_INVALID_PARAMETER
|
||||
|| ::CommDlgExtendedError() == FNERR_INVALIDFILENAME
|
||||
) {
|
||||
// probably the default file name is too long or contains illegal characters!
|
||||
// Try again, without a starting file name.
|
||||
ofn.lpstrFile[0] = 0;
|
||||
result = GetFileName(&ofn, PICKER_TYPE_SAVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_ERROR("unsupported mode");
|
||||
}
|
||||
|
||||
if (result) {
|
||||
// Remember what filter type the user selected
|
||||
mSelectedType = (PRInt16)ofn.nFilterIndex;
|
||||
|
||||
// Clear out any files from previous Show calls
|
||||
mFiles.Clear();
|
||||
|
||||
// Set user-selected location of file or directory
|
||||
if (mMode == modeOpenMultiple) {
|
||||
|
||||
// from msdn.microsoft.com, "Open and Save As Dialog Boxes" section:
|
||||
// If you specify OFN_EXPLORER,
|
||||
// The directory and file name strings are NULL separated,
|
||||
// with an extra NULL character after the last file name.
|
||||
// This format enables the Explorer-style dialog boxes
|
||||
// to return long file names that include spaces.
|
||||
PRUnichar *current = fileBuffer;
|
||||
|
||||
nsAutoString dirName(current);
|
||||
// sometimes dirName contains a trailing slash
|
||||
// and sometimes it doesn't.
|
||||
if (current[dirName.Length() - 1] != '\\')
|
||||
dirName.Append((PRUnichar)'\\');
|
||||
|
||||
nsresult rv;
|
||||
while (current && *current && *(current + nsCRT::strlen(current) + 1)) {
|
||||
current = current + nsCRT::strlen(current) + 1;
|
||||
|
||||
nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
// Only prepend the directory if the path specified is a relative path
|
||||
nsAutoString path;
|
||||
if (PathIsRelativeW(current)) {
|
||||
path = dirName + nsDependentString(current);
|
||||
} else {
|
||||
path = current;
|
||||
}
|
||||
|
||||
nsAutoString canonicalizedPath;
|
||||
GetQualifiedPath(path.get(), canonicalizedPath);
|
||||
|
||||
rv = file->InitWithPath(canonicalizedPath);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
rv = mFiles.AppendObject(file);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
|
||||
// handle the case where the user selected just one
|
||||
// file. according to msdn.microsoft.com:
|
||||
// If you specify OFN_ALLOWMULTISELECT and the user selects
|
||||
// only one file, the lpstrFile string does not have
|
||||
// a separator between the path and file name.
|
||||
if (current && *current && (current == fileBuffer)) {
|
||||
nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
nsAutoString canonicalizedPath;
|
||||
GetQualifiedPath(current, canonicalizedPath);
|
||||
rv = file->InitWithPath(canonicalizedPath);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
rv = mFiles.AppendObject(file);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
} else {
|
||||
GetQualifiedPath(fileBuffer, mUnicodeFile);
|
||||
result = FilePickerWrapper(&ofn, PICKER_TYPE_OPEN);
|
||||
}
|
||||
}
|
||||
if (ofn.hwndOwner) {
|
||||
::DestroyWindow(ofn.hwndOwner);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
if (result) {
|
||||
PRInt16 returnOKorReplace = returnOK;
|
||||
case modeSave:
|
||||
{
|
||||
ofn.Flags |= OFN_NOREADONLYRETURN;
|
||||
|
||||
// Remember last used directory.
|
||||
nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
|
||||
NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
|
||||
// Don't follow shortcuts when saving a shortcut, this can be used
|
||||
// to trick users (bug 271732)
|
||||
if (IsDefaultPathLink())
|
||||
ofn.Flags |= OFN_NODEREFERENCELINKS;
|
||||
|
||||
// XXX InitWithPath() will convert UCS2 to FS path !!! corrupts unicode
|
||||
file->InitWithPath(mUnicodeFile);
|
||||
nsCOMPtr<nsIFile> dir;
|
||||
if (NS_SUCCEEDED(file->GetParent(getter_AddRefs(dir)))) {
|
||||
mDisplayDirectory = do_QueryInterface(dir);
|
||||
if (mDisplayDirectory) {
|
||||
if (mLastUsedUnicodeDirectory) {
|
||||
NS_Free(mLastUsedUnicodeDirectory);
|
||||
mLastUsedUnicodeDirectory = nsnull;
|
||||
result = FilePickerWrapper(&ofn, PICKER_TYPE_SAVE);
|
||||
if (!result) {
|
||||
// Error, find out what kind.
|
||||
if (GetLastError() == ERROR_INVALID_PARAMETER ||
|
||||
CommDlgExtendedError() == FNERR_INVALIDFILENAME) {
|
||||
// Probably the default file name is too long or contains illegal
|
||||
// characters. Try again, without a starting file name.
|
||||
ofn.lpstrFile[0] = nsnull;
|
||||
result = FilePickerWrapper(&ofn, PICKER_TYPE_SAVE);
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoString newDir;
|
||||
mDisplayDirectory->GetPath(newDir);
|
||||
if(!newDir.IsEmpty())
|
||||
mLastUsedUnicodeDirectory = ToNewUnicode(newDir);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_ERROR("unsupported file picker mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
// Remember what filter type the user selected
|
||||
mSelectedType = (PRInt16)ofn.nFilterIndex;
|
||||
|
||||
// Single file selection, we're done
|
||||
if (mMode != modeOpenMultiple) {
|
||||
GetQualifiedPath(fileBuffer, mUnicodeFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Clear previous file selection list
|
||||
mFiles.Clear();
|
||||
|
||||
// Set user-selected location of file or directory. From msdn's "Open and
|
||||
// Save As Dialog Boxes" section:
|
||||
// If you specify OFN_EXPLORER, the directory and file name strings are NULL
|
||||
// separated, with an extra NULL character after the last file name. This
|
||||
// format enables the Explorer-style dialog boxes to return long file names
|
||||
// that include spaces.
|
||||
PRUnichar *current = fileBuffer;
|
||||
|
||||
nsAutoString dirName(current);
|
||||
// Sometimes dirName contains a trailing slash and sometimes it doesn't:
|
||||
if (current[dirName.Length() - 1] != '\\')
|
||||
dirName.Append((PRUnichar)'\\');
|
||||
|
||||
while (current && *current && *(current + nsCRT::strlen(current) + 1)) {
|
||||
current = current + nsCRT::strlen(current) + 1;
|
||||
|
||||
nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
NS_ENSURE_TRUE(file, false);
|
||||
|
||||
// Only prepend the directory if the path specified is a relative path
|
||||
nsAutoString path;
|
||||
if (PathIsRelativeW(current)) {
|
||||
path = dirName + nsDependentString(current);
|
||||
} else {
|
||||
path = current;
|
||||
}
|
||||
|
||||
if (mMode == modeSave) {
|
||||
// Windows does not return resultReplace,
|
||||
// we must check if file already exists
|
||||
bool exists = false;
|
||||
file->Exists(&exists);
|
||||
nsAutoString canonicalizedPath;
|
||||
GetQualifiedPath(path.get(), canonicalizedPath);
|
||||
if (NS_FAILED(file->InitWithPath(canonicalizedPath)) ||
|
||||
!mFiles.AppendObject(file))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle the case where the user selected just one file. From msdn: If you
|
||||
// specify OFN_ALLOWMULTISELECT and the user selects only one file the
|
||||
// lpstrFile string does not have a separator between the path and file name.
|
||||
if (current && *current && (current == fileBuffer)) {
|
||||
nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
NS_ENSURE_TRUE(file, false);
|
||||
|
||||
nsAutoString canonicalizedPath;
|
||||
GetQualifiedPath(current, canonicalizedPath);
|
||||
if (NS_FAILED(file->InitWithPath(canonicalizedPath)) ||
|
||||
!mFiles.AppendObject(file))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exists)
|
||||
returnOKorReplace = returnReplace;
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::ShowW(PRInt16 *aReturnVal)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aReturnVal);
|
||||
|
||||
*aReturnVal = returnCancel;
|
||||
|
||||
AutoSuppressEvents supress(mParentWidget);
|
||||
|
||||
nsAutoString initialDir;
|
||||
if (mDisplayDirectory)
|
||||
mDisplayDirectory->GetPath(initialDir);
|
||||
|
||||
// If no display directory, re-use the last one.
|
||||
if(initialDir.IsEmpty()) {
|
||||
// Allocate copy of last used dir.
|
||||
initialDir = mLastUsedUnicodeDirectory;
|
||||
}
|
||||
|
||||
mUnicodeFile.Truncate();
|
||||
|
||||
bool result = false;
|
||||
if (mMode == modeGetFolder) {
|
||||
result = ShowFolderPicker(initialDir);
|
||||
} else {
|
||||
result = ShowFilePicker(initialDir);
|
||||
}
|
||||
|
||||
// exit, and return returnCancel in aReturnVal
|
||||
if (!result)
|
||||
return NS_OK;
|
||||
|
||||
RememberLastUsedDirectory();
|
||||
|
||||
PRInt16 retValue = returnOK;
|
||||
if (mMode == modeSave) {
|
||||
// Windows does not return resultReplace, we must check if file
|
||||
// already exists.
|
||||
nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
|
||||
bool flag = false;
|
||||
if (file && NS_SUCCEEDED(file->InitWithPath(mUnicodeFile)) &&
|
||||
NS_SUCCEEDED(file->Exists(&flag)) && flag) {
|
||||
retValue = returnReplace;
|
||||
}
|
||||
*aReturnVal = returnOKorReplace;
|
||||
}
|
||||
else {
|
||||
*aReturnVal = returnCancel;
|
||||
}
|
||||
if (mParentWidget) {
|
||||
nsIWidget *tmp = mParentWidget;
|
||||
nsWindow *parent = static_cast<nsWindow *>(tmp);
|
||||
parent->SuppressBlurEvents(false);
|
||||
}
|
||||
|
||||
*aReturnVal = retValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::Show(PRInt16 *aReturnVal)
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::Show(PRInt16 *aReturnVal)
|
||||
{
|
||||
return ShowW(aReturnVal);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::GetFile(nsILocalFile **aFile)
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::GetFile(nsILocalFile **aFile)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFile);
|
||||
*aFile = nsnull;
|
||||
@ -585,7 +641,8 @@ NS_IMETHODIMP nsFilePicker::GetFile(nsILocalFile **aFile)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::GetFileURL(nsIURI **aFileURL)
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::GetFileURL(nsIURI **aFileURL)
|
||||
{
|
||||
*aFileURL = nsnull;
|
||||
nsCOMPtr<nsILocalFile> file;
|
||||
@ -596,14 +653,16 @@ NS_IMETHODIMP nsFilePicker::GetFileURL(nsIURI **aFileURL)
|
||||
return NS_NewFileURI(aFileURL, file);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFiles);
|
||||
return NS_NewArrayEnumerator(aFiles, mFiles);
|
||||
}
|
||||
|
||||
// Get the file + path
|
||||
NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString& aString)
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::SetDefaultString(const nsAString& aString)
|
||||
{
|
||||
mDefault = aString;
|
||||
|
||||
@ -635,42 +694,48 @@ NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString& aString)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString& aString)
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::GetDefaultString(nsAString& aString)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// The default extension to use for files
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension)
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::GetDefaultExtension(nsAString& aExtension)
|
||||
{
|
||||
aExtension = mDefaultExtension;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString& aExtension)
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::SetDefaultExtension(const nsAString& aExtension)
|
||||
{
|
||||
mDefaultExtension = aExtension;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Set the filter index
|
||||
NS_IMETHODIMP nsFilePicker::GetFilterIndex(PRInt32 *aFilterIndex)
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::GetFilterIndex(PRInt32 *aFilterIndex)
|
||||
{
|
||||
// Windows' filter index is 1-based, we use a 0-based system.
|
||||
*aFilterIndex = mSelectedType - 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::SetFilterIndex(PRInt32 aFilterIndex)
|
||||
NS_IMETHODIMP
|
||||
nsFilePicker::SetFilterIndex(PRInt32 aFilterIndex)
|
||||
{
|
||||
// Windows' filter index is 1-based, we use a 0-based system.
|
||||
mSelectedType = aFilterIndex + 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsFilePicker::InitNative(nsIWidget *aParent,
|
||||
const nsAString& aTitle,
|
||||
PRInt16 aMode)
|
||||
void
|
||||
nsFilePicker::InitNative(nsIWidget *aParent,
|
||||
const nsAString& aTitle,
|
||||
PRInt16 aMode)
|
||||
{
|
||||
mParentWidget = aParent;
|
||||
mTitle.Assign(aTitle);
|
||||
@ -713,19 +778,69 @@ nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AutoRestoreWorkingPath::AutoRestoreWorkingPath()
|
||||
void
|
||||
nsFilePicker::RememberLastUsedDirectory()
|
||||
{
|
||||
DWORD bufferLength = GetCurrentDirectoryW(0, NULL);
|
||||
mWorkingPath = new PRUnichar[bufferLength];
|
||||
if (GetCurrentDirectoryW(bufferLength, mWorkingPath) == 0) {
|
||||
mWorkingPath = NULL;
|
||||
nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
|
||||
if (!file || NS_FAILED(file->InitWithPath(mUnicodeFile))) {
|
||||
NS_WARNING("RememberLastUsedDirectory failed to init file path.");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> dir;
|
||||
nsAutoString newDir;
|
||||
if (NS_FAILED(file->GetParent(getter_AddRefs(dir))) ||
|
||||
!(mDisplayDirectory = do_QueryInterface(dir)) ||
|
||||
NS_FAILED(mDisplayDirectory->GetPath(newDir)) ||
|
||||
newDir.IsEmpty()) {
|
||||
NS_WARNING("RememberLastUsedDirectory failed to get parent directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mLastUsedUnicodeDirectory) {
|
||||
NS_Free(mLastUsedUnicodeDirectory);
|
||||
mLastUsedUnicodeDirectory = nsnull;
|
||||
}
|
||||
mLastUsedUnicodeDirectory = ToNewUnicode(newDir);
|
||||
}
|
||||
|
||||
AutoRestoreWorkingPath::~AutoRestoreWorkingPath()
|
||||
bool
|
||||
nsFilePicker::IsPrivacyModeEnabled()
|
||||
{
|
||||
if (HasWorkingPath()) {
|
||||
::SetCurrentDirectoryW(mWorkingPath);
|
||||
// Handle add to recent docs settings
|
||||
nsCOMPtr<nsIPrivateBrowsingService> pbs =
|
||||
do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
|
||||
bool privacyModeEnabled = false;
|
||||
if (pbs) {
|
||||
pbs->GetPrivateBrowsingEnabled(&privacyModeEnabled);
|
||||
}
|
||||
return privacyModeEnabled;
|
||||
}
|
||||
|
||||
bool
|
||||
nsFilePicker::IsDefaultPathLink()
|
||||
{
|
||||
NS_ConvertUTF16toUTF8 ext(mDefault);
|
||||
ext.Trim(" .", false, true); // watch out for trailing space and dots
|
||||
ToLowerCase(ext);
|
||||
if (StringEndsWith(ext, NS_LITERAL_CSTRING(".lnk")) ||
|
||||
StringEndsWith(ext, NS_LITERAL_CSTRING(".pif")) ||
|
||||
StringEndsWith(ext, NS_LITERAL_CSTRING(".url")))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsFilePicker::IsDefaultPathHtml()
|
||||
{
|
||||
PRInt32 extIndex = mDefault.RFind(".");
|
||||
if (extIndex >= 0) {
|
||||
nsAutoString ext;
|
||||
mDefault.Right(ext, mDefault.Length() - extIndex);
|
||||
if (ext.LowerCaseEqualsLiteral(".htm") ||
|
||||
ext.LowerCaseEqualsLiteral(".html") ||
|
||||
ext.LowerCaseEqualsLiteral(".shtml"))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <pavlov@netscape.com>
|
||||
* Seth Spitzer <sspitzer@netscape.com>
|
||||
* Jim Mathies <jmathies@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
|
||||
@ -90,7 +91,13 @@ protected:
|
||||
PRInt16 aMode);
|
||||
static void GetQualifiedPath(const PRUnichar *aInPath, nsString &aOutPath);
|
||||
void GetFilterListArray(nsString& aFilterList);
|
||||
bool GetFileName(OPENFILENAMEW* ofn, PickerType aType);
|
||||
bool FilePickerWrapper(OPENFILENAMEW* ofn, PickerType aType);
|
||||
bool ShowFilePicker(const nsString& aInitialDir);
|
||||
bool ShowFolderPicker(const nsString& aInitialDir);
|
||||
void RememberLastUsedDirectory();
|
||||
bool IsPrivacyModeEnabled();
|
||||
bool IsDefaultPathLink();
|
||||
bool IsDefaultPathHtml();
|
||||
|
||||
nsCOMPtr<nsIWidget> mParentWidget;
|
||||
nsString mTitle;
|
||||
@ -106,20 +113,4 @@ protected:
|
||||
static PRUnichar *mLastUsedUnicodeDirectory;
|
||||
};
|
||||
|
||||
// The constructor will obtain the working path, the destructor
|
||||
// will set the working path back to what it used to be.
|
||||
class AutoRestoreWorkingPath
|
||||
{
|
||||
public:
|
||||
AutoRestoreWorkingPath();
|
||||
~AutoRestoreWorkingPath();
|
||||
inline bool HasWorkingPath() const
|
||||
{
|
||||
return mWorkingPath != NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
nsAutoArrayPtr<PRUnichar> mWorkingPath;
|
||||
};
|
||||
|
||||
#endif // nsFilePicker_h__
|
||||
|
Loading…
Reference in New Issue
Block a user