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"
15 #include "nsXPIDLString.h"
16 #include "nsIServiceManager.h"
17 #include "nsCOMArray.h"
19 #include "nsEnumeratorUtils.h"
20 #include "mozilla/dom/File.h"
21 #include "mozilla/Services.h"
22 #include "WidgetUtils.h"
23 #include "nsThreadUtils.h"
25 #include "nsBaseFilePicker.h"
27 using namespace mozilla::widget
;
28 using namespace mozilla::dom
;
30 #define FILEPICKER_TITLES "chrome://global/locale/filepicker.properties"
31 #define FILEPICKER_FILTERS "chrome://global/content/filepicker.properties"
34 * A runnable to dispatch from the main thread to the main thread to display
35 * the file picker while letting the showAsync method return right away.
37 class AsyncShowFilePicker
: public nsRunnable
40 AsyncShowFilePicker(nsIFilePicker
*aFilePicker
,
41 nsIFilePickerShownCallback
*aCallback
) :
42 mFilePicker(aFilePicker
),
49 NS_ASSERTION(NS_IsMainThread(),
50 "AsyncShowFilePicker should be on the main thread!");
52 // It's possible that some widget implementations require GUI operations
53 // to be on the main thread, so that's why we're not dispatching to another
54 // thread and calling back to the main after it's done.
55 int16_t result
= nsIFilePicker::returnCancel
;
56 nsresult rv
= mFilePicker
->Show(&result
);
58 NS_ERROR("FilePicker's Show() implementation failed!");
62 mCallback
->Done(result
);
68 nsRefPtr
<nsIFilePicker
> mFilePicker
;
69 nsRefPtr
<nsIFilePickerShownCallback
> mCallback
;
72 class nsBaseFilePickerEnumerator
: public nsISimpleEnumerator
77 explicit nsBaseFilePickerEnumerator(nsPIDOMWindow
* aParent
,
78 nsISimpleEnumerator
* iterator
)
84 GetNext(nsISupports
** aResult
)
86 nsCOMPtr
<nsISupports
> tmp
;
87 nsresult rv
= mIterator
->GetNext(getter_AddRefs(tmp
));
88 NS_ENSURE_SUCCESS(rv
, rv
);
94 nsCOMPtr
<nsIFile
> localFile
= do_QueryInterface(tmp
);
96 return NS_ERROR_FAILURE
;
99 nsCOMPtr
<nsIDOMFile
> domFile
= File::CreateFromFile(mParent
, localFile
);
100 domFile
.forget(aResult
);
105 HasMoreElements(bool* aResult
)
107 return mIterator
->HasMoreElements(aResult
);
111 virtual ~nsBaseFilePickerEnumerator()
115 nsCOMPtr
<nsISimpleEnumerator
> mIterator
;
116 nsCOMPtr
<nsPIDOMWindow
> mParent
;
119 NS_IMPL_ISUPPORTS(nsBaseFilePickerEnumerator
, nsISimpleEnumerator
)
121 nsBaseFilePicker::nsBaseFilePicker()
122 : mAddToRecentDocs(true)
123 , mMode(nsIFilePicker::modeOpen
)
128 nsBaseFilePicker::~nsBaseFilePicker()
133 NS_IMETHODIMP
nsBaseFilePicker::Init(nsIDOMWindow
*aParent
,
134 const nsAString
& aTitle
,
137 NS_PRECONDITION(aParent
, "Null parent passed to filepicker, no file "
139 nsCOMPtr
<nsIWidget
> widget
= WidgetUtils::DOMWindowToWidget(aParent
);
140 NS_ENSURE_TRUE(widget
, NS_ERROR_FAILURE
);
142 mParent
= do_QueryInterface(aParent
);
143 if (!mParent
->IsInnerWindow()) {
144 mParent
= mParent
->GetCurrentInnerWindow();
148 InitNative(widget
, aTitle
);
154 nsBaseFilePicker::Open(nsIFilePickerShownCallback
*aCallback
)
156 nsCOMPtr
<nsIRunnable
> filePickerEvent
=
157 new AsyncShowFilePicker(this, aCallback
);
158 return NS_DispatchToMainThread(filePickerEvent
);
162 nsBaseFilePicker::AppendFilters(int32_t aFilterMask
)
164 nsCOMPtr
<nsIStringBundleService
> stringService
=
165 mozilla::services::GetStringBundleService();
167 return NS_ERROR_FAILURE
;
169 nsCOMPtr
<nsIStringBundle
> titleBundle
, filterBundle
;
171 nsresult rv
= stringService
->CreateBundle(FILEPICKER_TITLES
,
172 getter_AddRefs(titleBundle
));
174 return NS_ERROR_FAILURE
;
176 rv
= stringService
->CreateBundle(FILEPICKER_FILTERS
, getter_AddRefs(filterBundle
));
178 return NS_ERROR_FAILURE
;
181 nsXPIDLString filter
;
183 if (aFilterMask
& filterAll
) {
184 titleBundle
->GetStringFromName(MOZ_UTF16("allTitle"), getter_Copies(title
));
185 filterBundle
->GetStringFromName(MOZ_UTF16("allFilter"), getter_Copies(filter
));
186 AppendFilter(title
,filter
);
188 if (aFilterMask
& filterHTML
) {
189 titleBundle
->GetStringFromName(MOZ_UTF16("htmlTitle"), getter_Copies(title
));
190 filterBundle
->GetStringFromName(MOZ_UTF16("htmlFilter"), getter_Copies(filter
));
191 AppendFilter(title
,filter
);
193 if (aFilterMask
& filterText
) {
194 titleBundle
->GetStringFromName(MOZ_UTF16("textTitle"), getter_Copies(title
));
195 filterBundle
->GetStringFromName(MOZ_UTF16("textFilter"), getter_Copies(filter
));
196 AppendFilter(title
,filter
);
198 if (aFilterMask
& filterImages
) {
199 titleBundle
->GetStringFromName(MOZ_UTF16("imageTitle"), getter_Copies(title
));
200 filterBundle
->GetStringFromName(MOZ_UTF16("imageFilter"), getter_Copies(filter
));
201 AppendFilter(title
,filter
);
203 if (aFilterMask
& filterAudio
) {
204 titleBundle
->GetStringFromName(MOZ_UTF16("audioTitle"), getter_Copies(title
));
205 filterBundle
->GetStringFromName(MOZ_UTF16("audioFilter"), getter_Copies(filter
));
206 AppendFilter(title
,filter
);
208 if (aFilterMask
& filterVideo
) {
209 titleBundle
->GetStringFromName(MOZ_UTF16("videoTitle"), getter_Copies(title
));
210 filterBundle
->GetStringFromName(MOZ_UTF16("videoFilter"), getter_Copies(filter
));
211 AppendFilter(title
,filter
);
213 if (aFilterMask
& filterXML
) {
214 titleBundle
->GetStringFromName(MOZ_UTF16("xmlTitle"), getter_Copies(title
));
215 filterBundle
->GetStringFromName(MOZ_UTF16("xmlFilter"), getter_Copies(filter
));
216 AppendFilter(title
,filter
);
218 if (aFilterMask
& filterXUL
) {
219 titleBundle
->GetStringFromName(MOZ_UTF16("xulTitle"), getter_Copies(title
));
220 filterBundle
->GetStringFromName(MOZ_UTF16("xulFilter"), getter_Copies(filter
));
221 AppendFilter(title
, filter
);
223 if (aFilterMask
& filterApps
) {
224 titleBundle
->GetStringFromName(MOZ_UTF16("appsTitle"), getter_Copies(title
));
225 // Pass the magic string "..apps" to the platform filepicker, which it
226 // should recognize and do the correct platform behavior for.
227 AppendFilter(title
, NS_LITERAL_STRING("..apps"));
232 // Set the filter index
233 NS_IMETHODIMP
nsBaseFilePicker::GetFilterIndex(int32_t *aFilterIndex
)
239 NS_IMETHODIMP
nsBaseFilePicker::SetFilterIndex(int32_t aFilterIndex
)
244 NS_IMETHODIMP
nsBaseFilePicker::GetFiles(nsISimpleEnumerator
**aFiles
)
246 NS_ENSURE_ARG_POINTER(aFiles
);
247 nsCOMArray
<nsIFile
> files
;
250 // if we get into the base class, the platform
251 // doesn't implement GetFiles() yet.
253 nsCOMPtr
<nsIFile
> file
;
254 rv
= GetFile(getter_AddRefs(file
));
255 NS_ENSURE_SUCCESS(rv
,rv
);
257 files
.AppendObject(file
);
259 return NS_NewArrayEnumerator(aFiles
, files
);
262 // Set the display directory
263 NS_IMETHODIMP
nsBaseFilePicker::SetDisplayDirectory(nsIFile
*aDirectory
)
266 mDisplayDirectory
= nullptr;
269 nsCOMPtr
<nsIFile
> directory
;
270 nsresult rv
= aDirectory
->Clone(getter_AddRefs(directory
));
273 mDisplayDirectory
= do_QueryInterface(directory
, &rv
);
277 // Get the display directory
278 NS_IMETHODIMP
nsBaseFilePicker::GetDisplayDirectory(nsIFile
**aDirectory
)
280 *aDirectory
= nullptr;
281 if (!mDisplayDirectory
)
283 nsCOMPtr
<nsIFile
> directory
;
284 nsresult rv
= mDisplayDirectory
->Clone(getter_AddRefs(directory
));
288 directory
.forget(aDirectory
);
293 nsBaseFilePicker::GetAddToRecentDocs(bool *aFlag
)
295 *aFlag
= mAddToRecentDocs
;
300 nsBaseFilePicker::SetAddToRecentDocs(bool aFlag
)
302 mAddToRecentDocs
= aFlag
;
307 nsBaseFilePicker::GetMode(int16_t* aMode
)
314 nsBaseFilePicker::GetDomfile(nsIDOMFile
** aDomfile
)
316 nsCOMPtr
<nsIFile
> localFile
;
317 nsresult rv
= GetFile(getter_AddRefs(localFile
));
318 NS_ENSURE_SUCCESS(rv
, rv
);
325 nsRefPtr
<File
> domFile
= File::CreateFromFile(mParent
, localFile
);
326 domFile
.forget(aDomfile
);
331 nsBaseFilePicker::GetDomfiles(nsISimpleEnumerator
** aDomfiles
)
333 nsCOMPtr
<nsISimpleEnumerator
> iter
;
334 nsresult rv
= GetFiles(getter_AddRefs(iter
));
335 NS_ENSURE_SUCCESS(rv
, rv
);
337 nsRefPtr
<nsBaseFilePickerEnumerator
> retIter
=
338 new nsBaseFilePickerEnumerator(mParent
, iter
);
340 retIter
.forget(aDomfiles
);