1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "nsPIDOMWindow.h"
9 #include "nsIDocShell.h"
10 #include "nsIInterfaceRequestorUtils.h"
11 #include "nsIBaseWindow.h"
12 #include "nsIWidget.h"
14 #include "nsIStringBundle.h"
16 #include "nsIServiceManager.h"
17 #include "nsCOMArray.h"
19 #include "nsEnumeratorUtils.h"
20 #include "mozilla/dom/Directory.h"
21 #include "mozilla/dom/File.h"
22 #include "mozilla/Services.h"
23 #include "WidgetUtils.h"
24 #include "nsThreadUtils.h"
26 #include "nsBaseFilePicker.h"
28 using namespace mozilla::widget
;
29 using namespace mozilla::dom
;
31 #define FILEPICKER_TITLES "chrome://global/locale/filepicker.properties"
32 #define FILEPICKER_FILTERS "chrome://global/content/filepicker.properties"
37 LocalFileToDirectoryOrBlob(nsPIDOMWindowInner
* aWindow
,
40 nsISupports
** aResult
)
45 aFile
->IsDirectory(&isDir
);
49 RefPtr
<Directory
> directory
= Directory::Create(aWindow
, aFile
);
50 MOZ_ASSERT(directory
);
52 directory
.forget(aResult
);
56 RefPtr
<File
> file
= File::CreateFromFile(aWindow
, aFile
);
61 } // anonymous namespace
64 * A runnable to dispatch from the main thread to the main thread to display
65 * the file picker while letting the showAsync method return right away.
67 class nsBaseFilePicker::AsyncShowFilePicker
: public mozilla::Runnable
70 AsyncShowFilePicker(nsBaseFilePicker
* aFilePicker
,
71 nsIFilePickerShownCallback
* aCallback
)
72 : mozilla::Runnable("AsyncShowFilePicker")
73 , mFilePicker(aFilePicker
)
74 , mCallback(aCallback
)
78 NS_IMETHOD
Run() override
80 NS_ASSERTION(NS_IsMainThread(),
81 "AsyncShowFilePicker should be on the main thread!");
83 // It's possible that some widget implementations require GUI operations
84 // to be on the main thread, so that's why we're not dispatching to another
85 // thread and calling back to the main after it's done.
86 int16_t result
= nsIFilePicker::returnCancel
;
87 nsresult rv
= mFilePicker
->Show(&result
);
89 NS_ERROR("FilePicker's Show() implementation failed!");
93 mCallback
->Done(result
);
99 RefPtr
<nsBaseFilePicker
> mFilePicker
;
100 RefPtr
<nsIFilePickerShownCallback
> mCallback
;
103 class nsBaseFilePickerEnumerator
: public nsISimpleEnumerator
108 nsBaseFilePickerEnumerator(nsPIDOMWindowOuter
* aParent
,
109 nsISimpleEnumerator
* iterator
,
111 : mIterator(iterator
)
112 , mParent(aParent
->GetCurrentInnerWindow())
117 GetNext(nsISupports
** aResult
) override
119 nsCOMPtr
<nsISupports
> tmp
;
120 nsresult rv
= mIterator
->GetNext(getter_AddRefs(tmp
));
121 NS_ENSURE_SUCCESS(rv
, rv
);
127 nsCOMPtr
<nsIFile
> localFile
= do_QueryInterface(tmp
);
129 return NS_ERROR_FAILURE
;
132 return LocalFileToDirectoryOrBlob(mParent
,
133 mMode
== nsIFilePicker::modeGetFolder
,
139 HasMoreElements(bool* aResult
) override
141 return mIterator
->HasMoreElements(aResult
);
145 virtual ~nsBaseFilePickerEnumerator()
149 nsCOMPtr
<nsISimpleEnumerator
> mIterator
;
150 nsCOMPtr
<nsPIDOMWindowInner
> mParent
;
154 NS_IMPL_ISUPPORTS(nsBaseFilePickerEnumerator
, nsISimpleEnumerator
)
156 nsBaseFilePicker::nsBaseFilePicker()
157 : mAddToRecentDocs(true)
158 , mMode(nsIFilePicker::modeOpen
)
163 nsBaseFilePicker::~nsBaseFilePicker()
168 NS_IMETHODIMP
nsBaseFilePicker::Init(mozIDOMWindowProxy
* aParent
,
169 const nsAString
& aTitle
,
172 MOZ_ASSERT(aParent
, "Null parent passed to filepicker, no file "
175 mParent
= nsPIDOMWindowOuter::From(aParent
);
177 nsCOMPtr
<nsIWidget
> widget
= WidgetUtils::DOMWindowToWidget(mParent
->GetOuterWindow());
178 NS_ENSURE_TRUE(widget
, NS_ERROR_FAILURE
);
182 InitNative(widget
, aTitle
);
188 nsBaseFilePicker::Open(nsIFilePickerShownCallback
*aCallback
)
190 nsCOMPtr
<nsIRunnable
> filePickerEvent
=
191 new AsyncShowFilePicker(this, aCallback
);
192 return NS_DispatchToMainThread(filePickerEvent
);
196 nsBaseFilePicker::AppendFilters(int32_t aFilterMask
)
198 nsCOMPtr
<nsIStringBundleService
> stringService
=
199 mozilla::services::GetStringBundleService();
201 return NS_ERROR_FAILURE
;
203 nsCOMPtr
<nsIStringBundle
> titleBundle
, filterBundle
;
205 nsresult rv
= stringService
->CreateBundle(FILEPICKER_TITLES
,
206 getter_AddRefs(titleBundle
));
208 return NS_ERROR_FAILURE
;
210 rv
= stringService
->CreateBundle(FILEPICKER_FILTERS
, getter_AddRefs(filterBundle
));
212 return NS_ERROR_FAILURE
;
217 if (aFilterMask
& filterAll
) {
218 titleBundle
->GetStringFromName("allTitle", title
);
219 filterBundle
->GetStringFromName("allFilter", filter
);
220 AppendFilter(title
,filter
);
222 if (aFilterMask
& filterHTML
) {
223 titleBundle
->GetStringFromName("htmlTitle", title
);
224 filterBundle
->GetStringFromName("htmlFilter", filter
);
225 AppendFilter(title
,filter
);
227 if (aFilterMask
& filterText
) {
228 titleBundle
->GetStringFromName("textTitle", title
);
229 filterBundle
->GetStringFromName("textFilter", filter
);
230 AppendFilter(title
,filter
);
232 if (aFilterMask
& filterImages
) {
233 titleBundle
->GetStringFromName("imageTitle", title
);
234 filterBundle
->GetStringFromName("imageFilter", filter
);
235 AppendFilter(title
,filter
);
237 if (aFilterMask
& filterAudio
) {
238 titleBundle
->GetStringFromName("audioTitle", title
);
239 filterBundle
->GetStringFromName("audioFilter", filter
);
240 AppendFilter(title
,filter
);
242 if (aFilterMask
& filterVideo
) {
243 titleBundle
->GetStringFromName("videoTitle", title
);
244 filterBundle
->GetStringFromName("videoFilter", filter
);
245 AppendFilter(title
,filter
);
247 if (aFilterMask
& filterXML
) {
248 titleBundle
->GetStringFromName("xmlTitle", title
);
249 filterBundle
->GetStringFromName("xmlFilter", filter
);
250 AppendFilter(title
,filter
);
252 if (aFilterMask
& filterXUL
) {
253 titleBundle
->GetStringFromName("xulTitle", title
);
254 filterBundle
->GetStringFromName("xulFilter", filter
);
255 AppendFilter(title
, filter
);
257 if (aFilterMask
& filterApps
) {
258 titleBundle
->GetStringFromName("appsTitle", title
);
259 // Pass the magic string "..apps" to the platform filepicker, which it
260 // should recognize and do the correct platform behavior for.
261 AppendFilter(title
, NS_LITERAL_STRING("..apps"));
266 // Set the filter index
267 NS_IMETHODIMP
nsBaseFilePicker::GetFilterIndex(int32_t *aFilterIndex
)
273 NS_IMETHODIMP
nsBaseFilePicker::SetFilterIndex(int32_t aFilterIndex
)
278 NS_IMETHODIMP
nsBaseFilePicker::GetFiles(nsISimpleEnumerator
**aFiles
)
280 NS_ENSURE_ARG_POINTER(aFiles
);
281 nsCOMArray
<nsIFile
> files
;
284 // if we get into the base class, the platform
285 // doesn't implement GetFiles() yet.
287 nsCOMPtr
<nsIFile
> file
;
288 rv
= GetFile(getter_AddRefs(file
));
289 NS_ENSURE_SUCCESS(rv
,rv
);
291 files
.AppendObject(file
);
293 return NS_NewArrayEnumerator(aFiles
, files
);
296 // Set the display directory
297 NS_IMETHODIMP
nsBaseFilePicker::SetDisplayDirectory(nsIFile
*aDirectory
)
299 // if displaySpecialDirectory has been previously called, let's abort this
301 if (!mDisplaySpecialDirectory
.IsEmpty()) {
306 mDisplayDirectory
= nullptr;
309 nsCOMPtr
<nsIFile
> directory
;
310 nsresult rv
= aDirectory
->Clone(getter_AddRefs(directory
));
313 mDisplayDirectory
= do_QueryInterface(directory
, &rv
);
317 // Get the display directory
318 NS_IMETHODIMP
nsBaseFilePicker::GetDisplayDirectory(nsIFile
**aDirectory
)
320 *aDirectory
= nullptr;
322 // if displaySpecialDirectory has been previously called, let's abort this
324 if (!mDisplaySpecialDirectory
.IsEmpty()) {
328 if (!mDisplayDirectory
)
330 nsCOMPtr
<nsIFile
> directory
;
331 nsresult rv
= mDisplayDirectory
->Clone(getter_AddRefs(directory
));
335 directory
.forget(aDirectory
);
339 // Set the display special directory
340 NS_IMETHODIMP
nsBaseFilePicker::SetDisplaySpecialDirectory(const nsAString
& aDirectory
)
342 // if displayDirectory has been previously called, let's abort this operation.
343 if (mDisplayDirectory
&& mDisplaySpecialDirectory
.IsEmpty()) {
347 mDisplaySpecialDirectory
= aDirectory
;
348 if (mDisplaySpecialDirectory
.IsEmpty()) {
349 mDisplayDirectory
= nullptr;
353 return NS_GetSpecialDirectory(NS_ConvertUTF16toUTF8(mDisplaySpecialDirectory
).get(),
354 getter_AddRefs(mDisplayDirectory
));
357 // Get the display special directory
358 NS_IMETHODIMP
nsBaseFilePicker::GetDisplaySpecialDirectory(nsAString
& aDirectory
)
360 aDirectory
= mDisplaySpecialDirectory
;
365 nsBaseFilePicker::GetAddToRecentDocs(bool *aFlag
)
367 *aFlag
= mAddToRecentDocs
;
372 nsBaseFilePicker::SetAddToRecentDocs(bool aFlag
)
374 mAddToRecentDocs
= aFlag
;
379 nsBaseFilePicker::GetMode(int16_t* aMode
)
386 nsBaseFilePicker::SetOkButtonLabel(const nsAString
& aLabel
)
388 mOkButtonLabel
= aLabel
;
393 nsBaseFilePicker::GetOkButtonLabel(nsAString
& aLabel
)
395 aLabel
= mOkButtonLabel
;
400 nsBaseFilePicker::GetDomFileOrDirectory(nsISupports
** aValue
)
402 nsCOMPtr
<nsIFile
> localFile
;
403 nsresult rv
= GetFile(getter_AddRefs(localFile
));
404 NS_ENSURE_SUCCESS(rv
, rv
);
411 auto* innerParent
= mParent
? mParent
->GetCurrentInnerWindow() : nullptr;
413 return LocalFileToDirectoryOrBlob(innerParent
,
414 mMode
== nsIFilePicker::modeGetFolder
,
420 nsBaseFilePicker::GetDomFileOrDirectoryEnumerator(nsISimpleEnumerator
** aValue
)
422 nsCOMPtr
<nsISimpleEnumerator
> iter
;
423 nsresult rv
= GetFiles(getter_AddRefs(iter
));
424 NS_ENSURE_SUCCESS(rv
, rv
);
426 RefPtr
<nsBaseFilePickerEnumerator
> retIter
=
427 new nsBaseFilePickerEnumerator(mParent
, iter
, mMode
);
429 retIter
.forget(aValue
);