b2g/components/FilePicker.js

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     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/. */
     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  */
    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',
    32                        'audio/webm'];
    34 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
    35 Cu.import("resource://gre/modules/osfile.jsm");
    37 XPCOMUtils.defineLazyServiceGetter(this, 'cpmm',
    38                                    '@mozilla.org/childprocessmessagemanager;1',
    39                                    'nsIMessageSender');
    41 function FilePicker() {
    42 }
    44 FilePicker.prototype = {
    45   classID: Components.ID('{436ff8f9-0acc-4b11-8ec7-e293efba3141}'),
    46   QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker]),
    48   /* members */
    50   mParent: undefined,
    51   mExtraProps: undefined,
    52   mFilterTypes: undefined,
    53   mFileEnumerator: undefined,
    54   mFilePickerShownCallback: undefined,
    56   /* methods */
    58   init: function(parent, title, mode) {
    59     this.mParent = parent;
    60     this.mExtraProps = {};
    61     this.mFilterTypes = [];
    62     this.mMode = mode;
    64     if (mode != Ci.nsIFilePicker.modeOpen &&
    65         mode != Ci.nsIFilePicker.modeOpenMultiple) {
    66       throw Cr.NS_ERROR_NOT_IMPLEMENTED;
    67     }
    68   },
    70   /* readonly attribute nsILocalFile file - not implemented; */
    71   /* readonly attribute nsISimpleEnumerator files - not implemented; */
    72   /* readonly attribute nsIURI fileURL - not implemented; */
    74   get domfiles() {
    75     return this.mFilesEnumerator;
    76   },
    78   get domfile() {
    79     return this.mFilesEnumerator ? this.mFilesEnumerator.mFiles[0] : null;
    80   },
    82   get mode() {
    83     return this.mMode;
    84   },
    86   appendFilters: function(filterMask) {
    87     // Ci.nsIFilePicker.filterHTML is not supported
    88     // Ci.nsIFilePicker.filterText is not supported
    90     if (filterMask & Ci.nsIFilePicker.filterImages) {
    91       this.mFilterTypes = this.mFilterTypes.concat(IMAGE_FILTERS);
    92       // This property is needed for the gallery app pick activity.
    93       this.mExtraProps['nocrop'] = true;
    94     }
    96     // Ci.nsIFilePicker.filterXML is not supported
    97     // Ci.nsIFilePicker.filterXUL is not supported
    98     // Ci.nsIFilePicker.filterApps is not supported
    99     // Ci.nsIFilePicker.filterAllowURLs is not supported
   101     if (filterMask & Ci.nsIFilePicker.filterVideo) {
   102       this.mFilterTypes = this.mFilterTypes.concat(VIDEO_FILTERS);
   103     }
   105     if (filterMask & Ci.nsIFilePicker.filterAudio) {
   106       this.mFilterTypes = this.mFilterTypes.concat(AUDIO_FILTERS);
   107     }
   109     if (filterMask & Ci.nsIFilePicker.filterAll) {
   110       // This property is needed for the gallery app pick activity.
   111       this.mExtraProps['nocrop'] = true;
   112     }
   113   },
   115   appendFilter: function(title, extensions) {
   116     // pick activity doesn't support extensions
   117   },
   119   open: function(aFilePickerShownCallback) {
   120     this.mFilePickerShownCallback = aFilePickerShownCallback;
   122     cpmm.addMessageListener('file-picked', this);
   124     let detail = {};
   125     if (this.mFilterTypes) {
   126        detail.type = this.mFilterTypes;
   127     }
   129     for (let prop in this.mExtraProps) {
   130       if (!(prop in detail)) {
   131         detail[prop] = this.mExtraProps[prop];
   132       }
   133     }
   135     cpmm.sendAsyncMessage('file-picker', detail);
   136   },
   138   fireSuccess: function(file) {
   139     this.mFilesEnumerator = {
   140       QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
   142       mFiles: [file],
   143       mIndex: 0,
   145       hasMoreElements: function() {
   146         return (this.mIndex < this.mFiles.length);
   147       },
   149       getNext: function() {
   150         if (this.mIndex >= this.mFiles.length) {
   151           throw Components.results.NS_ERROR_FAILURE;
   152         }
   153         return this.mFiles[this.mIndex++];
   154       }
   155     };
   157     if (this.mFilePickerShownCallback) {
   158       this.mFilePickerShownCallback.done(Ci.nsIFilePicker.returnOK);
   159       this.mFilePickerShownCallback = null;
   160     }
   161   },
   163   fireError: function() {
   164     if (this.mFilePickerShownCallback) {
   165       this.mFilePickerShownCallback.done(Ci.nsIFilePicker.returnCancel);
   166       this.mFilePickerShownCallback = null;
   167     }
   168   },
   170   receiveMessage: function(message) {
   171     if (message.name !== 'file-picked') {
   172       return;
   173     }
   175     cpmm.removeMessageListener('file-picked', this);
   177     let data = message.data;
   178     if (!data.success || !data.result.blob) {
   179       this.fireError();
   180       return;
   181     }
   183     // The name to be shown can be part of the message, or can be taken from
   184     // the DOMFile (if the blob is a DOMFile).
   185     let name = data.result.name;
   186     if (!name &&
   187         (data.result.blob instanceof this.mParent.File) &&
   188         data.result.blob.name) {
   189       name = data.result.blob.name;
   190     }
   192     // Let's try to remove the full path and take just the filename.
   193     if (name) {
   194       let names = OS.Path.split(name);
   195       name = names.components[names.components.length - 1];
   196     }
   198     // the fallback is a filename composed by 'blob' + extension.
   199     if (!name) {
   200       name = 'blob';
   201       if (data.result.blob.type) {
   202         let mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
   203         let mimeInfo = mimeSvc.getFromTypeAndExtension(data.result.blob.type, '');
   204         if (mimeInfo) {
   205           name += '.' + mimeInfo.primaryExtension;
   206         }
   207       }
   208     }
   210     let file = new this.mParent.File(data.result.blob,
   211                                      { name: name,
   212                                        type: data.result.blob.type });
   214     if (file) {
   215       this.fireSuccess(file);
   216     } else {
   217       this.fireError();
   218     }
   219   }
   220 };
   222 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FilePicker]);

mercurial