1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/components/FilePicker.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,283 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +const Ci = Components.interfaces; 1.9 +const Cu = Components.utils; 1.10 +const Cc = Components.classes; 1.11 + 1.12 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.13 +Cu.import("resource://gre/modules/Services.jsm"); 1.14 +Cu.import("resource://gre/modules/FileUtils.jsm"); 1.15 + 1.16 +function FilePicker() { 1.17 +} 1.18 + 1.19 +FilePicker.prototype = { 1.20 + _mimeTypeFilter: 0, 1.21 + _extensionsFilter: "", 1.22 + _defaultString: "", 1.23 + _domWin: null, 1.24 + _defaultExtension: null, 1.25 + _displayDirectory: null, 1.26 + _filePath: null, 1.27 + _promptActive: false, 1.28 + _filterIndex: 0, 1.29 + _addToRecentDocs: false, 1.30 + 1.31 + init: function(aParent, aTitle, aMode) { 1.32 + this._domWin = aParent; 1.33 + this._mode = aMode; 1.34 + Services.obs.addObserver(this, "FilePicker:Result", false); 1.35 + 1.36 + let idService = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); 1.37 + this.guid = idService.generateUUID().toString(); 1.38 + 1.39 + if (aMode != Ci.nsIFilePicker.modeOpen && aMode != Ci.nsIFilePicker.modeOpenMultiple) 1.40 + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; 1.41 + }, 1.42 + 1.43 + appendFilters: function(aFilterMask) { 1.44 + if (aFilterMask & Ci.nsIFilePicker.filterAudio) { 1.45 + this._mimeTypeFilter = "audio/*"; 1.46 + return; 1.47 + } 1.48 + 1.49 + if (aFilterMask & Ci.nsIFilePicker.filterImages) { 1.50 + this._mimeTypeFilter = "image/*"; 1.51 + return; 1.52 + } 1.53 + 1.54 + if (aFilterMask & Ci.nsIFilePicker.filterVideo) { 1.55 + this._mimeTypeFilter = "video/*"; 1.56 + return; 1.57 + } 1.58 + 1.59 + if (aFilterMask & Ci.nsIFilePicker.filterAll) { 1.60 + this._mimeTypeFilter = "*/*"; 1.61 + return; 1.62 + } 1.63 + 1.64 + /* From BaseFilePicker.cpp */ 1.65 + if (aFilterMask & Ci.nsIFilePicker.filterHTML) { 1.66 + this.appendFilter("*.html; *.htm; *.shtml; *.xhtml"); 1.67 + } 1.68 + if (aFilterMask & Ci.nsIFilePicker.filterText) { 1.69 + this.appendFilter("*.txt; *.text"); 1.70 + } 1.71 + 1.72 + if (aFilterMask & Ci.nsIFilePicker.filterXML) { 1.73 + this.appendFilter("*.xml"); 1.74 + } 1.75 + 1.76 + if (aFilterMask & Ci.nsIFilePicker.xulFilter) { 1.77 + this.appendFilter("*.xul"); 1.78 + } 1.79 + 1.80 + if (aFilterMask & Ci.nsIFilePicker.xulFilter) { 1.81 + this.appendFilter("..apps"); 1.82 + } 1.83 + }, 1.84 + 1.85 + appendFilter: function(title, filter) { 1.86 + if (this._extensionsFilter) 1.87 + this._extensionsFilter += ", "; 1.88 + this._extensionsFilter += filter; 1.89 + }, 1.90 + 1.91 + get defaultString() { 1.92 + return this._defaultString; 1.93 + }, 1.94 + 1.95 + set defaultString(defaultString) { 1.96 + this._defaultString = defaultString; 1.97 + }, 1.98 + 1.99 + get defaultExtension() { 1.100 + return this._defaultExtension; 1.101 + }, 1.102 + 1.103 + set defaultExtension(defaultExtension) { 1.104 + this._defaultExtension = defaultExtension; 1.105 + }, 1.106 + 1.107 + get filterIndex() { 1.108 + return this._filterIndex; 1.109 + }, 1.110 + 1.111 + set filterIndex(val) { 1.112 + this._filterIndex = val; 1.113 + }, 1.114 + 1.115 + get displayDirectory() { 1.116 + return this._displayDirectory; 1.117 + }, 1.118 + 1.119 + set displayDirectory(dir) { 1.120 + this._displayDirectory = dir; 1.121 + }, 1.122 + 1.123 + get file() { 1.124 + if (!this._filePath) { 1.125 + return null; 1.126 + } 1.127 + 1.128 + return new FileUtils.File(this._filePath); 1.129 + }, 1.130 + 1.131 + get fileURL() { 1.132 + let file = this.getFile(); 1.133 + return Services.io.newFileURI(file); 1.134 + }, 1.135 + 1.136 + get files() { 1.137 + return this.getEnumerator([this.file], function(file) { 1.138 + return file; 1.139 + }); 1.140 + }, 1.141 + 1.142 + get domfile() { 1.143 + let f = this.file; 1.144 + if (!f) { 1.145 + return null; 1.146 + } 1.147 + return File(f); 1.148 + }, 1.149 + 1.150 + get domfiles() { 1.151 + return this.getEnumerator([this.file], function(file) { 1.152 + return File(file); 1.153 + }); 1.154 + }, 1.155 + 1.156 + get addToRecentDocs() { 1.157 + return this._addToRecentDocs; 1.158 + }, 1.159 + 1.160 + set addToRecentDocs(val) { 1.161 + this._addToRecentDocs = val; 1.162 + }, 1.163 + 1.164 + get mode() { 1.165 + return this._mode; 1.166 + }, 1.167 + 1.168 + show: function() { 1.169 + if (this._domWin) { 1.170 + this.fireDialogEvent(this._domWin, "DOMWillOpenModalDialog"); 1.171 + let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); 1.172 + winUtils.enterModalState(); 1.173 + } 1.174 + 1.175 + this._promptActive = true; 1.176 + this._sendMessage(); 1.177 + 1.178 + let thread = Services.tm.currentThread; 1.179 + while (this._promptActive) 1.180 + thread.processNextEvent(true); 1.181 + delete this._promptActive; 1.182 + 1.183 + if (this._domWin) { 1.184 + let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); 1.185 + winUtils.leaveModalState(); 1.186 + this.fireDialogEvent(this._domWin, "DOMModalDialogClosed"); 1.187 + } 1.188 + 1.189 + if (this._filePath) 1.190 + return Ci.nsIFilePicker.returnOK; 1.191 + 1.192 + return Ci.nsIFilePicker.returnCancel; 1.193 + }, 1.194 + 1.195 + open: function(callback) { 1.196 + this._callback = callback; 1.197 + this._sendMessage(); 1.198 + }, 1.199 + 1.200 + _sendMessage: function() { 1.201 + let msg = { 1.202 + type: "FilePicker:Show", 1.203 + guid: this.guid, 1.204 + }; 1.205 + 1.206 + // Knowing the window lets us destroy any temp files when the tab is closed 1.207 + // Other consumers of the file picker may have to either wait for Android 1.208 + // to clean up the temp dir (not guaranteed) or clean up after themselves. 1.209 + let win = Services.wm.getMostRecentWindow('navigator:browser'); 1.210 + let tab = win.BrowserApp.getTabForWindow(this._domWin.top) 1.211 + if (tab) { 1.212 + msg.tabId = tab.id; 1.213 + } 1.214 + 1.215 + if (!this._extensionsFilter && !this._mimeTypeFilter) { 1.216 + // If neither filters is set show anything we can. 1.217 + msg.mode = "mimeType"; 1.218 + msg.mimeType = "*/*"; 1.219 + } else if (this._extensionsFilter) { 1.220 + msg.mode = "extension"; 1.221 + msg.extensions = this._extensionsFilter; 1.222 + } else { 1.223 + msg.mode = "mimeType"; 1.224 + msg.mimeType = this._mimeTypeFilter; 1.225 + } 1.226 + 1.227 + this.sendMessageToJava(msg); 1.228 + }, 1.229 + 1.230 + sendMessageToJava: function(aMsg) { 1.231 + Services.androidBridge.handleGeckoMessage(aMsg); 1.232 + }, 1.233 + 1.234 + observe: function(aSubject, aTopic, aData) { 1.235 + let data = JSON.parse(aData); 1.236 + if (data.guid != this.guid) 1.237 + return; 1.238 + 1.239 + this._filePath = null; 1.240 + if (data.file) 1.241 + this._filePath = data.file; 1.242 + 1.243 + this._promptActive = false; 1.244 + 1.245 + if (this._callback) { 1.246 + this._callback.done(this._filePath ? Ci.nsIFilePicker.returnOK : Ci.nsIFilePicker.returnCancel); 1.247 + } 1.248 + delete this._callback; 1.249 + }, 1.250 + 1.251 + getEnumerator: function(files, mapFunction) { 1.252 + return { 1.253 + QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]), 1.254 + mFiles: files, 1.255 + mIndex: 0, 1.256 + hasMoreElements: function() { 1.257 + return (this.mIndex < this.mFiles.length); 1.258 + }, 1.259 + getNext: function() { 1.260 + if (this.mIndex >= this.mFiles.length) { 1.261 + throw Components.results.NS_ERROR_FAILURE; 1.262 + } 1.263 + return mapFunction(this.mFiles[this.mIndex++]); 1.264 + } 1.265 + }; 1.266 + }, 1.267 + 1.268 + fireDialogEvent: function(aDomWin, aEventName) { 1.269 + // accessing the document object can throw if this window no longer exists. See bug 789888. 1.270 + try { 1.271 + if (!aDomWin.document) 1.272 + return; 1.273 + let event = aDomWin.document.createEvent("Events"); 1.274 + event.initEvent(aEventName, true, true); 1.275 + let winUtils = aDomWin.QueryInterface(Ci.nsIInterfaceRequestor) 1.276 + .getInterface(Ci.nsIDOMWindowUtils); 1.277 + winUtils.dispatchEventToChromeOnly(aDomWin, event); 1.278 + } catch(ex) { 1.279 + } 1.280 + }, 1.281 + 1.282 + classID: Components.ID("{18a4e042-7c7c-424b-a583-354e68553a7f}"), 1.283 + QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker, Ci.nsIObserver]) 1.284 +}; 1.285 + 1.286 +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FilePicker]);