summaryrefslogtreecommitdiffstats
path: root/widget/nsBaseFilePicker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/nsBaseFilePicker.cpp')
-rw-r--r--widget/nsBaseFilePicker.cpp393
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;
+}
+