toolkit/components/filepicker/nsFilePicker.js

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:9650415687b1
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 /*
7 * No magic constructor behaviour, as is de rigeur for XPCOM.
8 * If you must perform some initialization, and it could possibly fail (even
9 * due to an out-of-memory condition), you should use an Init method, which
10 * can convey failure appropriately (thrown exception in JS,
11 * NS_FAILED(nsresult) return in C++).
12 *
13 * In JS, you can actually cheat, because a thrown exception will cause the
14 * CreateInstance call to fail in turn, but not all languages are so lucky.
15 * (Though ANSI C++ provides exceptions, they are verboten in Mozilla code
16 * for portability reasons -- and even when you're building completely
17 * platform-specific code, you can't throw across an XPCOM method boundary.)
18 */
19
20 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
21
22 const DEBUG = false; /* set to true to enable debug messages */
23
24 const LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1";
25 const APPSHELL_SERV_CONTRACTID = "@mozilla.org/appshell/appShellService;1";
26 const STRBUNDLE_SERV_CONTRACTID = "@mozilla.org/intl/stringbundle;1";
27
28 const nsIAppShellService = Components.interfaces.nsIAppShellService;
29 const nsILocalFile = Components.interfaces.nsILocalFile;
30 const nsIFileURL = Components.interfaces.nsIFileURL;
31 const nsISupports = Components.interfaces.nsISupports;
32 const nsIFactory = Components.interfaces.nsIFactory;
33 const nsIFilePicker = Components.interfaces.nsIFilePicker;
34 const nsIInterfaceRequestor = Components.interfaces.nsIInterfaceRequestor;
35 const nsIDOMWindow = Components.interfaces.nsIDOMWindow;
36 const nsIStringBundleService = Components.interfaces.nsIStringBundleService;
37 const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
38 const nsIDocShellTreeItem = Components.interfaces.nsIDocShellTreeItem;
39 const nsIBaseWindow = Components.interfaces.nsIBaseWindow;
40
41 var titleBundle = null;
42 var filterBundle = null;
43 var lastDirectory = null;
44
45 function nsFilePicker()
46 {
47 if (!titleBundle)
48 titleBundle = srGetStrBundle("chrome://global/locale/filepicker.properties");
49 if (!filterBundle)
50 filterBundle = srGetStrBundle("chrome://global/content/filepicker.properties");
51
52 /* attributes */
53 this.mDefaultString = "";
54 this.mFilterIndex = 0;
55 this.mFilterTitles = new Array();
56 this.mFilters = new Array();
57 this.mDisplayDirectory = null;
58 if (lastDirectory) {
59 try {
60 var dir = Components.classes[LOCAL_FILE_CONTRACTID].createInstance(nsILocalFile);
61 dir.initWithPath(lastDirectory);
62 this.mDisplayDirectory = dir;
63 } catch (e) {}
64 }
65 }
66
67 nsFilePicker.prototype = {
68 classID: Components.ID("{54ae32f8-1dd2-11b2-a209-df7c505370f8}"),
69
70 QueryInterface: function(iid) {
71 if (iid.equals(nsIFilePicker) ||
72 iid.equals(nsISupports))
73 return this;
74
75 throw Components.results.NS_ERROR_NO_INTERFACE;
76 },
77
78
79 /* attribute nsILocalFile displayDirectory; */
80 set displayDirectory(a) {
81 this.mDisplayDirectory = a &&
82 a.clone().QueryInterface(nsILocalFile);
83 },
84 get displayDirectory() {
85 return this.mDisplayDirectory &&
86 this.mDisplayDirectory.clone()
87 .QueryInterface(nsILocalFile);
88 },
89
90 /* readonly attribute nsILocalFile file; */
91 get file() { return this.mFilesEnumerator.mFiles[0]; },
92
93 /* readonly attribute nsISimpleEnumerator files; */
94 get files() { return this.mFilesEnumerator; },
95
96 /* readonly attribute nsIDOMFile domfile; */
97 get domfile() {
98 let enumerator = this.domfiles;
99 return enumerator ? enumerator.mFiles[0] : null;
100 },
101
102 /* readonly attribute nsISimpleEnumerator domfiles; */
103 get domfiles() {
104 if (!this.mFilesEnumerator) {
105 return null;
106 }
107
108 if (!this.mDOMFilesEnumerator) {
109 this.mDOMFilesEnumerator = {
110 QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISimpleEnumerator]),
111
112 mFiles: [],
113 mIndex: 0,
114
115 hasMoreElements: function() {
116 return (this.mIndex < this.mFiles.length);
117 },
118
119 getNext: function() {
120 if (this.mIndex >= this.mFiles.length) {
121 throw Components.results.NS_ERROR_FAILURE;
122 }
123 return this.mFiles[this.mIndex++];
124 }
125 };
126
127 var utils = this.mParentWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
128 .getInterface(Components.interfaces.nsIDOMWindowUtils);
129
130 for (var i = 0; i < this.mFilesEnumerator.mFiles.length; ++i) {
131 var file = utils.wrapDOMFile(this.mFilesEnumerator.mFiles[i]);
132 this.mDOMFilesEnumerator.mFiles.push(file);
133 }
134 }
135
136 return this.mDOMFilesEnumerator;
137 },
138
139 /* readonly attribute nsIURI fileURL; */
140 get fileURL() {
141 if (this.mFileURL)
142 return this.mFileURL;
143
144 if (!this.mFilesEnumerator)
145 return null;
146
147 var ioService = Components.classes["@mozilla.org/network/io-service;1"]
148 .getService(Components.interfaces.nsIIOService);
149
150 return this.mFileURL = ioService.newFileURI(this.file);
151 },
152
153 /* attribute wstring defaultString; */
154 set defaultString(a) { this.mDefaultString = a; },
155 get defaultString() { return this.mDefaultString; },
156
157 /* attribute wstring defaultExtension */
158 set defaultExtension(ext) { },
159 get defaultExtension() { return ""; },
160
161 /* attribute long filterIndex; */
162 set filterIndex(a) { this.mFilterIndex = a; },
163 get filterIndex() { return this.mFilterIndex; },
164
165 /* attribute boolean addToRecentDocs; */
166 set addToRecentDocs(a) {},
167 get addToRecentDocs() { return false; },
168
169 /* readonly attribute short mode; */
170 get mode() { return this.mMode; },
171
172 /* members */
173 mFilesEnumerator: undefined,
174 mDOMFilesEnumerator: undefined,
175 mParentWindow: null,
176
177 /* methods */
178 init: function(parent, title, mode) {
179 this.mParentWindow = parent;
180 this.mTitle = title;
181 this.mMode = mode;
182 },
183
184 appendFilters: function(filterMask) {
185 if (filterMask & nsIFilePicker.filterHTML) {
186 this.appendFilter(titleBundle.GetStringFromName("htmlTitle"),
187 filterBundle.GetStringFromName("htmlFilter"));
188 }
189 if (filterMask & nsIFilePicker.filterText) {
190 this.appendFilter(titleBundle.GetStringFromName("textTitle"),
191 filterBundle.GetStringFromName("textFilter"));
192 }
193 if (filterMask & nsIFilePicker.filterImages) {
194 this.appendFilter(titleBundle.GetStringFromName("imageTitle"),
195 filterBundle.GetStringFromName("imageFilter"));
196 }
197 if (filterMask & nsIFilePicker.filterXML) {
198 this.appendFilter(titleBundle.GetStringFromName("xmlTitle"),
199 filterBundle.GetStringFromName("xmlFilter"));
200 }
201 if (filterMask & nsIFilePicker.filterXUL) {
202 this.appendFilter(titleBundle.GetStringFromName("xulTitle"),
203 filterBundle.GetStringFromName("xulFilter"));
204 }
205 this.mAllowURLs = !!(filterMask & nsIFilePicker.filterAllowURLs);
206 if (filterMask & nsIFilePicker.filterApps) {
207 // We use "..apps" as a special filter for executable files
208 this.appendFilter(titleBundle.GetStringFromName("appsTitle"),
209 "..apps");
210 }
211 if (filterMask & nsIFilePicker.filterAudio) {
212 this.appendFilter(titleBundle.GetStringFromName("audioTitle"),
213 filterBundle.GetStringFromName("audioFilter"));
214 }
215 if (filterMask & nsIFilePicker.filterVideo) {
216 this.appendFilter(titleBundle.GetStringFromName("videoTitle"),
217 filterBundle.GetStringFromName("videoFilter"));
218 }
219 if (filterMask & nsIFilePicker.filterAll) {
220 this.appendFilter(titleBundle.GetStringFromName("allTitle"),
221 filterBundle.GetStringFromName("allFilter"));
222 }
223 },
224
225 appendFilter: function(title, extensions) {
226 this.mFilterTitles.push(title);
227 this.mFilters.push(extensions);
228 },
229
230 open: function(aFilePickerShownCallback) {
231 var tm = Components.classes["@mozilla.org/thread-manager;1"]
232 .getService(Components.interfaces.nsIThreadManager);
233 tm.mainThread.dispatch(function() {
234 let result = Components.interfaces.nsIFilePicker.returnCancel;
235 try {
236 result = this.show();
237 } catch(ex) {
238 }
239 if (aFilePickerShownCallback) {
240 aFilePickerShownCallback.done(result);
241 }
242 }.bind(this), Components.interfaces.nsIThread.DISPATCH_NORMAL);
243 },
244
245 show: function() {
246 var o = new Object();
247 o.title = this.mTitle;
248 o.mode = this.mMode;
249 o.displayDirectory = this.mDisplayDirectory;
250 o.defaultString = this.mDefaultString;
251 o.filterIndex = this.mFilterIndex;
252 o.filters = new Object();
253 o.filters.titles = this.mFilterTitles;
254 o.filters.types = this.mFilters;
255 o.allowURLs = this.mAllowURLs;
256 o.retvals = new Object();
257
258 var parent;
259 if (this.mParentWindow) {
260 parent = this.mParentWindow;
261 } else if (typeof(window) == "object" && window != null) {
262 parent = window;
263 } else {
264 try {
265 var appShellService = Components.classes[APPSHELL_SERV_CONTRACTID].getService(nsIAppShellService);
266 parent = appShellService.hiddenDOMWindow;
267 } catch(ex) {
268 debug("Can't get parent. xpconnect hates me so we can't get one from the appShellService.\n");
269 debug(ex + "\n");
270 }
271 }
272
273 var parentWin = null;
274 try {
275 parentWin = parent.QueryInterface(nsIInterfaceRequestor)
276 .getInterface(nsIWebNavigation)
277 .QueryInterface(nsIDocShellTreeItem)
278 .treeOwner
279 .QueryInterface(nsIInterfaceRequestor)
280 .getInterface(nsIBaseWindow);
281 } catch(ex) {
282 dump("file picker couldn't get base window\n"+ex+"\n");
283 }
284 try {
285 parent.openDialog("chrome://global/content/filepicker.xul",
286 "",
287 "chrome,modal,titlebar,resizable=yes,dependent=yes",
288 o);
289
290 this.mFilterIndex = o.retvals.filterIndex;
291 this.mFilesEnumerator = o.retvals.files;
292 this.mFileURL = o.retvals.fileURL;
293 lastDirectory = o.retvals.directory;
294 return o.retvals.buttonStatus;
295 } catch(ex) { dump("unable to open file picker\n" + ex + "\n"); }
296
297 return null;
298 }
299 }
300
301 if (DEBUG)
302 debug = function (s) { dump("-*- filepicker: " + s + "\n"); };
303 else
304 debug = function (s) {};
305
306 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsFilePicker]);
307
308 /* crap from strres.js that I want to use for string bundles since I can't include another .js file.... */
309
310 var strBundleService = null;
311
312 function srGetStrBundle(path)
313 {
314 var strBundle = null;
315
316 if (!strBundleService) {
317 try {
318 strBundleService = Components.classes[STRBUNDLE_SERV_CONTRACTID].getService(nsIStringBundleService);
319 } catch (ex) {
320 dump("\n--** strBundleService createInstance failed **--\n");
321 return null;
322 }
323 }
324
325 strBundle = strBundleService.createBundle(path);
326 if (!strBundle) {
327 dump("\n--** strBundle createInstance failed **--\n");
328 }
329 return strBundle;
330 }
331

mercurial