Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const Ci = Components.interfaces;
6 const Cu = Components.utils;
7 const Cc = Components.classes;
9 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
10 Cu.import("resource://gre/modules/Services.jsm");
11 Cu.import("resource://gre/modules/FileUtils.jsm");
13 function FilePicker() {
14 }
16 FilePicker.prototype = {
17 _mimeTypeFilter: 0,
18 _extensionsFilter: "",
19 _defaultString: "",
20 _domWin: null,
21 _defaultExtension: null,
22 _displayDirectory: null,
23 _filePath: null,
24 _promptActive: false,
25 _filterIndex: 0,
26 _addToRecentDocs: false,
28 init: function(aParent, aTitle, aMode) {
29 this._domWin = aParent;
30 this._mode = aMode;
31 Services.obs.addObserver(this, "FilePicker:Result", false);
33 let idService = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
34 this.guid = idService.generateUUID().toString();
36 if (aMode != Ci.nsIFilePicker.modeOpen && aMode != Ci.nsIFilePicker.modeOpenMultiple)
37 throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
38 },
40 appendFilters: function(aFilterMask) {
41 if (aFilterMask & Ci.nsIFilePicker.filterAudio) {
42 this._mimeTypeFilter = "audio/*";
43 return;
44 }
46 if (aFilterMask & Ci.nsIFilePicker.filterImages) {
47 this._mimeTypeFilter = "image/*";
48 return;
49 }
51 if (aFilterMask & Ci.nsIFilePicker.filterVideo) {
52 this._mimeTypeFilter = "video/*";
53 return;
54 }
56 if (aFilterMask & Ci.nsIFilePicker.filterAll) {
57 this._mimeTypeFilter = "*/*";
58 return;
59 }
61 /* From BaseFilePicker.cpp */
62 if (aFilterMask & Ci.nsIFilePicker.filterHTML) {
63 this.appendFilter("*.html; *.htm; *.shtml; *.xhtml");
64 }
65 if (aFilterMask & Ci.nsIFilePicker.filterText) {
66 this.appendFilter("*.txt; *.text");
67 }
69 if (aFilterMask & Ci.nsIFilePicker.filterXML) {
70 this.appendFilter("*.xml");
71 }
73 if (aFilterMask & Ci.nsIFilePicker.xulFilter) {
74 this.appendFilter("*.xul");
75 }
77 if (aFilterMask & Ci.nsIFilePicker.xulFilter) {
78 this.appendFilter("..apps");
79 }
80 },
82 appendFilter: function(title, filter) {
83 if (this._extensionsFilter)
84 this._extensionsFilter += ", ";
85 this._extensionsFilter += filter;
86 },
88 get defaultString() {
89 return this._defaultString;
90 },
92 set defaultString(defaultString) {
93 this._defaultString = defaultString;
94 },
96 get defaultExtension() {
97 return this._defaultExtension;
98 },
100 set defaultExtension(defaultExtension) {
101 this._defaultExtension = defaultExtension;
102 },
104 get filterIndex() {
105 return this._filterIndex;
106 },
108 set filterIndex(val) {
109 this._filterIndex = val;
110 },
112 get displayDirectory() {
113 return this._displayDirectory;
114 },
116 set displayDirectory(dir) {
117 this._displayDirectory = dir;
118 },
120 get file() {
121 if (!this._filePath) {
122 return null;
123 }
125 return new FileUtils.File(this._filePath);
126 },
128 get fileURL() {
129 let file = this.getFile();
130 return Services.io.newFileURI(file);
131 },
133 get files() {
134 return this.getEnumerator([this.file], function(file) {
135 return file;
136 });
137 },
139 get domfile() {
140 let f = this.file;
141 if (!f) {
142 return null;
143 }
144 return File(f);
145 },
147 get domfiles() {
148 return this.getEnumerator([this.file], function(file) {
149 return File(file);
150 });
151 },
153 get addToRecentDocs() {
154 return this._addToRecentDocs;
155 },
157 set addToRecentDocs(val) {
158 this._addToRecentDocs = val;
159 },
161 get mode() {
162 return this._mode;
163 },
165 show: function() {
166 if (this._domWin) {
167 this.fireDialogEvent(this._domWin, "DOMWillOpenModalDialog");
168 let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
169 winUtils.enterModalState();
170 }
172 this._promptActive = true;
173 this._sendMessage();
175 let thread = Services.tm.currentThread;
176 while (this._promptActive)
177 thread.processNextEvent(true);
178 delete this._promptActive;
180 if (this._domWin) {
181 let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
182 winUtils.leaveModalState();
183 this.fireDialogEvent(this._domWin, "DOMModalDialogClosed");
184 }
186 if (this._filePath)
187 return Ci.nsIFilePicker.returnOK;
189 return Ci.nsIFilePicker.returnCancel;
190 },
192 open: function(callback) {
193 this._callback = callback;
194 this._sendMessage();
195 },
197 _sendMessage: function() {
198 let msg = {
199 type: "FilePicker:Show",
200 guid: this.guid,
201 };
203 // Knowing the window lets us destroy any temp files when the tab is closed
204 // Other consumers of the file picker may have to either wait for Android
205 // to clean up the temp dir (not guaranteed) or clean up after themselves.
206 let win = Services.wm.getMostRecentWindow('navigator:browser');
207 let tab = win.BrowserApp.getTabForWindow(this._domWin.top)
208 if (tab) {
209 msg.tabId = tab.id;
210 }
212 if (!this._extensionsFilter && !this._mimeTypeFilter) {
213 // If neither filters is set show anything we can.
214 msg.mode = "mimeType";
215 msg.mimeType = "*/*";
216 } else if (this._extensionsFilter) {
217 msg.mode = "extension";
218 msg.extensions = this._extensionsFilter;
219 } else {
220 msg.mode = "mimeType";
221 msg.mimeType = this._mimeTypeFilter;
222 }
224 this.sendMessageToJava(msg);
225 },
227 sendMessageToJava: function(aMsg) {
228 Services.androidBridge.handleGeckoMessage(aMsg);
229 },
231 observe: function(aSubject, aTopic, aData) {
232 let data = JSON.parse(aData);
233 if (data.guid != this.guid)
234 return;
236 this._filePath = null;
237 if (data.file)
238 this._filePath = data.file;
240 this._promptActive = false;
242 if (this._callback) {
243 this._callback.done(this._filePath ? Ci.nsIFilePicker.returnOK : Ci.nsIFilePicker.returnCancel);
244 }
245 delete this._callback;
246 },
248 getEnumerator: function(files, mapFunction) {
249 return {
250 QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
251 mFiles: files,
252 mIndex: 0,
253 hasMoreElements: function() {
254 return (this.mIndex < this.mFiles.length);
255 },
256 getNext: function() {
257 if (this.mIndex >= this.mFiles.length) {
258 throw Components.results.NS_ERROR_FAILURE;
259 }
260 return mapFunction(this.mFiles[this.mIndex++]);
261 }
262 };
263 },
265 fireDialogEvent: function(aDomWin, aEventName) {
266 // accessing the document object can throw if this window no longer exists. See bug 789888.
267 try {
268 if (!aDomWin.document)
269 return;
270 let event = aDomWin.document.createEvent("Events");
271 event.initEvent(aEventName, true, true);
272 let winUtils = aDomWin.QueryInterface(Ci.nsIInterfaceRequestor)
273 .getInterface(Ci.nsIDOMWindowUtils);
274 winUtils.dispatchEventToChromeOnly(aDomWin, event);
275 } catch(ex) {
276 }
277 },
279 classID: Components.ID("{18a4e042-7c7c-424b-a583-354e68553a7f}"),
280 QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker, Ci.nsIObserver])
281 };
283 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FilePicker]);