|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
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/. */ |
|
6 |
|
7 #include "nsCOMPtr.h" |
|
8 #include "nsPIDOMWindow.h" |
|
9 #include "nsIDocShell.h" |
|
10 #include "nsIInterfaceRequestorUtils.h" |
|
11 #include "nsIBaseWindow.h" |
|
12 #include "nsIWidget.h" |
|
13 |
|
14 #include "nsIStringBundle.h" |
|
15 #include "nsXPIDLString.h" |
|
16 #include "nsIServiceManager.h" |
|
17 #include "nsCOMArray.h" |
|
18 #include "nsIFile.h" |
|
19 #include "nsDOMFile.h" |
|
20 #include "nsEnumeratorUtils.h" |
|
21 #include "mozilla/Services.h" |
|
22 #include "WidgetUtils.h" |
|
23 #include "nsThreadUtils.h" |
|
24 |
|
25 #include "nsBaseFilePicker.h" |
|
26 |
|
27 using namespace mozilla::widget; |
|
28 |
|
29 #define FILEPICKER_TITLES "chrome://global/locale/filepicker.properties" |
|
30 #define FILEPICKER_FILTERS "chrome://global/content/filepicker.properties" |
|
31 |
|
32 /** |
|
33 * A runnable to dispatch from the main thread to the main thread to display |
|
34 * the file picker while letting the showAsync method return right away. |
|
35 */ |
|
36 class AsyncShowFilePicker : public nsRunnable |
|
37 { |
|
38 public: |
|
39 AsyncShowFilePicker(nsIFilePicker *aFilePicker, |
|
40 nsIFilePickerShownCallback *aCallback) : |
|
41 mFilePicker(aFilePicker), |
|
42 mCallback(aCallback) |
|
43 { |
|
44 } |
|
45 |
|
46 NS_IMETHOD Run() |
|
47 { |
|
48 NS_ASSERTION(NS_IsMainThread(), |
|
49 "AsyncShowFilePicker should be on the main thread!"); |
|
50 |
|
51 // It's possible that some widget implementations require GUI operations |
|
52 // to be on the main thread, so that's why we're not dispatching to another |
|
53 // thread and calling back to the main after it's done. |
|
54 int16_t result = nsIFilePicker::returnCancel; |
|
55 nsresult rv = mFilePicker->Show(&result); |
|
56 if (NS_FAILED(rv)) { |
|
57 NS_ERROR("FilePicker's Show() implementation failed!"); |
|
58 } |
|
59 |
|
60 if (mCallback) { |
|
61 mCallback->Done(result); |
|
62 } |
|
63 return NS_OK; |
|
64 } |
|
65 |
|
66 private: |
|
67 nsRefPtr<nsIFilePicker> mFilePicker; |
|
68 nsRefPtr<nsIFilePickerShownCallback> mCallback; |
|
69 }; |
|
70 |
|
71 class nsBaseFilePickerEnumerator : public nsISimpleEnumerator |
|
72 { |
|
73 public: |
|
74 NS_DECL_ISUPPORTS |
|
75 |
|
76 nsBaseFilePickerEnumerator(nsISimpleEnumerator* iterator) |
|
77 : mIterator(iterator) |
|
78 {} |
|
79 |
|
80 virtual ~nsBaseFilePickerEnumerator() |
|
81 {} |
|
82 |
|
83 NS_IMETHOD |
|
84 GetNext(nsISupports** aResult) |
|
85 { |
|
86 nsCOMPtr<nsISupports> tmp; |
|
87 nsresult rv = mIterator->GetNext(getter_AddRefs(tmp)); |
|
88 NS_ENSURE_SUCCESS(rv, rv); |
|
89 |
|
90 if (!tmp) { |
|
91 return NS_OK; |
|
92 } |
|
93 |
|
94 nsCOMPtr<nsIFile> localFile = do_QueryInterface(tmp); |
|
95 if (!localFile) { |
|
96 return NS_ERROR_FAILURE; |
|
97 } |
|
98 |
|
99 nsCOMPtr<nsIDOMFile> domFile = new nsDOMFileFile(localFile); |
|
100 domFile.forget(aResult); |
|
101 return NS_OK; |
|
102 } |
|
103 |
|
104 NS_IMETHOD |
|
105 HasMoreElements(bool* aResult) |
|
106 { |
|
107 return mIterator->HasMoreElements(aResult); |
|
108 } |
|
109 |
|
110 private: |
|
111 nsCOMPtr<nsISimpleEnumerator> mIterator; |
|
112 }; |
|
113 |
|
114 NS_IMPL_ISUPPORTS(nsBaseFilePickerEnumerator, nsISimpleEnumerator) |
|
115 |
|
116 nsBaseFilePicker::nsBaseFilePicker() |
|
117 : mAddToRecentDocs(true) |
|
118 , mMode(nsIFilePicker::modeOpen) |
|
119 { |
|
120 |
|
121 } |
|
122 |
|
123 nsBaseFilePicker::~nsBaseFilePicker() |
|
124 { |
|
125 |
|
126 } |
|
127 |
|
128 NS_IMETHODIMP nsBaseFilePicker::Init(nsIDOMWindow *aParent, |
|
129 const nsAString& aTitle, |
|
130 int16_t aMode) |
|
131 { |
|
132 NS_PRECONDITION(aParent, "Null parent passed to filepicker, no file " |
|
133 "picker for you!"); |
|
134 nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(aParent); |
|
135 NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE); |
|
136 |
|
137 mMode = aMode; |
|
138 InitNative(widget, aTitle); |
|
139 |
|
140 return NS_OK; |
|
141 } |
|
142 |
|
143 NS_IMETHODIMP |
|
144 nsBaseFilePicker::Open(nsIFilePickerShownCallback *aCallback) |
|
145 { |
|
146 nsCOMPtr<nsIRunnable> filePickerEvent = |
|
147 new AsyncShowFilePicker(this, aCallback); |
|
148 return NS_DispatchToMainThread(filePickerEvent); |
|
149 } |
|
150 |
|
151 NS_IMETHODIMP |
|
152 nsBaseFilePicker::AppendFilters(int32_t aFilterMask) |
|
153 { |
|
154 nsCOMPtr<nsIStringBundleService> stringService = |
|
155 mozilla::services::GetStringBundleService(); |
|
156 if (!stringService) |
|
157 return NS_ERROR_FAILURE; |
|
158 |
|
159 nsCOMPtr<nsIStringBundle> titleBundle, filterBundle; |
|
160 |
|
161 nsresult rv = stringService->CreateBundle(FILEPICKER_TITLES, |
|
162 getter_AddRefs(titleBundle)); |
|
163 if (NS_FAILED(rv)) |
|
164 return NS_ERROR_FAILURE; |
|
165 |
|
166 rv = stringService->CreateBundle(FILEPICKER_FILTERS, getter_AddRefs(filterBundle)); |
|
167 if (NS_FAILED(rv)) |
|
168 return NS_ERROR_FAILURE; |
|
169 |
|
170 nsXPIDLString title; |
|
171 nsXPIDLString filter; |
|
172 |
|
173 if (aFilterMask & filterAll) { |
|
174 titleBundle->GetStringFromName(MOZ_UTF16("allTitle"), getter_Copies(title)); |
|
175 filterBundle->GetStringFromName(MOZ_UTF16("allFilter"), getter_Copies(filter)); |
|
176 AppendFilter(title,filter); |
|
177 } |
|
178 if (aFilterMask & filterHTML) { |
|
179 titleBundle->GetStringFromName(MOZ_UTF16("htmlTitle"), getter_Copies(title)); |
|
180 filterBundle->GetStringFromName(MOZ_UTF16("htmlFilter"), getter_Copies(filter)); |
|
181 AppendFilter(title,filter); |
|
182 } |
|
183 if (aFilterMask & filterText) { |
|
184 titleBundle->GetStringFromName(MOZ_UTF16("textTitle"), getter_Copies(title)); |
|
185 filterBundle->GetStringFromName(MOZ_UTF16("textFilter"), getter_Copies(filter)); |
|
186 AppendFilter(title,filter); |
|
187 } |
|
188 if (aFilterMask & filterImages) { |
|
189 titleBundle->GetStringFromName(MOZ_UTF16("imageTitle"), getter_Copies(title)); |
|
190 filterBundle->GetStringFromName(MOZ_UTF16("imageFilter"), getter_Copies(filter)); |
|
191 AppendFilter(title,filter); |
|
192 } |
|
193 if (aFilterMask & filterAudio) { |
|
194 titleBundle->GetStringFromName(MOZ_UTF16("audioTitle"), getter_Copies(title)); |
|
195 filterBundle->GetStringFromName(MOZ_UTF16("audioFilter"), getter_Copies(filter)); |
|
196 AppendFilter(title,filter); |
|
197 } |
|
198 if (aFilterMask & filterVideo) { |
|
199 titleBundle->GetStringFromName(MOZ_UTF16("videoTitle"), getter_Copies(title)); |
|
200 filterBundle->GetStringFromName(MOZ_UTF16("videoFilter"), getter_Copies(filter)); |
|
201 AppendFilter(title,filter); |
|
202 } |
|
203 if (aFilterMask & filterXML) { |
|
204 titleBundle->GetStringFromName(MOZ_UTF16("xmlTitle"), getter_Copies(title)); |
|
205 filterBundle->GetStringFromName(MOZ_UTF16("xmlFilter"), getter_Copies(filter)); |
|
206 AppendFilter(title,filter); |
|
207 } |
|
208 if (aFilterMask & filterXUL) { |
|
209 titleBundle->GetStringFromName(MOZ_UTF16("xulTitle"), getter_Copies(title)); |
|
210 filterBundle->GetStringFromName(MOZ_UTF16("xulFilter"), getter_Copies(filter)); |
|
211 AppendFilter(title, filter); |
|
212 } |
|
213 if (aFilterMask & filterApps) { |
|
214 titleBundle->GetStringFromName(MOZ_UTF16("appsTitle"), getter_Copies(title)); |
|
215 // Pass the magic string "..apps" to the platform filepicker, which it |
|
216 // should recognize and do the correct platform behavior for. |
|
217 AppendFilter(title, NS_LITERAL_STRING("..apps")); |
|
218 } |
|
219 return NS_OK; |
|
220 } |
|
221 |
|
222 // Set the filter index |
|
223 NS_IMETHODIMP nsBaseFilePicker::GetFilterIndex(int32_t *aFilterIndex) |
|
224 { |
|
225 *aFilterIndex = 0; |
|
226 return NS_OK; |
|
227 } |
|
228 |
|
229 NS_IMETHODIMP nsBaseFilePicker::SetFilterIndex(int32_t aFilterIndex) |
|
230 { |
|
231 return NS_OK; |
|
232 } |
|
233 |
|
234 NS_IMETHODIMP nsBaseFilePicker::GetFiles(nsISimpleEnumerator **aFiles) |
|
235 { |
|
236 NS_ENSURE_ARG_POINTER(aFiles); |
|
237 nsCOMArray <nsIFile> files; |
|
238 nsresult rv; |
|
239 |
|
240 // if we get into the base class, the platform |
|
241 // doesn't implement GetFiles() yet. |
|
242 // so we fake it. |
|
243 nsCOMPtr <nsIFile> file; |
|
244 rv = GetFile(getter_AddRefs(file)); |
|
245 NS_ENSURE_SUCCESS(rv,rv); |
|
246 |
|
247 files.AppendObject(file); |
|
248 |
|
249 return NS_NewArrayEnumerator(aFiles, files); |
|
250 } |
|
251 |
|
252 // Set the display directory |
|
253 NS_IMETHODIMP nsBaseFilePicker::SetDisplayDirectory(nsIFile *aDirectory) |
|
254 { |
|
255 if (!aDirectory) { |
|
256 mDisplayDirectory = nullptr; |
|
257 return NS_OK; |
|
258 } |
|
259 nsCOMPtr<nsIFile> directory; |
|
260 nsresult rv = aDirectory->Clone(getter_AddRefs(directory)); |
|
261 if (NS_FAILED(rv)) |
|
262 return rv; |
|
263 mDisplayDirectory = do_QueryInterface(directory, &rv); |
|
264 return rv; |
|
265 } |
|
266 |
|
267 // Get the display directory |
|
268 NS_IMETHODIMP nsBaseFilePicker::GetDisplayDirectory(nsIFile **aDirectory) |
|
269 { |
|
270 *aDirectory = nullptr; |
|
271 if (!mDisplayDirectory) |
|
272 return NS_OK; |
|
273 nsCOMPtr<nsIFile> directory; |
|
274 nsresult rv = mDisplayDirectory->Clone(getter_AddRefs(directory)); |
|
275 if (NS_FAILED(rv)) { |
|
276 return rv; |
|
277 } |
|
278 directory.forget(aDirectory); |
|
279 return NS_OK; |
|
280 } |
|
281 |
|
282 NS_IMETHODIMP |
|
283 nsBaseFilePicker::GetAddToRecentDocs(bool *aFlag) |
|
284 { |
|
285 *aFlag = mAddToRecentDocs; |
|
286 return NS_OK; |
|
287 } |
|
288 |
|
289 NS_IMETHODIMP |
|
290 nsBaseFilePicker::SetAddToRecentDocs(bool aFlag) |
|
291 { |
|
292 mAddToRecentDocs = aFlag; |
|
293 return NS_OK; |
|
294 } |
|
295 |
|
296 NS_IMETHODIMP |
|
297 nsBaseFilePicker::GetMode(int16_t* aMode) |
|
298 { |
|
299 *aMode = mMode; |
|
300 return NS_OK; |
|
301 } |
|
302 |
|
303 NS_IMETHODIMP |
|
304 nsBaseFilePicker::GetDomfile(nsIDOMFile** aDomfile) |
|
305 { |
|
306 nsCOMPtr<nsIFile> localFile; |
|
307 nsresult rv = GetFile(getter_AddRefs(localFile)); |
|
308 NS_ENSURE_SUCCESS(rv, rv); |
|
309 |
|
310 if (!localFile) { |
|
311 *aDomfile = nullptr; |
|
312 return NS_OK; |
|
313 } |
|
314 |
|
315 nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(localFile); |
|
316 domFile.forget(aDomfile); |
|
317 return NS_OK; |
|
318 } |
|
319 |
|
320 NS_IMETHODIMP |
|
321 nsBaseFilePicker::GetDomfiles(nsISimpleEnumerator** aDomfiles) |
|
322 { |
|
323 nsCOMPtr<nsISimpleEnumerator> iter; |
|
324 nsresult rv = GetFiles(getter_AddRefs(iter)); |
|
325 NS_ENSURE_SUCCESS(rv, rv); |
|
326 |
|
327 nsRefPtr<nsBaseFilePickerEnumerator> retIter = |
|
328 new nsBaseFilePickerEnumerator(iter); |
|
329 |
|
330 retIter.forget(aDomfiles); |
|
331 return NS_OK; |
|
332 } |
|
333 |