home *** CD-ROM | disk | FTP | other *** search
/ Freelog 112 / FreelogNo112-NovembreDecembre2012.iso / Multimedia / Songbird / Songbird_2.0.0-2311_windows-i686-msvc8.exe / jsmodules / sbAddToDevice.jsm < prev    next >
Text File  |  2012-06-08  |  20KB  |  646 lines

  1. /*
  2.  *=BEGIN SONGBIRD GPL
  3.  *
  4.  * This file is part of the Songbird web player.
  5.  *
  6.  * Copyright(c) 2005-2010 POTI, Inc.
  7.  * http://www.songbirdnest.com
  8.  *
  9.  * This file may be licensed under the terms of of the
  10.  * GNU General Public License Version 2 (the ``GPL'').
  11.  *
  12.  * Software distributed under the License is distributed
  13.  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
  14.  * express or implied. See the GPL for the specific language
  15.  * governing rights and limitations.
  16.  *
  17.  * You should have received a copy of the GPL along with this
  18.  * program. If not, go to http://www.gnu.org/licenses/gpl.html
  19.  * or write to the Free Software Foundation, Inc.,
  20.  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21.  *
  22.  *=END SONGBIRD GPL
  23.  */
  24.  
  25. Components.utils.import("resource://app/jsmodules/sbProperties.jsm");
  26. Components.utils.import("resource://app/jsmodules/DropHelper.jsm");
  27. Components.utils.import("resource://app/jsmodules/sbLibraryUtils.jsm");
  28. Components.utils.import("resource://app/jsmodules/SBUtils.jsm");
  29. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  30.  
  31.  
  32. const Ci = Components.interfaces;
  33. const Cc = Components.classes;
  34. const Cr = Components.results;
  35.  
  36. const SB_MEDIALISTDUPLICATEFILTER_CONTRACTID =
  37.   "@songbirdnest.com/Songbird/Library/medialistduplicatefilter;1";
  38.  
  39. const ADDTODEVICE_MENU_TYPE      = "submenu";
  40. const ADDTODEVICE_MENU_ID        = "library_cmd_addtodevice";
  41. const ADDTODEVICE_MENU_NAME      = "&command.addtodevice";
  42. const ADDTODEVICE_MENU_TOOLTIP   = "&command.tooltip.addtodevice";
  43. const ADDTODEVICE_MENU_KEY       = "&command.shortcut.key.addtodevice";
  44. const ADDTODEVICE_MENU_KEYCODE   = "&command.shortcut.keycode.addtodevice";
  45. const ADDTODEVICE_MENU_MODIFIERS = "&command.shortcut.modifiers.addtodevice";
  46.  
  47.  
  48. const ADDTODEVICE_COMMAND_ID = "library_cmd_addtodevice:";
  49.  
  50. EXPORTED_SYMBOLS = [ "addToDeviceHelper",
  51.                      "SBPlaylistCommand_AddToDevice" ];
  52.  
  53. /**
  54.  * \brief Creates a new unwrapper helper object which ensures
  55.  *        downloadStatusTarget is always set when adding items
  56.  *        to another library or playlist on a device.
  57.  * \param aSelection An sbIMediaListViewSelection.selectedMediaItems enumerator
  58.  * \return A new unwrapper helper object.
  59.  */
  60. function createUnwrapper(aSelection) {
  61.   var unwrapper = Cc["@songbirdnest.com/Songbird/Library/EnumeratorWrapper;1"]
  62.                     .createInstance(Ci.sbIMediaListEnumeratorWrapper);
  63.   unwrapper.initialize(aSelection);
  64.  
  65.   return unwrapper;
  66. }
  67.  
  68. // ----------------------------------------------------------------------------
  69. // The "Add to device" dynamic command object
  70. // ----------------------------------------------------------------------------
  71. var SBPlaylistCommand_AddToDevice =
  72. {
  73.   m_Context: {
  74.     m_Playlist: null,
  75.     m_Window: null
  76.   },
  77.  
  78.   m_addToDevice: null,
  79.  
  80.   m_root_commands :
  81.   {
  82.     m_Types: new Array
  83.     (
  84.       ADDTODEVICE_MENU_TYPE
  85.     ),
  86.  
  87.     m_Ids: new Array
  88.     (
  89.       ADDTODEVICE_MENU_ID
  90.     ),
  91.  
  92.     m_Names: new Array
  93.     (
  94.       ADDTODEVICE_MENU_NAME
  95.     ),
  96.  
  97.     m_Tooltips: new Array
  98.     (
  99.       ADDTODEVICE_MENU_TOOLTIP
  100.     ),
  101.  
  102.     m_Keys: new Array
  103.     (
  104.       ADDTODEVICE_MENU_KEY
  105.     ),
  106.  
  107.     m_Keycodes: new Array
  108.     (
  109.       ADDTODEVICE_MENU_KEYCODE
  110.     ),
  111.  
  112.     m_Enableds: new Array
  113.     (
  114.       true
  115.     ),
  116.  
  117.     m_Modifiers: new Array
  118.     (
  119.       ADDTODEVICE_MENU_MODIFIERS
  120.     ),
  121.  
  122.     m_PlaylistCommands: new Array
  123.     (
  124.       null
  125.     ),
  126.  
  127.     m_DeviceIds: new Array
  128.     (
  129.       null
  130.     )
  131.   },
  132.  
  133.   _getMenu: function(aSubMenu)
  134.   {
  135.     var cmds;
  136.  
  137.     cmds = this.m_addToDevice.handleGetMenu(aSubMenu);
  138.     if (cmds) return cmds;
  139.  
  140.     switch (aSubMenu) {
  141.       default:
  142.         cmds = this.m_root_commands;
  143.         break;
  144.     }
  145.     return cmds;
  146.   },
  147.  
  148.   getVisible: function( aHost )
  149.   {
  150.     return this.m_addToDevice.hasDevices();
  151.   },
  152.  
  153.   getNumCommands: function( aSubMenu, aHost )
  154.   {
  155.     var cmds = this._getMenu(aSubMenu);
  156.     return cmds.m_Ids.length;
  157.   },
  158.  
  159.   getCommandId: function( aSubMenu, aIndex, aHost )
  160.   {
  161.     var cmds = this._getMenu(aSubMenu);
  162.     if ( aIndex >= cmds.m_Ids.length ) return "";
  163.     return cmds.m_Ids[ aIndex ];
  164.   },
  165.  
  166.   getCommandType: function( aSubMenu, aIndex, aHost )
  167.   {
  168.     var cmds = this._getMenu(aSubMenu);
  169.     if ( aIndex >= cmds.m_Ids.length ) return "";
  170.     return cmds.m_Types[ aIndex ];
  171.   },
  172.  
  173.   getCommandText: function( aSubMenu, aIndex, aHost )
  174.   {
  175.     var cmds = this._getMenu(aSubMenu);
  176.     if ( aIndex >= cmds.m_Names.length ) return "";
  177.     return cmds.m_Names[ aIndex ];
  178.   },
  179.  
  180.   getCommandFlex: function( aSubMenu, aIndex, aHost )
  181.   {
  182.     var cmds = this._getMenu(aSubMenu);
  183.     if ( cmds.m_Types[ aIndex ] == "separator" ) return 1;
  184.     return 0;
  185.   },
  186.  
  187.   getCommandToolTipText: function( aSubMenu, aIndex, aHost )
  188.   {
  189.     var cmds = this._getMenu(aSubMenu);
  190.     if ( aIndex >= cmds.m_Tooltips.length ) return "";
  191.     return cmds.m_Tooltips[ aIndex ];
  192.   },
  193.  
  194.   getCommandValue: function( aSubMenu, aIndex, aHost )
  195.   {
  196.   },
  197.  
  198.   instantiateCustomCommand: function( aDocument, aId, aHost )
  199.   {
  200.     return null;
  201.   },
  202.  
  203.   refreshCustomCommand: function( aElement, aId, aHost )
  204.   {
  205.   },
  206.  
  207.   getCommandVisible: function( aSubMenu, aIndex, aHost )
  208.   {
  209.     return true;
  210.   },
  211.  
  212.   getCommandFlag: function( aSubmenu, aIndex, aHost )
  213.   {
  214.     return false;
  215.   },
  216.  
  217.   getCommandChoiceItem: function( aChoiceMenu, aHost )
  218.   {
  219.     return "";
  220.   },
  221.  
  222.   getCommandEnabled: function( aSubMenu, aIndex, aHost )
  223.   {
  224.     if (this.m_Context.m_Playlist.tree.currentIndex == -1) return false;
  225.  
  226.     var cmds = this._getMenu(aSubMenu);
  227.     if (aSubMenu == ADDTODEVICE_MENU_ID) {
  228.       var deviceRegistrar =
  229.         Components.classes["@songbirdnest.com/Songbird/DeviceManager;2"]
  230.                   .getService(Components.interfaces.sbIDeviceRegistrar);
  231.  
  232.       var device = deviceRegistrar.getDevice(cmds.m_DeviceIds[aIndex]);
  233.       if (device.state == Components.interfaces.sbIDevice.STATE_MOUNTING) {
  234.         // Don't enable the device command if the device is
  235.         // currently mounting.
  236.         return false;
  237.       }
  238.     }
  239.  
  240.     return cmds.m_Enableds[ aIndex ];
  241.   },
  242.  
  243.   getCommandShortcutModifiers: function ( aSubMenu, aIndex, aHost )
  244.   {
  245.     var cmds = this._getMenu(aSubMenu);
  246.     if ( aIndex >= cmds.m_Modifiers.length ) return "";
  247.     return cmds.m_Modifiers[ aIndex ];
  248.   },
  249.  
  250.   getCommandShortcutKey: function ( aSubMenu, aIndex, aHost )
  251.   {
  252.     var cmds = this._getMenu(aSubMenu);
  253.     if ( aIndex >= cmds.m_Keys.length ) return "";
  254.     return cmds.m_Keys[ aIndex ];
  255.   },
  256.  
  257.   getCommandShortcutKeycode: function ( aSubMenu, aIndex, aHost )
  258.   {
  259.     var cmds = this._getMenu(aSubMenu);
  260.     if ( aIndex >= cmds.m_Keycodes.length ) return "";
  261.     return cmds.m_Keycodes[ aIndex ];
  262.   },
  263.  
  264.   getCommandShortcutLocal: function ( aSubMenu, aIndex, aHost )
  265.   {
  266.     return true;
  267.   },
  268.  
  269.   getCommandSubObject: function ( aSubMenu, aIndex, aHost )
  270.   {
  271.     var cmds = this._getMenu(aSubMenu);
  272.     if ( aIndex >= cmds.m_PlaylistCommands.length ) return null;
  273.     return cmds.m_PlaylistCommands[ aIndex ];
  274.   },
  275.  
  276.   onCommand: function( aSubMenu, aIndex, aHost, id, value )
  277.   {
  278.     if ( id )
  279.     {
  280.       // ADDTODEVICE
  281.       if (this.m_addToDevice.handleCommand(id)) return;
  282.  
  283.       // ...
  284.     }
  285.   },
  286.  
  287.   // The object registered with the sbIPlaylistCommandsManager interface acts
  288.   // as a template for instances bound to specific playlist elements
  289.  
  290.   dupObject: function (obj) {
  291.     var r = {};
  292.     for ( var i in obj )
  293.     {
  294.       r[ i ] = obj[ i ];
  295.     }
  296.     return r;
  297.   },
  298.  
  299.   duplicate: function()
  300.   {
  301.     var obj = this.dupObject(this);
  302.     obj.m_Context = this.dupObject(this.m_Context);
  303.     return obj;
  304.   },
  305.  
  306.   initCommands: function(aHost) {
  307.     if (!this.m_addToDevice) {
  308.       this.m_addToDevice = new addToDeviceHelper();
  309.       this.m_addToDevice.init(this);
  310.     }
  311.   },
  312.  
  313.   shutdownCommands: function() {
  314.     if (!this.m_addToDevice) {
  315.       dump("this.m_addToDevice is null in SBPlaylistCommand_AddToDevice ?!!\n");
  316.       return;
  317.     }
  318.     this.m_addToDevice.shutdown();
  319.     this.m_addToDevice = null;
  320.     this.m_Context = null;
  321.   },
  322.  
  323.   setContext: function( context )
  324.   {
  325.     var playlist = context.playlist;
  326.     var window = context.window;
  327.  
  328.     // Ah.  Sometimes, things are being secure.
  329.  
  330.     if ( playlist && playlist.wrappedJSObject )
  331.       playlist = playlist.wrappedJSObject;
  332.  
  333.     if ( window && window.wrappedJSObject )
  334.       window = window.wrappedJSObject;
  335.  
  336.     this.m_Context.m_Playlist = playlist;
  337.     this.m_Context.m_Window = window;
  338.   },
  339.  
  340.   QueryInterface : function(aIID)
  341.   {
  342.     if (!aIID.equals(Components.interfaces.sbIPlaylistCommands) &&
  343.         !aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
  344.         !aIID.equals(Components.interfaces.nsISupports))
  345.     {
  346.       throw Components.results.NS_ERROR_NO_INTERFACE;
  347.     }
  348.  
  349.     return this;
  350.   }
  351. }; // SBPlaylistCommand_AddToDevice declaration
  352.  
  353. function addToDeviceHelper() {
  354. }
  355.  
  356. addToDeviceHelper.prototype = {
  357.   m_listofdevices: null,
  358.   m_commands: null,
  359.   m_deviceManager: null,
  360.   m_libraryManager: null,
  361.  
  362.   LOG: function(str) {
  363.     var consoleService = Components.classes['@mozilla.org/consoleservice;1']
  364.                             .getService(Components.interfaces.nsIConsoleService);
  365.     consoleService.logStringMessage(str);
  366.   },
  367.  
  368.   init: function addToDeviceHelper_init(aCommands) {
  369.     this.m_libraryManager =
  370.       Components.classes["@songbirdnest.com/Songbird/library/Manager;1"]
  371.       .getService(Components.interfaces.sbILibraryManager);
  372.     this.m_deviceManager =
  373.       Components.classes["@songbirdnest.com/Songbird/DeviceManager;2"]
  374.       .getService(Components.interfaces.sbIDeviceManager2);
  375.     var eventTarget =
  376.       this.m_deviceManager.QueryInterface(
  377.         Components.interfaces.sbIDeviceEventTarget
  378.       );
  379.     eventTarget.addEventListener(this);
  380.     this.m_commands = aCommands;
  381.     this.makeListOfDevices();
  382.   },
  383.  
  384.   shutdown: function addToDeviceHelper_shutdown() {
  385.     var eventTarget =
  386.       this.m_deviceManager.QueryInterface(
  387.         Components.interfaces.sbIDeviceEventTarget
  388.       );
  389.     eventTarget.removeEventListener(this);
  390.     this.m_deviceManager = null;
  391.   },
  392.  
  393.   // returns true if we have at least one device in the list,
  394.   // the commands object hides the "add to device" submenu when
  395.   // no device is present
  396.   hasDevices: function addToDeviceHelper_hasDevices() {
  397.     return (this.m_listofdevices &&
  398.             this.m_listofdevices.m_Types &&
  399.             this.m_listofdevices.m_Types.length > 0);
  400.   },
  401.  
  402.   // builds the list of devices, called on startup and when a
  403.   // device is added or removed
  404.   makeListOfDevices: function addToDeviceHelper_makeListOfDevices() {
  405.     this._makingList = true;
  406.  
  407.     this.m_listofdevices = {};
  408.     this.m_listofdevices.m_Types = new Array();
  409.     this.m_listofdevices.m_Ids = new Array();
  410.     this.m_listofdevices.m_Names = new Array();
  411.     this.m_listofdevices.m_Tooltips = new Array();
  412.     this.m_listofdevices.m_Enableds = new Array();
  413.     this.m_listofdevices.m_Modifiers = new Array();
  414.     this.m_listofdevices.m_Keys = new Array();
  415.     this.m_listofdevices.m_Keycodes = new Array();
  416.     this.m_listofdevices.m_PlaylistCommands = new Array();
  417.     this.m_listofdevices.m_DeviceIds = new Array();
  418.  
  419.     // get all devices
  420.     var registrar =
  421.       this.m_deviceManager.QueryInterface(
  422.         Components.interfaces.sbIDeviceRegistrar
  423.       );
  424.     var devices = Array();
  425.     // turn into a js array
  426.     for (var i=0;i<registrar.devices.length;i++) {
  427.       var device = registrar.devices.queryElementAt
  428.                                        (i, Components.interfaces.sbIDevice);
  429.       if (device && device.connected)
  430.         devices.push(device);
  431.     }
  432.     // order of devices returned by the registrar is undefined,
  433.     // so sort by device name
  434.     function deviceSorter(x, y) {
  435.       var nameX = x.name;
  436.       var nameY = y.name;
  437.       if (x < y) return -1;
  438.       if (y < x) return 1;
  439.       return 0;
  440.     }
  441.     devices.sort(deviceSorter);
  442.     // extract the device names and associated library guids
  443.     // and fill the arrays used by the command object
  444.     for (var d in devices) {
  445.       var libraryguid;
  446.       var device = devices[d];
  447.       var devicename = device.name;
  448.  
  449.       // don't add devices that are read-only
  450.       var deviceProperties = device.properties.properties;
  451.       var accessCompatibility;
  452.       try {
  453.         accessCompatibility = deviceProperties.getPropertyAsAString(
  454.             "http://songbirdnest.com/device/1.0#accessCompatibility");
  455.       } catch (ex) {}
  456.       if (accessCompatibility == "ro") {
  457.         continue;
  458.       }
  459.  
  460.       var isEnabled = false;
  461.       if (!devicename)
  462.         devicename = "Unnamed Device";
  463.       var library = device.defaultLibrary;
  464.       if (library) {
  465.         isEnabled = library.userEditable;
  466.         libraryguid = library.guid;
  467.       } else {
  468.         continue;
  469.       }
  470.       this.m_listofdevices.m_Types.push("action");
  471.       this.m_listofdevices.m_Ids.push(ADDTODEVICE_COMMAND_ID +
  472.                                       libraryguid + ";" +
  473.                                       devicename);
  474.       this.m_listofdevices.m_Names.push(devicename);
  475.       this.m_listofdevices.m_Tooltips.push(devicename);
  476.       this.m_listofdevices.m_Enableds.push(isEnabled);
  477.       this.m_listofdevices.m_Modifiers.push("");
  478.       this.m_listofdevices.m_Keys.push("");
  479.       this.m_listofdevices.m_Keycodes.push("");
  480.       this.m_listofdevices.m_PlaylistCommands.push(null);
  481.       this.m_listofdevices.m_DeviceIds.push(device.id);
  482.     }
  483.  
  484.     this._makingList = false;
  485.   },
  486.  
  487.   handleGetMenu: function addToDeviceHelper_handleGetMenu(aSubMenu) {
  488.     if (this.m_listofdevices == null) {
  489.       // handleGetMenu called before makeListOfPlaylists, this would
  490.       // cause infinite recursion : the command object would not find
  491.       // the menu either, would return null to getMenu which corresponds
  492.       // to the root menu, and it'd recurse infinitly.
  493.       throw Components.results.NS_ERROR_FAILURE;
  494.     }
  495.     if (aSubMenu == ADDTODEVICE_MENU_ID) return this.m_listofdevices;
  496.     return null;
  497.   },
  498.  
  499.   // handle click on a device command item
  500.   handleCommand: function addToDeviceHelper_handleCommand(id) {
  501.     try {
  502.       var context = this.m_commands.m_Context;
  503.       var addtodevicestr = ADDTODEVICE_COMMAND_ID;
  504.       if ( id.slice(0, addtodevicestr.length) == addtodevicestr) {
  505.         var r = id.slice(addtodevicestr.length);
  506.         var parts = r.split(';');
  507.         if (parts.length >= 2) {
  508.           var libraryguid = parts[0];
  509.           var devicename = parts[1];
  510.           this.addToDevice(libraryguid, context.m_Playlist, devicename);
  511.           return true;
  512.         }
  513.       }
  514.     } catch (e) {
  515.       Components.utils.reportError(e);
  516.     }
  517.     return false;
  518.   },
  519.  
  520.   _getDeviceLibraryForLibrary: function(aDevice, aLibrary) {
  521.     var libs = aDevice.content.libraries;
  522.     for (var i = 0; i < libs.length; i++) {
  523.       var devLib = libs.queryElementAt(i, Ci.sbIDeviceLibrary);
  524.       if (devLib.equals(aLibrary))
  525.         return devLib;
  526.     }
  527.  
  528.     return null;
  529.   },
  530.  
  531.   _itemsFromEnumerator: function(aItemEnum) {
  532.     var items = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
  533.  
  534.     while (aItemEnum.hasMoreElements())
  535.       items.appendElement(aItemEnum.getNext(), false);
  536.  
  537.     return items;
  538.   },
  539.  
  540.   // perform the transfer of the selected items to the device library
  541.   addToDevice: function addToDeviceHelper_addToDevice(
  542.                           devicelibraryguid,
  543.                           sourceplaylist,
  544.                           devicename) {
  545.     var library = this.m_libraryManager.getLibrary(devicelibraryguid);
  546.     if (library) {
  547.       var selection =
  548.         sourceplaylist.mediaListView.selection.selectedMediaItems;
  549.       var items = this._itemsFromEnumerator(selection);
  550.  
  551.       var deviceManager = Cc["@songbirdnest.com/Songbird/DeviceManager;2"]
  552.                             .getService(Ci.sbIDeviceManager2);
  553.       var device = deviceManager.getDeviceForItem(library);
  554.       var deviceLibrary = this._getDeviceLibraryForLibrary(device, library);
  555.  
  556.       var differ =
  557.           Cc["@songbirdnest.com/Songbird/Device/DeviceLibrarySyncDiff;1"]
  558.             .createInstance(Ci.sbIDeviceLibrarySyncDiff);
  559.       var changeset = {};
  560.       var destItems = {};
  561.  
  562.       differ.generateDropLists(sourceplaylist.library,
  563.                                library,
  564.                                null,
  565.                                items,
  566.                                destItems,
  567.                                changeset);
  568.  
  569.       device.exportToDevice(deviceLibrary, changeset.value);
  570.  
  571.       DNDUtils.reportAddedTracks(changeset.value.changes.length,
  572.                                  0, /* no duplicate reporting */
  573.                                  0, /* no unsupported reporting */
  574.                                  devicename,
  575.                                  true);
  576.     }
  577.   },
  578.  
  579.   //-----------------------------------------------------------------------------
  580.   // methods for refreshing the list when needed, detection is performed via
  581.   // an sbIDeviceEventListener on the device manager
  582.   //-----------------------------------------------------------------------------
  583.  
  584.   _makingList    : false,
  585.  
  586.   refreshCommands: function addToDeviceHelper_refreshCommands() {
  587.  
  588.     // Bug fixers beware! This code gets called very frequently and can have
  589.     // difficult-to-debug side effects. Proceed with caution.
  590.  
  591.     var self = this;
  592.     function ensureRefreshExists() {
  593.       // Explicitly return true or false. Otherwise, JS will complain to the
  594.       // error console if any of the checks finds an undefined property.
  595.       return (self.m_commands &&
  596.               self.m_commands.m_Context &&
  597.               self.m_commands.m_Context.m_Playlist &&
  598.               self.m_commands.m_Context.m_Playlist.refreshCommands) ?
  599.               true : false;
  600.     }
  601.  
  602.     /* We need to ensure that the context and playlist have been initialized
  603.      * and are ready to display commands before calling refreshCommands.
  604.      *
  605.      * It is possible for an event handler to fire before the binding
  606.      * is created or after it is destroyed, so it is possible for this to
  607.      * be triggered before m_Playlist is fully instantiated or after pieces
  608.      * of it have gone away.  Thus, we need to also check that refreshCommands
  609.      * is present to ensure the playlist binding is in a good state. */
  610.  
  611.     if (ensureRefreshExists()) {
  612.       this.makeListOfDevices();
  613.       // Check again, as the playlist binding can be destroyed during the
  614.       // previous function call.
  615.       if (ensureRefreshExists()) {
  616.         this.m_commands.m_Context.m_Playlist.refreshCommands();
  617.       }
  618.     }
  619.   },
  620.  
  621.   onUpdateEvent: function addToDeviceHelper_onUpdateEvent() {
  622.     if (this._makingList) return;
  623.     this.refreshCommands();
  624.   },
  625.  
  626.   QueryInterface: function QueryInterface(iid) {
  627.     if (!iid.equals(Components.interfaces.sbIDeviceEventListener) &&
  628.         !iid.equals(Components.interfaces.nsISupports))
  629.       throw Components.results.NS_ERROR_NO_INTERFACE;
  630.     return this;
  631.   },
  632.  
  633.   // trap event for device library added/removed, and refresh the commands
  634.   // we trap the library add/remove (instead of the plain device add/remove)
  635.   // since we check the library count in makeListOfDevices(), so we need to
  636.   // make sure we don't run before the libraries have been added to the device
  637.   onDeviceEvent: function addToDeviceHelper_onDeviceEvent(aEvent) {
  638.     if (aEvent.type == Components.interfaces.sbIDeviceEvent.EVENT_DEVICE_LIBRARY_ADDED ||
  639.         aEvent.type == Components.interfaces.sbIDeviceEvent.EVENT_DEVICE_LIBRARY_REMOVED ||
  640.         aEvent.type == Components.interfaces.sbIDeviceEvent.EVENT_DEVICE_MOUNTING_END) {
  641.       this.onUpdateEvent();
  642.     }
  643.   }
  644.  
  645. };
  646.