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/. */
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++).
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.)
20 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
22 // FIXME: improve this list of filters.
23 const IMAGE_FILTERS = ['image/gif', 'image/jpeg', 'image/pjpeg',
24 'image/png', 'image/svg+xml', 'image/tiff',
25 'image/vnd.microsoft.icon'];
26 const VIDEO_FILTERS = ['video/mpeg', 'video/mp4', 'video/ogg',
27 'video/quicktime', 'video/webm', 'video/x-matroska',
28 'video/x-ms-wmv', 'video/x-flv'];
29 const AUDIO_FILTERS = ['audio/basic', 'audio/L24', 'audio/mp4',
30 'audio/mpeg', 'audio/ogg', 'audio/vorbis',
31 'audio/vnd.rn-realaudio', 'audio/vnd.wave',
34 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
36 XPCOMUtils.defineLazyServiceGetter(this, 'cpmm',
37 '@mozilla.org/childprocessmessagemanager;1',
40 function FilePicker() {
43 FilePicker.prototype = {
44 classID: Components.ID('{436ff8f9-0acc-4b11-8ec7-e293efba3141}'),
45 QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker]),
51 mFileEnumerator: undefined,
52 mFilePickerShownCallback: undefined,
56 init: function(parent, title, mode) {
57 this.mParent = parent;
59 if (mode != Ci.nsIFilePicker.modeOpen &&
60 mode != Ci.nsIFilePicker.modeOpenMultiple) {
61 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
65 /* readonly attribute nsILocalFile file - not implemented; */
66 /* readonly attribute nsISimpleEnumerator files - not implemented; */
67 /* readonly attribute nsIURI fileURL - not implemented; */
70 return this.mFilesEnumerator;
74 return this.mFilesEnumerator ? this.mFilesEnumerator.mFiles[0] : null;
77 appendFilters: function(filterMask) {
78 // Ci.nsIFilePicker.filterHTML is not supported
79 // Ci.nsIFilePicker.filterText is not supported
81 if (filterMask & Ci.nsIFilePicker.filterImages) {
82 this.mFilterTypes = this.mFilterTypes.concat(IMAGE_FILTERS);
85 // Ci.nsIFilePicker.filterXML is not supported
86 // Ci.nsIFilePicker.filterXUL is not supported
87 // Ci.nsIFilePicker.filterApps is not supported
88 // Ci.nsIFilePicker.filterAllowURLs is not supported
90 if (filterMask & Ci.nsIFilePicker.filterVideo) {
91 this.mFilterTypes = this.mFilterTypes.concat(VIDEO_FILTERS);
94 if (filterMask & Ci.nsIFilePicker.filterAudio) {
95 this.mFilterTypes = this.mFilterTypes.concat(AUDIO_FILTERS);
98 // Ci.nsIFilePicker.filterAll is by default
101 appendFilter: function(title, extensions) {
102 // pick activity doesn't support extensions
105 open: function(aFilePickerShownCallback) {
106 this.mFilePickerShownCallback = aFilePickerShownCallback;
108 cpmm.addMessageListener('file-picked', this);
111 if (this.mFilterTypes) {
112 detail.type = this.mFilterTypes;
115 cpmm.sendAsyncMessage('file-picker', detail);
118 fireSuccess: function(file) {
119 this.mFilesEnumerator = {
120 QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
125 hasMoreElements: function() {
126 return (this.mIndex < this.mFiles.length);
129 getNext: function() {
130 if (this.mIndex >= this.mFiles.length) {
131 throw Components.results.NS_ERROR_FAILURE;
133 return this.mFiles[this.mIndex++];
137 if (this.mFilePickerShownCallback) {
138 this.mFilePickerShownCallback.done(Ci.nsIFilePicker.returnOK);
139 this.mFilePickerShownCallback = null;
143 fireError: function() {
144 if (this.mFilePickerShownCallback) {
145 this.mFilePickerShownCallback.done(Ci.nsIFilePicker.returnCancel);
146 this.mFilePickerShownCallback = null;
150 receiveMessage: function(message) {
151 if (message.name !== 'file-picked') {
155 cpmm.removeMessageListener('file-picked', this);
157 let data = message.data;
158 if (!data.success || !data.result.blob) {
163 var mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
164 var mimeInfo = mimeSvc.getFromTypeAndExtension(data.result.blob.type, '');
168 name += '.' + mimeInfo.primaryExtension;
171 let file = new this.mParent.File(data.result.blob,
173 type: data.result.blob.type });
175 this.fireSuccess(file);
182 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FilePicker]);