30 const Cc = Components.classes;
31 const Ci = Components.interfaces;
32 const Cr = Components.results;
33 const Cu = Components.utils;
35 const CONTRACTID =
"@songbirdnest.com/servicepane/device;1";
37 const SP =
"http://songbirdnest.com/rdf/servicepane#";
38 const LSP =
'http://songbirdnest.com/rdf/library-servicepane#';
39 const DEVICESP_NS =
"http://songbirdnest.com/rdf/device-servicepane#";
44 Cu.import(
"resource://gre/modules/XPCOMUtils.jsm");
45 Cu.import(
"resource://app/jsmodules/ArrayConverter.jsm");
46 Cu.import(
"resource://app/jsmodules/DOMUtils.jsm");
47 Cu.import(
"resource://app/jsmodules/sbProperties.jsm");
48 Cu.import(
"resource://app/jsmodules/sbLibraryUtils.jsm");
49 Cu.import(
"resource://app/jsmodules/DebugUtils.jsm");
57 dump(parentArgs.callee.name +
"(");
58 for (var
i = 0;
i < parentArgs.length;
i++) {
60 if (i < parentArgs.length - 1) {
75 this._servicePane =
null;
76 this._libraryServicePane =
null;
79 this.stringbundle =
null;
81 this.
log = DebugUtils.generateLogFunction(
"DeviceServicePaneService");
88 XPCOMUtils.generateQI([
Ci.sbIServicePaneModule,
89 Ci.sbIServicePaneMutationListener,
90 Ci.sbIDeviceServicePaneService]);
92 "Songbird Device Service Pane Service";
94 Components.ID(
"{845c31ee-c30e-4fb6-9667-0b10e58c7069}");
99 category:
'service-pane',
109 function sbDeviceServicePane_servicePaneInit(sps) {
113 this._servicePane = sps;
114 this._libraryServicePane =
Cc[
"@songbirdnest.com/servicepane/library;1"]
115 .getService(
Ci.sbILibraryServicePaneService);
118 this._deviceContextMenuDoc =
119 DOMUtils.loadDocument
120 (
"chrome://songbird/content/xul/device/deviceContextMenu.xul");
123 this._deviceMgr =
Cc[
"@songbirdnest.com/Songbird/DeviceManager;2"]
124 .getService(
Ci.sbIDeviceManager2);
126 this._mainLibraryListeners = [];
127 this._deviceLibraryAndListenerObjs = [];
131 function sbDeviceServicePane_shutdown() {
133 for (var
i = 0;
i < this._deviceLibraryAndListenerObjs.length;
i++) {
134 var currObj = this._deviceLibraryAndListenerObjs[
i];
135 currObj[
"library"].removeListener(currObj[
"listener"]);
138 for (var
i = 0;
i < this._mainLibraryListeners.length;
i++) {
139 LibraryUtils.mainLibrary.removeListener(this._mainLibraryListeners[
i]);
142 this._servicePane.root.removeMutationListener(
this);
143 this._servicePane =
null;
144 if (this._deviceGroupNode)
145 this._deviceGroupNode.removeMutationListener(
this);
146 this._deviceGroupNode =
null;
147 this._libraryServicePane =
null;
148 this._deviceContextMenuDoc =
null;
149 this._deviceMgr =
null;
153 function sbDeviceServicePane_fillContextMenu(aNode, aContextMenu, aParentWindow) {
155 var deviceID = aNode.getAttributeNS(DEVICESP_NS,
"device-id");
160 var fillDefaultContextMenu = aNode.getAttributeNS(DEVICESP_NS,
161 "fillDefaultContextMenu");
162 if (fillDefaultContextMenu !=
"true")
166 var deviceNodeType = aNode.getAttributeNS(DEVICESP_NS,
"deviceNodeType");
169 if (deviceNodeType ==
"device") {
170 DOMUtils.importChildElements(aContextMenu,
171 this._deviceContextMenuDoc,
172 "device_context_menu_items",
173 {
"device-id": deviceID,
174 "service_pane_node_id": aNode.id });
175 }
else if (deviceNodeType ==
"library") {
176 DOMUtils.importChildElements(aContextMenu,
177 this._deviceContextMenuDoc,
178 "device_library_context_menu_items",
179 {
"device-id": deviceID,
180 "service_pane_node_id": aNode.id });
185 function sbDeviceServicePane_fillNewItemMenu(aNode, aContextMenu, aParentWindow) {
189 function sbDeviceServicePane_onSelectionChanged(aNode, aContainer, aParentWindow) {
193 function sbDeviceServicePane_canDrop(aNode, aDragSession, aOrientation, aWindow) {
198 function sbDeviceServicePane_onDrop(aNode, aDragSession, aOrientation, aWindow) {
202 function sbDeviceServicePane_onDragGesture(aNode, aDataTransfer) {
211 function sbDeviceServicePane_onBeforeRename(aNode) {
218 function sbDeviceServicePane_onRename(aNode, aNewName) {
227 function sbDeviceServicePane_createNodeForDevice(aDevice, aDeviceIdentifier) {
229 this.
log(
"createNodeForDevice");
232 let devicesNode = this._ensureDevicesGroupExists();
235 var
id = this.
_deviceURN(aDevice, aDeviceIdentifier);
236 var
node = this._servicePane.getNode(
id);
239 node = this._servicePane.createNode();
246 node.editable =
false;
249 if (!node.parentNode) {
250 this.
log(
"\tNo parentNode, appending to devices group node");
251 devicesNode.appendChild(node);
258 function sbDeviceServicePane_createNodeForDevice2(aDevice, aEjectable) {
259 this.
log(
"createNodeForDevice2");
262 let devicesNode = this._ensureDevicesGroupExists();
265 var
id = this._deviceURN2(aDevice);
267 var node = this._servicePane.getNode(
id);
270 node = this._servicePane.createNode();
276 node.setAttributeNS(DEVICESP_NS,
"device-id", aDevice.id);
277 node.setAttributeNS(DEVICESP_NS,
"deviceNodeType",
"device");
280 node.setAttribute(
"ejectable",
"true");
281 let
listener =
new _deviceNodeEventListener(aDevice);
282 node.addEventListener(listener);
284 node.editable =
false;
285 node.className =
"device";
288 var iconUri = aDevice.properties.iconUri;
290 var spec = iconUri.spec;
291 if (iconUri.schemeIs(
"file") && /\.ico$/
i(spec)) {
293 spec =
"moz-icon://" + spec +
"?size=16";
302 if (!node.parentNode) {
303 this.
log(
"\tNo parentNode, appending to devices group node");
304 devicesNode.appendChild(node);
307 this._device = aDevice;
312 function sbDeviceServicePane_createLibraryNodeForDevice(aDevice, aLibrary) {
313 this.
log(
"Creating library nodes for device " + aDevice.id);
314 var deviceNode = this.getNodeForDevice(aDevice);
317 this._libraryServicePane.createNodeForLibrary(aLibrary);
318 this._moveLibraryNodes(aLibrary);
326 var listenToPropsArray =
327 Cc[
"@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1"]
328 .createInstance(
Ci.sbIMutablePropertyArray);
329 listenToPropsArray.appendProperty(SBProperties.originItemGuid,
"");
330 aLibrary.addListener(deviceUpdateListener,
332 Ci.sbIMediaList.LISTENER_FLAGS_ITEMUPDATED,
334 var deviceLibListenerObj = {
336 listener: deviceUpdateListener
339 this._deviceLibraryAndListenerObjs.push(deviceLibListenerObj);
345 var mainLibraryRemovedListener =
new MainLibraryItemRemovedListener(aLibrary);
347 (mainLibraryRemovedListener,
349 Ci.sbIMediaList.LISTENER_FLAGS_AFTERITEMREMOVED,
351 this._mainLibraryListeners.push(mainLibraryRemovedListener);
353 return this._libraryServicePane.getNodeForLibraryResource(aLibrary);
357 function sbDeviceServicePane_getNodeForDevice(aDevice) {
359 var
id = this._deviceURN2(aDevice);
360 return this._servicePane.getNode(
id);
364 function sbDeviceServicePane_setFillDefaultContxtMenu(aNode,
367 aNode.setAttributeNS(DEVICESP_NS,
"fillDefaultContextMenu",
"true");
369 aNode.setAttributeNS(DEVICESP_NS,
"fillDefaultContextMenu",
"false");
374 function sbDeviceServicePane_insertChildByName(aDevice, aChild) {
376 var deviceNode = this.getNodeForDevice(aDevice);
377 for (let node = deviceNode.firstChild; node; node = node.nextSibling) {
378 var listType = node.getAttributeNS(
LSP,
"ListType");
380 if (listType ==
"library") {
385 var childname = aChild.name ? aChild.name.toLowerCase() : aChild.name;
386 var nodename = node.name ? node.name.toLowerCase() : node.name;
387 if (childname < nodename) {
394 deviceNode.insertBefore(aChild, lastNode);
397 if (aChild.className.match(/medialist/) !=
null) {
403 var resource = this._libraryServicePane.getLibraryResourceForNode(aChild);
404 if (resource instanceof
Ci.sbIMediaList &&
406 var classes = aChild.className.split(/\s/);
407 classes.push(
"medialisttype-deviceonly");
408 aChild.className = classes.join(
' ');
416 function _deviceNodeEventListener(aDevice) {
417 this._device = aDevice;
419 _deviceNodeEventListener.prototype = {
420 handleEvent:
function sbDeviceServicePane_handleEvent(aEventName) {
421 switch (aEventName) {
424 this._device.eject();
426 dump(
"Exception in sbDeviceServicePane event listener: " + e +
"\n");
437 function sbDeviceServicePane_attrModified(aNode, aAttrName, aNamespace,
440 this._updateParentDeviceNode();
444 function sbDeviceServicePane_nodeInserted(aNode, aParent, aInsertBefore) {
446 this._updateParentDeviceNode();
450 function sbDeviceServicePane_nodeRemoved(aNode, aParent) {
452 this._updateParentDeviceNode();
468 onItemUpdated:
function DeviceLibraryItemUpdateListener_onItemUpdated
469 (aMediaList, aMediaItem, aProperties) {
472 if (!(aMediaItem instanceof
Ci.sbIMediaList)) {
475 var libSPS =
Cc[
"@songbirdnest.com/servicepane/library;1"]
476 .getService(
Ci.sbILibraryServicePaneService);
477 var node = libSPS.getNodeForLibraryResource(aMediaItem);
478 var classes = node.className.split(/\s/);
482 if (!
LibraryUtils.getMainLibraryOriginItem(aMediaItem)) {
484 classes.push(
"medialisttype-deviceonly");
489 classes = classes.filter(
function(aClass) {
490 return aClass !=
"medialisttype-deviceonly";
493 node.className = classes.join(
' ');
504 function MainLibraryItemRemovedListener(devLibrary) {
505 this.deviceLibrary = devLibrary;
508 MainLibraryItemRemovedListener.prototype = {
509 onAfterItemRemoved:
function MainLibraryItemRemovedListener_onAfterItemRemoved
510 (aMediaList, aMediaItem, aIndex) {
513 if (!(aMediaItem instanceof
Ci.sbIMediaList)) {
519 var foundLists = this.deviceLibrary.getItemsByProperty
520 (SBProperties.originItemGuid,
522 var libSPS =
Cc[
"@songbirdnest.com/servicepane/library;1"]
523 .getService(
Ci.sbILibraryServicePaneService);
525 for (let
i = 0;
i < foundLists.length;
i++) {
528 var foundList = foundLists.queryElementAt(
i,
Ci.sbIMediaItem);
530 var node = libSPS.getNodeForLibraryResource(foundList);
532 if (node && node.className.match(/medialisttype-deviceonly/) ==
null) {
536 var classes = node.className.split(/\s/);
537 classes.push(
"medialisttype-deviceonly");
538 node.className = classes.join(
" ");
553 function sbDeviceServicePane__updateParentDeviceNode() {
557 let devicesNode = this._servicePane.getNode(
"SB:Devices");
562 for (let node = devicesNode.firstChild; node; node = node.nextSibling) {
563 if (node && !node.hidden) {
569 if (devicesNode.hidden != hidden) {
570 this.
log(
"Hiding devices node since all children are gone or hidden");
571 devicesNode.hidden =
hidden;
575 this.
log(
"Execption updating device node: " + e);
583 function sbDeviceServicePane__deviceURN(aDevice, aDeviceIdentifier) {
591 function sbDeviceServicePane__ensureDevicesGroupExists() {
592 this.
log(
"ensureDevicesGroupExists");
593 let fnode = this._servicePane.getNode(
"SB:Devices");
596 fnode = this._servicePane.createNode();
597 fnode.id =
"SB:Devices";
598 fnode.name =
"&servicesource.devices";
599 this._addClassNames(fnode, [
"folder", this._makeCSSProperty(fnode.name)]);
602 fnode.editable =
false;
603 fnode.setAttributeNS(
SP,
'Weight', -2);
604 this._servicePane.root.appendChild(fnode);
605 fnode.addMutationListener(
this);
606 this._deviceGroupNode = fnode;
607 this.
log(
"\tDevices group created");
614 function sbDeviceServicePane__addClassNames(aNode, aList) {
617 for each (let
name in className.split(
" "))
618 existing[name] =
true;
620 for each (let name
in aList)
621 if (!existing.hasOwnProperty(name))
622 className += (className ?
" " :
"") +
name;
629 function sbDeviceServicePane__makeCSSProperty(aString) {
630 if ( aString[0] ==
"&" ) {
631 aString = aString.substr(1, aString.length);
632 aString = aString.replace(/\./g,
"-");
639 function sbDeviceServicePane__deviceURN2(aDevice) {
640 var
id =
"" + aDevice.id;
642 if(
id.charAt(0) ==
"{" &&
643 id.charAt(-1) ==
"}") {
644 id =
id.substring(1, -1);
659 function sbDeviceServicePane__moveLibraryNodes(aLibrary) {
660 var nodeList = this._libraryServicePane.getNodesForLibraryResource(aLibrary);
661 nodeList = ArrayConverter.JSArray(nodeList);
662 for each (var node
in nodeList) {
663 node.QueryInterface(
Ci.sbIServicePaneNode);
664 this._moveLibraryResourceNode(node);
675 function sbDeviceServicePane__getNodeIndexFromClassName(aNode) {
676 const K_TYPES = [
"audio",
"video",
"podcast"];
677 var
types = aNode.className.split(/\s/);
679 for (let
i = 0;
i < types.length; ++
i) {
680 if ((index = K_TYPES.indexOf(types[
i])) > -1)
695 function sbDeviceServicePane__moveLibraryResourceNode(aNode) {
696 var resource = this._libraryServicePane.getLibraryResourceForNode(aNode);
700 if (!(resource instanceof
Ci.sbIMediaList)) {
704 var device = this._deviceMgr.getDeviceForItem(resource);
711 var functions = device.capabilities.getSupportedFunctionTypes({});
713 "audio":
Ci.sbIDeviceCapabilities.FUNCTION_AUDIO_PLAYBACK,
714 "video":
Ci.sbIDeviceCapabilities.FUNCTION_VIDEO_PLAYBACK
717 var props = aNode.className.split(/\s/);
718 props = props.filter(
function(
val)
val in CAPS_MAP);
721 if (functions.indexOf(CAPS_MAP[props[0]]) < 0) {
722 this.
log(
"Not moving library node " + aNode.id +
723 " to device node, capability not supported");
728 aNode.setAttributeNS(DEVICESP_NS,
"device-id", device.id);
729 aNode.setAttributeNS(DEVICESP_NS,
"deviceNodeType",
"library");
731 var deviceNode = this.getNodeForDevice(device);
732 if (deviceNode && aNode.parentNode != deviceNode) {
733 var index1 = this._getNodeIndexFromClassName(aNode);
735 dump(
"_moveLibraryResourceNode: Not in the node array??!!\n");
736 deviceNode.appendChild(aNode);
740 var child = deviceNode.firstChild;
742 var index2 = this._getNodeIndexFromClassName(child);
743 if (index2 == -1 || index1 < index2)
746 child = child.nextSibling;
748 deviceNode.insertBefore(aNode, child);
function logcall(parentArgs)
sbOSDControlService prototype className
function sbDeviceServicePane()
this _dialogInput val(dateText)
Javascript wrappers for common library tasks.
sbDeviceServicePane prototype _deviceURN
_getSelectedPageStyle s i
function DeviceLibraryItemUpdateListener()