diff options
Diffstat (limited to 'mobile/android/components/FilePicker.js')
-rw-r--r-- | mobile/android/components/FilePicker.js | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/mobile/android/components/FilePicker.js b/mobile/android/components/FilePicker.js new file mode 100644 index 000000000..2de81ca46 --- /dev/null +++ b/mobile/android/components/FilePicker.js @@ -0,0 +1,302 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cc = Components.classes; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/FileUtils.jsm"); + +Cu.importGlobalProperties(['File']); + +function FilePicker() { +} + +FilePicker.prototype = { + _mimeTypeFilter: 0, + _extensionsFilter: "", + _defaultString: "", + _domWin: null, + _defaultExtension: null, + _displayDirectory: null, + _filePath: null, + _promptActive: false, + _filterIndex: 0, + _addToRecentDocs: false, + _title: "", + + init: function(aParent, aTitle, aMode) { + this._domWin = aParent; + this._mode = aMode; + this._title = aTitle; + Services.obs.addObserver(this, "FilePicker:Result", false); + + let idService = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); + this.guid = idService.generateUUID().toString(); + + if (aMode != Ci.nsIFilePicker.modeOpen && aMode != Ci.nsIFilePicker.modeOpenMultiple) + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + }, + + appendFilters: function(aFilterMask) { + if (aFilterMask & Ci.nsIFilePicker.filterAudio) { + this._mimeTypeFilter = "audio/*"; + return; + } + + if (aFilterMask & Ci.nsIFilePicker.filterImages) { + this._mimeTypeFilter = "image/*"; + return; + } + + if (aFilterMask & Ci.nsIFilePicker.filterVideo) { + this._mimeTypeFilter = "video/*"; + return; + } + + if (aFilterMask & Ci.nsIFilePicker.filterAll) { + this._mimeTypeFilter = "*/*"; + return; + } + + /* From BaseFilePicker.cpp */ + if (aFilterMask & Ci.nsIFilePicker.filterHTML) { + this.appendFilter("*.html; *.htm; *.shtml; *.xhtml"); + } + if (aFilterMask & Ci.nsIFilePicker.filterText) { + this.appendFilter("*.txt; *.text"); + } + + if (aFilterMask & Ci.nsIFilePicker.filterXML) { + this.appendFilter("*.xml"); + } + + if (aFilterMask & Ci.nsIFilePicker.xulFilter) { + this.appendFilter("*.xul"); + } + + if (aFilterMask & Ci.nsIFilePicker.xulFilter) { + this.appendFilter("..apps"); + } + }, + + appendFilter: function(title, filter) { + if (this._extensionsFilter) + this._extensionsFilter += ", "; + this._extensionsFilter += filter; + }, + + get defaultString() { + return this._defaultString; + }, + + set defaultString(defaultString) { + this._defaultString = defaultString; + }, + + get defaultExtension() { + return this._defaultExtension; + }, + + set defaultExtension(defaultExtension) { + this._defaultExtension = defaultExtension; + }, + + get filterIndex() { + return this._filterIndex; + }, + + set filterIndex(val) { + this._filterIndex = val; + }, + + get displayDirectory() { + return this._displayDirectory; + }, + + set displayDirectory(dir) { + this._displayDirectory = dir; + }, + + get file() { + if (!this._filePath) { + return null; + } + + return new FileUtils.File(this._filePath); + }, + + get fileURL() { + let file = this.getFile(); + return Services.io.newFileURI(file); + }, + + get files() { + return this.getEnumerator([this.file], function(file) { + return file; + }); + }, + + // We don't support directory selection yet. + get domFileOrDirectory() { + let f = this.file; + if (!f) { + return null; + } + + let win = this._domWin; + if (win) { + let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); + return utils.wrapDOMFile(f); + } + + return File.createFromNsIFile(f); + }, + + get domFileOrDirectoryEnumerator() { + let win = this._domWin; + return this.getEnumerator([this.file], function(file) { + if (win) { + let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); + return utils.wrapDOMFile(file); + } + + return File.createFromNsIFile(file); + }); + }, + + get addToRecentDocs() { + return this._addToRecentDocs; + }, + + set addToRecentDocs(val) { + this._addToRecentDocs = val; + }, + + get mode() { + return this._mode; + }, + + show: function() { + if (this._domWin) { + this.fireDialogEvent(this._domWin, "DOMWillOpenModalDialog"); + let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); + winUtils.enterModalState(); + } + + this._promptActive = true; + this._sendMessage(); + + let thread = Services.tm.currentThread; + while (this._promptActive) + thread.processNextEvent(true); + delete this._promptActive; + + if (this._domWin) { + let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); + winUtils.leaveModalState(); + this.fireDialogEvent(this._domWin, "DOMModalDialogClosed"); + } + + if (this._filePath) + return Ci.nsIFilePicker.returnOK; + + return Ci.nsIFilePicker.returnCancel; + }, + + open: function(callback) { + this._callback = callback; + this._sendMessage(); + }, + + _sendMessage: function() { + let msg = { + type: "FilePicker:Show", + guid: this.guid, + title: this._title, + }; + + // Knowing the window lets us destroy any temp files when the tab is closed + // Other consumers of the file picker may have to either wait for Android + // to clean up the temp dir (not guaranteed) or clean up after themselves. + let win = Services.wm.getMostRecentWindow('navigator:browser'); + let tab = win.BrowserApp.getTabForWindow(this._domWin.top) + if (tab) { + msg.tabId = tab.id; + } + + if (!this._extensionsFilter && !this._mimeTypeFilter) { + // If neither filters is set show anything we can. + msg.mode = "mimeType"; + msg.mimeType = "*/*"; + } else if (this._extensionsFilter) { + msg.mode = "extension"; + msg.extensions = this._extensionsFilter; + } else { + msg.mode = "mimeType"; + msg.mimeType = this._mimeTypeFilter; + } + + this.sendMessageToJava(msg); + }, + + sendMessageToJava: function(aMsg) { + Services.androidBridge.handleGeckoMessage(aMsg); + }, + + observe: function(aSubject, aTopic, aData) { + let data = JSON.parse(aData); + if (data.guid != this.guid) + return; + + this._filePath = null; + if (data.file) + this._filePath = data.file; + + this._promptActive = false; + + if (this._callback) { + this._callback.done(this._filePath ? Ci.nsIFilePicker.returnOK : Ci.nsIFilePicker.returnCancel); + } + delete this._callback; + }, + + getEnumerator: function(files, mapFunction) { + return { + QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]), + mFiles: files, + mIndex: 0, + hasMoreElements: function() { + return (this.mIndex < this.mFiles.length); + }, + getNext: function() { + if (this.mIndex >= this.mFiles.length) { + throw Components.results.NS_ERROR_FAILURE; + } + return mapFunction(this.mFiles[this.mIndex++]); + } + }; + }, + + fireDialogEvent: function(aDomWin, aEventName) { + // accessing the document object can throw if this window no longer exists. See bug 789888. + try { + if (!aDomWin.document) + return; + let event = aDomWin.document.createEvent("Events"); + event.initEvent(aEventName, true, true); + let winUtils = aDomWin.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + winUtils.dispatchEventToChromeOnly(aDomWin, event); + } catch(ex) { + } + }, + + classID: Components.ID("{18a4e042-7c7c-424b-a583-354e68553a7f}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker, Ci.nsIObserver]) +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FilePicker]); |