diff options
Diffstat (limited to 'widget/nsBaseFilePicker.cpp')
-rw-r--r-- | widget/nsBaseFilePicker.cpp | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/widget/nsBaseFilePicker.cpp b/widget/nsBaseFilePicker.cpp new file mode 100644 index 000000000..d65ffb651 --- /dev/null +++ b/widget/nsBaseFilePicker.cpp @@ -0,0 +1,393 @@ +/* -*- 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/. */ + +#include "nsCOMPtr.h" +#include "nsPIDOMWindow.h" +#include "nsIDocShell.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIBaseWindow.h" +#include "nsIWidget.h" + +#include "nsIStringBundle.h" +#include "nsXPIDLString.h" +#include "nsIServiceManager.h" +#include "nsCOMArray.h" +#include "nsIFile.h" +#include "nsEnumeratorUtils.h" +#include "mozilla/dom/Directory.h" +#include "mozilla/dom/File.h" +#include "mozilla/Services.h" +#include "WidgetUtils.h" +#include "nsThreadUtils.h" + +#include "nsBaseFilePicker.h" + +using namespace mozilla::widget; +using namespace mozilla::dom; + +#define FILEPICKER_TITLES "chrome://global/locale/filepicker.properties" +#define FILEPICKER_FILTERS "chrome://global/content/filepicker.properties" + +namespace { + +nsresult +LocalFileToDirectoryOrBlob(nsPIDOMWindowInner* aWindow, + bool aIsDirectory, + nsIFile* aFile, + nsISupports** aResult) +{ + if (aIsDirectory) { +#ifdef DEBUG + bool isDir; + aFile->IsDirectory(&isDir); + MOZ_ASSERT(isDir); +#endif + + RefPtr<Directory> directory = Directory::Create(aWindow, aFile); + MOZ_ASSERT(directory); + + directory.forget(aResult); + return NS_OK; + } + + nsCOMPtr<nsIDOMBlob> blob = File::CreateFromFile(aWindow, aFile); + blob.forget(aResult); + return NS_OK; +} + +} // anonymous namespace + +/** + * A runnable to dispatch from the main thread to the main thread to display + * the file picker while letting the showAsync method return right away. +*/ +class AsyncShowFilePicker : public mozilla::Runnable +{ +public: + AsyncShowFilePicker(nsIFilePicker *aFilePicker, + nsIFilePickerShownCallback *aCallback) : + mFilePicker(aFilePicker), + mCallback(aCallback) + { + } + + NS_IMETHOD Run() override + { + NS_ASSERTION(NS_IsMainThread(), + "AsyncShowFilePicker should be on the main thread!"); + + // It's possible that some widget implementations require GUI operations + // to be on the main thread, so that's why we're not dispatching to another + // thread and calling back to the main after it's done. + int16_t result = nsIFilePicker::returnCancel; + nsresult rv = mFilePicker->Show(&result); + if (NS_FAILED(rv)) { + NS_ERROR("FilePicker's Show() implementation failed!"); + } + + if (mCallback) { + mCallback->Done(result); + } + return NS_OK; + } + +private: + RefPtr<nsIFilePicker> mFilePicker; + RefPtr<nsIFilePickerShownCallback> mCallback; +}; + +class nsBaseFilePickerEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + + nsBaseFilePickerEnumerator(nsPIDOMWindowOuter* aParent, + nsISimpleEnumerator* iterator, + int16_t aMode) + : mIterator(iterator) + , mParent(aParent->GetCurrentInnerWindow()) + , mMode(aMode) + {} + + NS_IMETHOD + GetNext(nsISupports** aResult) override + { + nsCOMPtr<nsISupports> tmp; + nsresult rv = mIterator->GetNext(getter_AddRefs(tmp)); + NS_ENSURE_SUCCESS(rv, rv); + + if (!tmp) { + return NS_OK; + } + + nsCOMPtr<nsIFile> localFile = do_QueryInterface(tmp); + if (!localFile) { + return NS_ERROR_FAILURE; + } + + return LocalFileToDirectoryOrBlob(mParent, + mMode == nsIFilePicker::modeGetFolder, + localFile, + aResult); + } + + NS_IMETHOD + HasMoreElements(bool* aResult) override + { + return mIterator->HasMoreElements(aResult); + } + +protected: + virtual ~nsBaseFilePickerEnumerator() + {} + +private: + nsCOMPtr<nsISimpleEnumerator> mIterator; + nsCOMPtr<nsPIDOMWindowInner> mParent; + int16_t mMode; +}; + +NS_IMPL_ISUPPORTS(nsBaseFilePickerEnumerator, nsISimpleEnumerator) + +nsBaseFilePicker::nsBaseFilePicker() + : mAddToRecentDocs(true) + , mMode(nsIFilePicker::modeOpen) +{ + +} + +nsBaseFilePicker::~nsBaseFilePicker() +{ + +} + +NS_IMETHODIMP nsBaseFilePicker::Init(mozIDOMWindowProxy* aParent, + const nsAString& aTitle, + int16_t aMode) +{ + NS_PRECONDITION(aParent, "Null parent passed to filepicker, no file " + "picker for you!"); + + mParent = nsPIDOMWindowOuter::From(aParent); + + nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(mParent->GetOuterWindow()); + NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE); + + + mMode = aMode; + InitNative(widget, aTitle); + + return NS_OK; +} + +NS_IMETHODIMP +nsBaseFilePicker::Open(nsIFilePickerShownCallback *aCallback) +{ + nsCOMPtr<nsIRunnable> filePickerEvent = + new AsyncShowFilePicker(this, aCallback); + return NS_DispatchToMainThread(filePickerEvent); +} + +NS_IMETHODIMP +nsBaseFilePicker::AppendFilters(int32_t aFilterMask) +{ + nsCOMPtr<nsIStringBundleService> stringService = + mozilla::services::GetStringBundleService(); + if (!stringService) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIStringBundle> titleBundle, filterBundle; + + nsresult rv = stringService->CreateBundle(FILEPICKER_TITLES, + getter_AddRefs(titleBundle)); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + rv = stringService->CreateBundle(FILEPICKER_FILTERS, getter_AddRefs(filterBundle)); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + nsXPIDLString title; + nsXPIDLString filter; + + if (aFilterMask & filterAll) { + titleBundle->GetStringFromName(u"allTitle", getter_Copies(title)); + filterBundle->GetStringFromName(u"allFilter", getter_Copies(filter)); + AppendFilter(title,filter); + } + if (aFilterMask & filterHTML) { + titleBundle->GetStringFromName(u"htmlTitle", getter_Copies(title)); + filterBundle->GetStringFromName(u"htmlFilter", getter_Copies(filter)); + AppendFilter(title,filter); + } + if (aFilterMask & filterText) { + titleBundle->GetStringFromName(u"textTitle", getter_Copies(title)); + filterBundle->GetStringFromName(u"textFilter", getter_Copies(filter)); + AppendFilter(title,filter); + } + if (aFilterMask & filterImages) { + titleBundle->GetStringFromName(u"imageTitle", getter_Copies(title)); + filterBundle->GetStringFromName(u"imageFilter", getter_Copies(filter)); + AppendFilter(title,filter); + } + if (aFilterMask & filterAudio) { + titleBundle->GetStringFromName(u"audioTitle", getter_Copies(title)); + filterBundle->GetStringFromName(u"audioFilter", getter_Copies(filter)); + AppendFilter(title,filter); + } + if (aFilterMask & filterVideo) { + titleBundle->GetStringFromName(u"videoTitle", getter_Copies(title)); + filterBundle->GetStringFromName(u"videoFilter", getter_Copies(filter)); + AppendFilter(title,filter); + } + if (aFilterMask & filterXML) { + titleBundle->GetStringFromName(u"xmlTitle", getter_Copies(title)); + filterBundle->GetStringFromName(u"xmlFilter", getter_Copies(filter)); + AppendFilter(title,filter); + } + if (aFilterMask & filterXUL) { + titleBundle->GetStringFromName(u"xulTitle", getter_Copies(title)); + filterBundle->GetStringFromName(u"xulFilter", getter_Copies(filter)); + AppendFilter(title, filter); + } + if (aFilterMask & filterApps) { + titleBundle->GetStringFromName(u"appsTitle", getter_Copies(title)); + // Pass the magic string "..apps" to the platform filepicker, which it + // should recognize and do the correct platform behavior for. + AppendFilter(title, NS_LITERAL_STRING("..apps")); + } + return NS_OK; +} + +// Set the filter index +NS_IMETHODIMP nsBaseFilePicker::GetFilterIndex(int32_t *aFilterIndex) +{ + *aFilterIndex = 0; + return NS_OK; +} + +NS_IMETHODIMP nsBaseFilePicker::SetFilterIndex(int32_t aFilterIndex) +{ + return NS_OK; +} + +NS_IMETHODIMP nsBaseFilePicker::GetFiles(nsISimpleEnumerator **aFiles) +{ + NS_ENSURE_ARG_POINTER(aFiles); + nsCOMArray <nsIFile> files; + nsresult rv; + + // if we get into the base class, the platform + // doesn't implement GetFiles() yet. + // so we fake it. + nsCOMPtr <nsIFile> file; + rv = GetFile(getter_AddRefs(file)); + NS_ENSURE_SUCCESS(rv,rv); + + files.AppendObject(file); + + return NS_NewArrayEnumerator(aFiles, files); +} + +// Set the display directory +NS_IMETHODIMP nsBaseFilePicker::SetDisplayDirectory(nsIFile *aDirectory) +{ + if (!aDirectory) { + mDisplayDirectory = nullptr; + return NS_OK; + } + nsCOMPtr<nsIFile> directory; + nsresult rv = aDirectory->Clone(getter_AddRefs(directory)); + if (NS_FAILED(rv)) + return rv; + mDisplayDirectory = do_QueryInterface(directory, &rv); + return rv; +} + +// Get the display directory +NS_IMETHODIMP nsBaseFilePicker::GetDisplayDirectory(nsIFile **aDirectory) +{ + *aDirectory = nullptr; + if (!mDisplayDirectory) + return NS_OK; + nsCOMPtr<nsIFile> directory; + nsresult rv = mDisplayDirectory->Clone(getter_AddRefs(directory)); + if (NS_FAILED(rv)) { + return rv; + } + directory.forget(aDirectory); + return NS_OK; +} + +NS_IMETHODIMP +nsBaseFilePicker::GetAddToRecentDocs(bool *aFlag) +{ + *aFlag = mAddToRecentDocs; + return NS_OK; +} + +NS_IMETHODIMP +nsBaseFilePicker::SetAddToRecentDocs(bool aFlag) +{ + mAddToRecentDocs = aFlag; + return NS_OK; +} + +NS_IMETHODIMP +nsBaseFilePicker::GetMode(int16_t* aMode) +{ + *aMode = mMode; + return NS_OK; +} + +NS_IMETHODIMP +nsBaseFilePicker::SetOkButtonLabel(const nsAString& aLabel) +{ + mOkButtonLabel = aLabel; + return NS_OK; +} + +NS_IMETHODIMP +nsBaseFilePicker::GetOkButtonLabel(nsAString& aLabel) +{ + aLabel = mOkButtonLabel; + return NS_OK; +} + +NS_IMETHODIMP +nsBaseFilePicker::GetDomFileOrDirectory(nsISupports** aValue) +{ + nsCOMPtr<nsIFile> localFile; + nsresult rv = GetFile(getter_AddRefs(localFile)); + NS_ENSURE_SUCCESS(rv, rv); + + if (!localFile) { + *aValue = nullptr; + return NS_OK; + } + + auto* innerParent = mParent ? mParent->GetCurrentInnerWindow() : nullptr; + + return LocalFileToDirectoryOrBlob(innerParent, + mMode == nsIFilePicker::modeGetFolder, + localFile, + aValue); +} + +NS_IMETHODIMP +nsBaseFilePicker::GetDomFileOrDirectoryEnumerator(nsISimpleEnumerator** aValue) +{ + nsCOMPtr<nsISimpleEnumerator> iter; + nsresult rv = GetFiles(getter_AddRefs(iter)); + NS_ENSURE_SUCCESS(rv, rv); + + RefPtr<nsBaseFilePickerEnumerator> retIter = + new nsBaseFilePickerEnumerator(mParent, iter, mMode); + + retIter.forget(aValue); + return NS_OK; +} + |