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 >
Wrap
Text File
|
2012-06-08
|
20KB
|
646 lines
/*
*=BEGIN SONGBIRD GPL
*
* This file is part of the Songbird web player.
*
* Copyright(c) 2005-2010 POTI, Inc.
* http://www.songbirdnest.com
*
* This file may be licensed under the terms of of the
* GNU General Public License Version 2 (the ``GPL'').
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the GPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the GPL along with this
* program. If not, go to http://www.gnu.org/licenses/gpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*=END SONGBIRD GPL
*/
Components.utils.import("resource://app/jsmodules/sbProperties.jsm");
Components.utils.import("resource://app/jsmodules/DropHelper.jsm");
Components.utils.import("resource://app/jsmodules/sbLibraryUtils.jsm");
Components.utils.import("resource://app/jsmodules/SBUtils.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cr = Components.results;
const SB_MEDIALISTDUPLICATEFILTER_CONTRACTID =
"@songbirdnest.com/Songbird/Library/medialistduplicatefilter;1";
const ADDTODEVICE_MENU_TYPE = "submenu";
const ADDTODEVICE_MENU_ID = "library_cmd_addtodevice";
const ADDTODEVICE_MENU_NAME = "&command.addtodevice";
const ADDTODEVICE_MENU_TOOLTIP = "&command.tooltip.addtodevice";
const ADDTODEVICE_MENU_KEY = "&command.shortcut.key.addtodevice";
const ADDTODEVICE_MENU_KEYCODE = "&command.shortcut.keycode.addtodevice";
const ADDTODEVICE_MENU_MODIFIERS = "&command.shortcut.modifiers.addtodevice";
const ADDTODEVICE_COMMAND_ID = "library_cmd_addtodevice:";
EXPORTED_SYMBOLS = [ "addToDeviceHelper",
"SBPlaylistCommand_AddToDevice" ];
/**
* \brief Creates a new unwrapper helper object which ensures
* downloadStatusTarget is always set when adding items
* to another library or playlist on a device.
* \param aSelection An sbIMediaListViewSelection.selectedMediaItems enumerator
* \return A new unwrapper helper object.
*/
function createUnwrapper(aSelection) {
var unwrapper = Cc["@songbirdnest.com/Songbird/Library/EnumeratorWrapper;1"]
.createInstance(Ci.sbIMediaListEnumeratorWrapper);
unwrapper.initialize(aSelection);
return unwrapper;
}
// ----------------------------------------------------------------------------
// The "Add to device" dynamic command object
// ----------------------------------------------------------------------------
var SBPlaylistCommand_AddToDevice =
{
m_Context: {
m_Playlist: null,
m_Window: null
},
m_addToDevice: null,
m_root_commands :
{
m_Types: new Array
(
ADDTODEVICE_MENU_TYPE
),
m_Ids: new Array
(
ADDTODEVICE_MENU_ID
),
m_Names: new Array
(
ADDTODEVICE_MENU_NAME
),
m_Tooltips: new Array
(
ADDTODEVICE_MENU_TOOLTIP
),
m_Keys: new Array
(
ADDTODEVICE_MENU_KEY
),
m_Keycodes: new Array
(
ADDTODEVICE_MENU_KEYCODE
),
m_Enableds: new Array
(
true
),
m_Modifiers: new Array
(
ADDTODEVICE_MENU_MODIFIERS
),
m_PlaylistCommands: new Array
(
null
),
m_DeviceIds: new Array
(
null
)
},
_getMenu: function(aSubMenu)
{
var cmds;
cmds = this.m_addToDevice.handleGetMenu(aSubMenu);
if (cmds) return cmds;
switch (aSubMenu) {
default:
cmds = this.m_root_commands;
break;
}
return cmds;
},
getVisible: function( aHost )
{
return this.m_addToDevice.hasDevices();
},
getNumCommands: function( aSubMenu, aHost )
{
var cmds = this._getMenu(aSubMenu);
return cmds.m_Ids.length;
},
getCommandId: function( aSubMenu, aIndex, aHost )
{
var cmds = this._getMenu(aSubMenu);
if ( aIndex >= cmds.m_Ids.length ) return "";
return cmds.m_Ids[ aIndex ];
},
getCommandType: function( aSubMenu, aIndex, aHost )
{
var cmds = this._getMenu(aSubMenu);
if ( aIndex >= cmds.m_Ids.length ) return "";
return cmds.m_Types[ aIndex ];
},
getCommandText: function( aSubMenu, aIndex, aHost )
{
var cmds = this._getMenu(aSubMenu);
if ( aIndex >= cmds.m_Names.length ) return "";
return cmds.m_Names[ aIndex ];
},
getCommandFlex: function( aSubMenu, aIndex, aHost )
{
var cmds = this._getMenu(aSubMenu);
if ( cmds.m_Types[ aIndex ] == "separator" ) return 1;
return 0;
},
getCommandToolTipText: function( aSubMenu, aIndex, aHost )
{
var cmds = this._getMenu(aSubMenu);
if ( aIndex >= cmds.m_Tooltips.length ) return "";
return cmds.m_Tooltips[ aIndex ];
},
getCommandValue: function( aSubMenu, aIndex, aHost )
{
},
instantiateCustomCommand: function( aDocument, aId, aHost )
{
return null;
},
refreshCustomCommand: function( aElement, aId, aHost )
{
},
getCommandVisible: function( aSubMenu, aIndex, aHost )
{
return true;
},
getCommandFlag: function( aSubmenu, aIndex, aHost )
{
return false;
},
getCommandChoiceItem: function( aChoiceMenu, aHost )
{
return "";
},
getCommandEnabled: function( aSubMenu, aIndex, aHost )
{
if (this.m_Context.m_Playlist.tree.currentIndex == -1) return false;
var cmds = this._getMenu(aSubMenu);
if (aSubMenu == ADDTODEVICE_MENU_ID) {
var deviceRegistrar =
Components.classes["@songbirdnest.com/Songbird/DeviceManager;2"]
.getService(Components.interfaces.sbIDeviceRegistrar);
var device = deviceRegistrar.getDevice(cmds.m_DeviceIds[aIndex]);
if (device.state == Components.interfaces.sbIDevice.STATE_MOUNTING) {
// Don't enable the device command if the device is
// currently mounting.
return false;
}
}
return cmds.m_Enableds[ aIndex ];
},
getCommandShortcutModifiers: function ( aSubMenu, aIndex, aHost )
{
var cmds = this._getMenu(aSubMenu);
if ( aIndex >= cmds.m_Modifiers.length ) return "";
return cmds.m_Modifiers[ aIndex ];
},
getCommandShortcutKey: function ( aSubMenu, aIndex, aHost )
{
var cmds = this._getMenu(aSubMenu);
if ( aIndex >= cmds.m_Keys.length ) return "";
return cmds.m_Keys[ aIndex ];
},
getCommandShortcutKeycode: function ( aSubMenu, aIndex, aHost )
{
var cmds = this._getMenu(aSubMenu);
if ( aIndex >= cmds.m_Keycodes.length ) return "";
return cmds.m_Keycodes[ aIndex ];
},
getCommandShortcutLocal: function ( aSubMenu, aIndex, aHost )
{
return true;
},
getCommandSubObject: function ( aSubMenu, aIndex, aHost )
{
var cmds = this._getMenu(aSubMenu);
if ( aIndex >= cmds.m_PlaylistCommands.length ) return null;
return cmds.m_PlaylistCommands[ aIndex ];
},
onCommand: function( aSubMenu, aIndex, aHost, id, value )
{
if ( id )
{
// ADDTODEVICE
if (this.m_addToDevice.handleCommand(id)) return;
// ...
}
},
// The object registered with the sbIPlaylistCommandsManager interface acts
// as a template for instances bound to specific playlist elements
dupObject: function (obj) {
var r = {};
for ( var i in obj )
{
r[ i ] = obj[ i ];
}
return r;
},
duplicate: function()
{
var obj = this.dupObject(this);
obj.m_Context = this.dupObject(this.m_Context);
return obj;
},
initCommands: function(aHost) {
if (!this.m_addToDevice) {
this.m_addToDevice = new addToDeviceHelper();
this.m_addToDevice.init(this);
}
},
shutdownCommands: function() {
if (!this.m_addToDevice) {
dump("this.m_addToDevice is null in SBPlaylistCommand_AddToDevice ?!!\n");
return;
}
this.m_addToDevice.shutdown();
this.m_addToDevice = null;
this.m_Context = null;
},
setContext: function( context )
{
var playlist = context.playlist;
var window = context.window;
// Ah. Sometimes, things are being secure.
if ( playlist && playlist.wrappedJSObject )
playlist = playlist.wrappedJSObject;
if ( window && window.wrappedJSObject )
window = window.wrappedJSObject;
this.m_Context.m_Playlist = playlist;
this.m_Context.m_Window = window;
},
QueryInterface : function(aIID)
{
if (!aIID.equals(Components.interfaces.sbIPlaylistCommands) &&
!aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
!aIID.equals(Components.interfaces.nsISupports))
{
throw Components.results.NS_ERROR_NO_INTERFACE;
}
return this;
}
}; // SBPlaylistCommand_AddToDevice declaration
function addToDeviceHelper() {
}
addToDeviceHelper.prototype = {
m_listofdevices: null,
m_commands: null,
m_deviceManager: null,
m_libraryManager: null,
LOG: function(str) {
var consoleService = Components.classes['@mozilla.org/consoleservice;1']
.getService(Components.interfaces.nsIConsoleService);
consoleService.logStringMessage(str);
},
init: function addToDeviceHelper_init(aCommands) {
this.m_libraryManager =
Components.classes["@songbirdnest.com/Songbird/library/Manager;1"]
.getService(Components.interfaces.sbILibraryManager);
this.m_deviceManager =
Components.classes["@songbirdnest.com/Songbird/DeviceManager;2"]
.getService(Components.interfaces.sbIDeviceManager2);
var eventTarget =
this.m_deviceManager.QueryInterface(
Components.interfaces.sbIDeviceEventTarget
);
eventTarget.addEventListener(this);
this.m_commands = aCommands;
this.makeListOfDevices();
},
shutdown: function addToDeviceHelper_shutdown() {
var eventTarget =
this.m_deviceManager.QueryInterface(
Components.interfaces.sbIDeviceEventTarget
);
eventTarget.removeEventListener(this);
this.m_deviceManager = null;
},
// returns true if we have at least one device in the list,
// the commands object hides the "add to device" submenu when
// no device is present
hasDevices: function addToDeviceHelper_hasDevices() {
return (this.m_listofdevices &&
this.m_listofdevices.m_Types &&
this.m_listofdevices.m_Types.length > 0);
},
// builds the list of devices, called on startup and when a
// device is added or removed
makeListOfDevices: function addToDeviceHelper_makeListOfDevices() {
this._makingList = true;
this.m_listofdevices = {};
this.m_listofdevices.m_Types = new Array();
this.m_listofdevices.m_Ids = new Array();
this.m_listofdevices.m_Names = new Array();
this.m_listofdevices.m_Tooltips = new Array();
this.m_listofdevices.m_Enableds = new Array();
this.m_listofdevices.m_Modifiers = new Array();
this.m_listofdevices.m_Keys = new Array();
this.m_listofdevices.m_Keycodes = new Array();
this.m_listofdevices.m_PlaylistCommands = new Array();
this.m_listofdevices.m_DeviceIds = new Array();
// get all devices
var registrar =
this.m_deviceManager.QueryInterface(
Components.interfaces.sbIDeviceRegistrar
);
var devices = Array();
// turn into a js array
for (var i=0;i<registrar.devices.length;i++) {
var device = registrar.devices.queryElementAt
(i, Components.interfaces.sbIDevice);
if (device && device.connected)
devices.push(device);
}
// order of devices returned by the registrar is undefined,
// so sort by device name
function deviceSorter(x, y) {
var nameX = x.name;
var nameY = y.name;
if (x < y) return -1;
if (y < x) return 1;
return 0;
}
devices.sort(deviceSorter);
// extract the device names and associated library guids
// and fill the arrays used by the command object
for (var d in devices) {
var libraryguid;
var device = devices[d];
var devicename = device.name;
// don't add devices that are read-only
var deviceProperties = device.properties.properties;
var accessCompatibility;
try {
accessCompatibility = deviceProperties.getPropertyAsAString(
"http://songbirdnest.com/device/1.0#accessCompatibility");
} catch (ex) {}
if (accessCompatibility == "ro") {
continue;
}
var isEnabled = false;
if (!devicename)
devicename = "Unnamed Device";
var library = device.defaultLibrary;
if (library) {
isEnabled = library.userEditable;
libraryguid = library.guid;
} else {
continue;
}
this.m_listofdevices.m_Types.push("action");
this.m_listofdevices.m_Ids.push(ADDTODEVICE_COMMAND_ID +
libraryguid + ";" +
devicename);
this.m_listofdevices.m_Names.push(devicename);
this.m_listofdevices.m_Tooltips.push(devicename);
this.m_listofdevices.m_Enableds.push(isEnabled);
this.m_listofdevices.m_Modifiers.push("");
this.m_listofdevices.m_Keys.push("");
this.m_listofdevices.m_Keycodes.push("");
this.m_listofdevices.m_PlaylistCommands.push(null);
this.m_listofdevices.m_DeviceIds.push(device.id);
}
this._makingList = false;
},
handleGetMenu: function addToDeviceHelper_handleGetMenu(aSubMenu) {
if (this.m_listofdevices == null) {
// handleGetMenu called before makeListOfPlaylists, this would
// cause infinite recursion : the command object would not find
// the menu either, would return null to getMenu which corresponds
// to the root menu, and it'd recurse infinitly.
throw Components.results.NS_ERROR_FAILURE;
}
if (aSubMenu == ADDTODEVICE_MENU_ID) return this.m_listofdevices;
return null;
},
// handle click on a device command item
handleCommand: function addToDeviceHelper_handleCommand(id) {
try {
var context = this.m_commands.m_Context;
var addtodevicestr = ADDTODEVICE_COMMAND_ID;
if ( id.slice(0, addtodevicestr.length) == addtodevicestr) {
var r = id.slice(addtodevicestr.length);
var parts = r.split(';');
if (parts.length >= 2) {
var libraryguid = parts[0];
var devicename = parts[1];
this.addToDevice(libraryguid, context.m_Playlist, devicename);
return true;
}
}
} catch (e) {
Components.utils.reportError(e);
}
return false;
},
_getDeviceLibraryForLibrary: function(aDevice, aLibrary) {
var libs = aDevice.content.libraries;
for (var i = 0; i < libs.length; i++) {
var devLib = libs.queryElementAt(i, Ci.sbIDeviceLibrary);
if (devLib.equals(aLibrary))
return devLib;
}
return null;
},
_itemsFromEnumerator: function(aItemEnum) {
var items = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
while (aItemEnum.hasMoreElements())
items.appendElement(aItemEnum.getNext(), false);
return items;
},
// perform the transfer of the selected items to the device library
addToDevice: function addToDeviceHelper_addToDevice(
devicelibraryguid,
sourceplaylist,
devicename) {
var library = this.m_libraryManager.getLibrary(devicelibraryguid);
if (library) {
var selection =
sourceplaylist.mediaListView.selection.selectedMediaItems;
var items = this._itemsFromEnumerator(selection);
var deviceManager = Cc["@songbirdnest.com/Songbird/DeviceManager;2"]
.getService(Ci.sbIDeviceManager2);
var device = deviceManager.getDeviceForItem(library);
var deviceLibrary = this._getDeviceLibraryForLibrary(device, library);
var differ =
Cc["@songbirdnest.com/Songbird/Device/DeviceLibrarySyncDiff;1"]
.createInstance(Ci.sbIDeviceLibrarySyncDiff);
var changeset = {};
var destItems = {};
differ.generateDropLists(sourceplaylist.library,
library,
null,
items,
destItems,
changeset);
device.exportToDevice(deviceLibrary, changeset.value);
DNDUtils.reportAddedTracks(changeset.value.changes.length,
0, /* no duplicate reporting */
0, /* no unsupported reporting */
devicename,
true);
}
},
//-----------------------------------------------------------------------------
// methods for refreshing the list when needed, detection is performed via
// an sbIDeviceEventListener on the device manager
//-----------------------------------------------------------------------------
_makingList : false,
refreshCommands: function addToDeviceHelper_refreshCommands() {
// Bug fixers beware! This code gets called very frequently and can have
// difficult-to-debug side effects. Proceed with caution.
var self = this;
function ensureRefreshExists() {
// Explicitly return true or false. Otherwise, JS will complain to the
// error console if any of the checks finds an undefined property.
return (self.m_commands &&
self.m_commands.m_Context &&
self.m_commands.m_Context.m_Playlist &&
self.m_commands.m_Context.m_Playlist.refreshCommands) ?
true : false;
}
/* We need to ensure that the context and playlist have been initialized
* and are ready to display commands before calling refreshCommands.
*
* It is possible for an event handler to fire before the binding
* is created or after it is destroyed, so it is possible for this to
* be triggered before m_Playlist is fully instantiated or after pieces
* of it have gone away. Thus, we need to also check that refreshCommands
* is present to ensure the playlist binding is in a good state. */
if (ensureRefreshExists()) {
this.makeListOfDevices();
// Check again, as the playlist binding can be destroyed during the
// previous function call.
if (ensureRefreshExists()) {
this.m_commands.m_Context.m_Playlist.refreshCommands();
}
}
},
onUpdateEvent: function addToDeviceHelper_onUpdateEvent() {
if (this._makingList) return;
this.refreshCommands();
},
QueryInterface: function QueryInterface(iid) {
if (!iid.equals(Components.interfaces.sbIDeviceEventListener) &&
!iid.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
},
// trap event for device library added/removed, and refresh the commands
// we trap the library add/remove (instead of the plain device add/remove)
// since we check the library count in makeListOfDevices(), so we need to
// make sure we don't run before the libraries have been added to the device
onDeviceEvent: function addToDeviceHelper_onDeviceEvent(aEvent) {
if (aEvent.type == Components.interfaces.sbIDeviceEvent.EVENT_DEVICE_LIBRARY_ADDED ||
aEvent.type == Components.interfaces.sbIDeviceEvent.EVENT_DEVICE_LIBRARY_REMOVED ||
aEvent.type == Components.interfaces.sbIDeviceEvent.EVENT_DEVICE_MOUNTING_END) {
this.onUpdateEvent();
}
}
};