sbDeviceServicePaneService.js
Go to the documentation of this file.
1 /* vim: set ts=2 sw=2 expandtab : */
2 /*
3  *=BEGIN SONGBIRD GPL
4  *
5  * This file is part of the Songbird web player.
6  *
7  * Copyright(c) 2005-2010 POTI, Inc.
8  * http://www.songbirdnest.com
9  *
10  * This file may be licensed under the terms of of the
11  * GNU General Public License Version 2 (the ``GPL'').
12  *
13  * Software distributed under the License is distributed
14  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
15  * express or implied. See the GPL for the specific language
16  * governing rights and limitations.
17  *
18  * You should have received a copy of the GPL along with this
19  * program. If not, go to http://www.gnu.org/licenses/gpl.html
20  * or write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  *
23  *=END SONGBIRD GPL
24  */
25 
30 const Cc = Components.classes;
31 const Ci = Components.interfaces;
32 const Cr = Components.results;
33 const Cu = Components.utils;
34 
35 const CONTRACTID = "@songbirdnest.com/servicepane/device;1";
36 
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#";
40 
41 const URN_PREFIX_DEVICE = "urn:device:";
42 const DEVICE_NODE_WEIGHT = -2;
43 
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");
50 
55 function logcall(parentArgs) {
56  dump("\n");
57  dump(parentArgs.callee.name + "(");
58  for (var i = 0; i < parentArgs.length; i++) {
59  dump(parentArgs[i]);
60  if (i < parentArgs.length - 1) {
61  dump(', ');
62  }
63  }
64  dump(")\n");
65 }
66 
67 
68 
74 function sbDeviceServicePane() {
75  this._servicePane = null;
76  this._libraryServicePane = null;
77 
78  // use the default stringbundle to translate tree nodes
79  this.stringbundle = null;
80 
81  this.log = DebugUtils.generateLogFunction("DeviceServicePaneService");
82 }
83 
85 // XPCOM Support //
87 sbDeviceServicePane.prototype.QueryInterface =
88  XPCOMUtils.generateQI([Ci.sbIServicePaneModule,
89  Ci.sbIServicePaneMutationListener,
90  Ci.sbIDeviceServicePaneService]);
91 sbDeviceServicePane.prototype.classDescription =
92  "Songbird Device Service Pane Service";
93 sbDeviceServicePane.prototype.classID =
94  Components.ID("{845c31ee-c30e-4fb6-9667-0b10e58c7069}");
95 sbDeviceServicePane.prototype.contractID =
96  CONTRACTID;
97 sbDeviceServicePane.prototype._xpcom_categories = [
98  {
99  category: 'service-pane',
100  entry: 'device', // we want this to load first
102  }];
103 
105 // sbIServicePaneModule //
107 
108 sbDeviceServicePane.prototype.servicePaneInit =
109 function sbDeviceServicePane_servicePaneInit(sps) {
110  //logcall(arguments);
111 
112  // keep track of the service pane services
113  this._servicePane = sps;
114  this._libraryServicePane = Cc["@songbirdnest.com/servicepane/library;1"]
115  .getService(Ci.sbILibraryServicePaneService);
116 
117  // load the device context menu document
118  this._deviceContextMenuDoc =
119  DOMUtils.loadDocument
120  ("chrome://songbird/content/xul/device/deviceContextMenu.xul");
121 
122  // cache the device manager
123  this._deviceMgr = Cc["@songbirdnest.com/Songbird/DeviceManager;2"]
124  .getService(Ci.sbIDeviceManager2);
125 
126  this._mainLibraryListeners = [];
127  this._deviceLibraryAndListenerObjs = [];
128 }
129 
130 sbDeviceServicePane.prototype.shutdown =
131 function sbDeviceServicePane_shutdown() {
132  // release object references
133  for (var i = 0; i < this._deviceLibraryAndListenerObjs.length; i++) {
134  var currObj = this._deviceLibraryAndListenerObjs[i];
135  currObj["library"].removeListener(currObj["listener"]);
136  }
137 
138  for (var i = 0; i < this._mainLibraryListeners.length; i++) {
139  LibraryUtils.mainLibrary.removeListener(this._mainLibraryListeners[i]);
140  }
141 
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;
150 }
151 
152 sbDeviceServicePane.prototype.fillContextMenu =
153 function sbDeviceServicePane_fillContextMenu(aNode, aContextMenu, aParentWindow) {
154  // Get the node device ID. Do nothing if not a device node.
155  var deviceID = aNode.getAttributeNS(DEVICESP_NS, "device-id");
156  if (!deviceID)
157  return;
158 
159  // Do nothing if not set to fill with the default device context menu items.
160  var fillDefaultContextMenu = aNode.getAttributeNS(DEVICESP_NS,
161  "fillDefaultContextMenu");
162  if (fillDefaultContextMenu != "true")
163  return;
164 
165  // Get the device node type.
166  var deviceNodeType = aNode.getAttributeNS(DEVICESP_NS, "deviceNodeType");
167 
168  // Import device context menu items into the context menu.
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 });
181  }
182 }
183 
184 sbDeviceServicePane.prototype.fillNewItemMenu =
185 function sbDeviceServicePane_fillNewItemMenu(aNode, aContextMenu, aParentWindow) {
186 }
187 
188 sbDeviceServicePane.prototype.onSelectionChanged =
189 function sbDeviceServicePane_onSelectionChanged(aNode, aContainer, aParentWindow) {
190 }
191 
192 sbDeviceServicePane.prototype.canDrop =
193 function sbDeviceServicePane_canDrop(aNode, aDragSession, aOrientation, aWindow) {
194  return false;
195 }
196 
197 sbDeviceServicePane.prototype.onDrop =
198 function sbDeviceServicePane_onDrop(aNode, aDragSession, aOrientation, aWindow) {
199 }
200 
201 sbDeviceServicePane.prototype.onDragGesture =
202 function sbDeviceServicePane_onDragGesture(aNode, aDataTransfer) {
203  return false;
204 }
205 
206 
210 sbDeviceServicePane.prototype.onBeforeRename =
211 function sbDeviceServicePane_onBeforeRename(aNode) {
212 }
213 
217 sbDeviceServicePane.prototype.onRename =
218 function sbDeviceServicePane_onRename(aNode, aNewName) {
219 }
220 
221 
223 // sbIDeviceServicePaneService //
225 
226 sbDeviceServicePane.prototype.createNodeForDevice =
227 function sbDeviceServicePane_createNodeForDevice(aDevice, aDeviceIdentifier) {
228  //logcall(arguments);
229  this.log("createNodeForDevice");
230 
231  // Make sure the devices group exists first
232  let devicesNode = this._ensureDevicesGroupExists();
233 
234  // Get the Node.
235  var id = this._deviceURN(aDevice, aDeviceIdentifier);
236  var node = this._servicePane.getNode(id);
237  if (!node) {
238  // Create the node
239  node = this._servicePane.createNode();
240  node.id = id;
241  }
242 
243  // Refresh the information just in case it is supposed to change
244  node.contractid = CONTRACTID;
245  node.setAttributeNS(SP, "Weight", DEVICE_NODE_WEIGHT);
246  node.editable = false;
247 
248  // Add the node
249  if (!node.parentNode) {
250  this.log("\tNo parentNode, appending to devices group node");
251  devicesNode.appendChild(node);
252  }
253 
254  return node;
255 }
256 
257 sbDeviceServicePane.prototype.createNodeForDevice2 =
258 function sbDeviceServicePane_createNodeForDevice2(aDevice, aEjectable) {
259  this.log("createNodeForDevice2");
260 
261  // Make sure the devices group exists first
262  let devicesNode = this._ensureDevicesGroupExists();
263 
264  // Get the Node.
265  var id = this._deviceURN2(aDevice);
266 
267  var node = this._servicePane.getNode(id);
268  if (!node) {
269  // Create the node
270  node = this._servicePane.createNode();
271  node.id = id;
272  }
273 
274  // Refresh the information just in case it is supposed to change
275  node.contractid = CONTRACTID;
276  node.setAttributeNS(DEVICESP_NS, "device-id", aDevice.id);
277  node.setAttributeNS(DEVICESP_NS, "deviceNodeType", "device");
278  node.setAttributeNS(SP, "Weight", DEVICE_NODE_WEIGHT);
279  if (aEjectable) {
280  node.setAttribute("ejectable", "true");
281  let listener = new _deviceNodeEventListener(aDevice);
282  node.addEventListener(listener);
283  }
284  node.editable = false;
285  node.className = "device";
286 
287  try {
288  var iconUri = aDevice.properties.iconUri;
289  if (iconUri) {
290  var spec = iconUri.spec;
291  if (iconUri.schemeIs("file") && /\.ico$/i(spec)) {
292  // for *.ico, try to get the small icon
293  spec = "moz-icon://" + spec + "?size=16";
294  }
295  node.image = spec;
296  }
297  } catch(ex) {
298  /* we do not care if setting the icon fails */
299  }
300 
301  // Add the node
302  if (!node.parentNode) {
303  this.log("\tNo parentNode, appending to devices group node");
304  devicesNode.appendChild(node);
305  }
306 
307  this._device = aDevice;
308  return node;
309 }
310 
311 sbDeviceServicePane.prototype.createLibraryNodeForDevice =
312 function sbDeviceServicePane_createLibraryNodeForDevice(aDevice, aLibrary) {
313  this.log("Creating library nodes for device " + aDevice.id);
314  var deviceNode = this.getNodeForDevice(aDevice);
315 
316  // Create the library nodes and move them underneath the device node
317  this._libraryServicePane.createNodeForLibrary(aLibrary);
318  this._moveLibraryNodes(aLibrary);
319 
320  /* Add a listener to detect when a device library item's originItemGuid
321  * property is updated.
322  * We use this listener to detect when a medialist has its originItemGuid
323  * changed which will occur when the medialist is imporpied into the main
324  * library and will likely mean we should remove its 'deviceonly' icon */
325  var deviceUpdateListener = new DeviceLibraryItemUpdateListener();
326  var listenToPropsArray =
327  Cc["@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1"]
328  .createInstance(Ci.sbIMutablePropertyArray);
329  listenToPropsArray.appendProperty(SBProperties.originItemGuid, "");
330  aLibrary.addListener(deviceUpdateListener,
331  false,
332  Ci.sbIMediaList.LISTENER_FLAGS_ITEMUPDATED,
333  listenToPropsArray);
334  var deviceLibListenerObj = {
335  library: aLibrary,
336  listener: deviceUpdateListener
337  };
338 
339  this._deviceLibraryAndListenerObjs.push(deviceLibListenerObj);
340 
341  /* Add a listener to the main library to detect when a medialist is removed.
342  * This listener, when a medialist is removed, checks if there is an item
343  * on the device whose originItemGuid pointed to the removed medialist and, if
344  * so, labels the device medialist with the 'deviceonly' icon. */
345  var mainLibraryRemovedListener = new MainLibraryItemRemovedListener(aLibrary);
346  LibraryUtils.mainLibrary.addListener
347  (mainLibraryRemovedListener,
348  false,
349  Ci.sbIMediaList.LISTENER_FLAGS_AFTERITEMREMOVED,
350  null);
351  this._mainLibraryListeners.push(mainLibraryRemovedListener);
352 
353  return this._libraryServicePane.getNodeForLibraryResource(aLibrary);
354 }
355 
356 sbDeviceServicePane.prototype.getNodeForDevice =
357 function sbDeviceServicePane_getNodeForDevice(aDevice) {
358  // Get the Node.
359  var id = this._deviceURN2(aDevice);
360  return this._servicePane.getNode(id);
361 }
362 
363 sbDeviceServicePane.prototype.setFillDefaultContextMenu =
364 function sbDeviceServicePane_setFillDefaultContxtMenu(aNode,
365  aEnabled) {
366  if (aEnabled) {
367  aNode.setAttributeNS(DEVICESP_NS, "fillDefaultContextMenu", "true");
368  } else {
369  aNode.setAttributeNS(DEVICESP_NS, "fillDefaultContextMenu", "false");
370  }
371 }
372 
373 sbDeviceServicePane.prototype.insertChildByName =
374 function sbDeviceServicePane_insertChildByName(aDevice, aChild) {
375  var lastNode = null;
376  var deviceNode = this.getNodeForDevice(aDevice);
377  for (let node = deviceNode.firstChild; node; node = node.nextSibling) {
378  var listType = node.getAttributeNS(LSP, "ListType");
379  // Ignore library node.
380  if (listType == "library") {
381  continue;
382  }
383 
384  // Find the node to insert before. Ignore case.
385  var childname = aChild.name ? aChild.name.toLowerCase() : aChild.name;
386  var nodename = node.name ? node.name.toLowerCase() : node.name;
387  if (childname < nodename) {
388  lastNode = node;
389  break;
390  }
391  }
392 
393  // Insert before the node found, or insert at the end if lastNode is null.
394  deviceNode.insertBefore(aChild, lastNode);
395 
396  // If we are inserting a medialist node, check if it is deviceonly
397  if (aChild.className.match(/medialist/) != null) {
398 
399  /* The node looks like a medialist. We'll get its resource, check that
400  * it's a medialist, and look for an item in the mainLibrary that has a
401  * guid matching its originGUID. If we can't find one, we'll label the
402  * node as representing a deviceonly medialist */
403  var resource = this._libraryServicePane.getLibraryResourceForNode(aChild);
404  if (resource instanceof Ci.sbIMediaList &&
405  !LibraryUtils.getMainLibraryOriginItem(resource)) {
406  var classes = aChild.className.split(/\s/);
407  classes.push("medialisttype-deviceonly");
408  aChild.className = classes.join(' ');
409  }
410  }
411 }
412 
414 // sbIServicePaneMutationListener //
416 function _deviceNodeEventListener(aDevice) {
417  this._device = aDevice;
418 }
419 _deviceNodeEventListener.prototype = {
420  handleEvent: function sbDeviceServicePane_handleEvent(aEventName) {
421  switch (aEventName) {
422  case "eject":
423  try {
424  this._device.eject();
425  } catch (e) {
426  dump("Exception in sbDeviceServicePane event listener: " + e + "\n");
427  }
428  break;
429  }
430  }
431 }
432 
434 // sbIServicePaneMutationListener //
436 sbDeviceServicePane.prototype.attrModified =
437 function sbDeviceServicePane_attrModified(aNode, aAttrName, aNamespace,
438  aOldVal, aNewVal) {
439  // Ensure that the parent device's node reflects any changes.
440  this._updateParentDeviceNode();
441 };
442 
443 sbDeviceServicePane.prototype.nodeInserted =
444 function sbDeviceServicePane_nodeInserted(aNode, aParent, aInsertBefore) {
445  // Ensure that the parent device's node reflects any changes.
446  this._updateParentDeviceNode();
447 };
448 
449 sbDeviceServicePane.prototype.nodeRemoved =
450 function sbDeviceServicePane_nodeRemoved(aNode, aParent) {
451  // Ensure that the parent device's node reflects any changes.
452  this._updateParentDeviceNode();
453 };
454 
456 // DeviceLibraryItemUpdateListener //
458 /* This listener detects when the originItemGuid of an item in the mainlibrary
459  * is updated. If the item is a medialist, we check if there is an item in the
460  * main library with a guid matching that originItemGuid. If there is not, we
461  * label the medialist with a 'deviceonly' icon in the servicepane.
462  * We are unconcerned with mediaitems as they are labeled 'deviceonly'
463  * separately */
465 }
466 
468  onItemUpdated: function DeviceLibraryItemUpdateListener_onItemUpdated
469  (aMediaList, aMediaItem, aProperties) {
470 
471  // only deal with medialists
472  if (!(aMediaItem instanceof Ci.sbIMediaList)) {
473  return true;
474  }
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/);
479 
480  /* Check if there is an item in the main library with a guid corresponding
481  * to this medialist's originItemGuid. */
482  if (!LibraryUtils.getMainLibraryOriginItem(aMediaItem)) {
483  // no corresponding item in the main library, label as deviceonly
484  classes.push("medialisttype-deviceonly");
485  }
486  else {
487  /* Corresponding item in the main library, this is not deviceonly
488  * so remove the 'medialisttype-deviceonly' class if it exists */
489  classes = classes.filter(function(aClass) {
490  return aClass != "medialisttype-deviceonly";
491  });
492  }
493  node.className = classes.join(' ');
494  }
495 }
496 
498 // MainLibraryItemRemovedListener //
500 /* This listener detects when a medialist is removed from the mainlibrary and
501  * checks if there is a medialist on this device whose originItemGuid pointed to
502  * the removed item's guid. If there was, that device medialist should now be
503  * marked as deviceonly. */
504 function MainLibraryItemRemovedListener(devLibrary) {
505  this.deviceLibrary = devLibrary;
506 }
507 
508 MainLibraryItemRemovedListener.prototype = {
509  onAfterItemRemoved: function MainLibraryItemRemovedListener_onAfterItemRemoved
510  (aMediaList, aMediaItem, aIndex) {
511 
512  // only concerned with medialists that are removed
513  if (!(aMediaItem instanceof Ci.sbIMediaList)) {
514  return true;
515  }
516 
517  /* Check for items on the device whose originItemGuid pointed to the removed
518  * medialist's guid */
519  var foundLists = this.deviceLibrary.getItemsByProperty
520  (SBProperties.originItemGuid,
521  aMediaItem.guid);
522  var libSPS = Cc["@songbirdnest.com/servicepane/library;1"]
523  .getService(Ci.sbILibraryServicePaneService);
524 
525  for (let i = 0; i < foundLists.length; i++) {
526 
527  // We found an item of interest, check if its node was already 'deviceonly'
528  var foundList = foundLists.queryElementAt(i, Ci.sbIMediaItem);
529 
530  var node = libSPS.getNodeForLibraryResource(foundList);
531 
532  if (node && node.className.match(/medialisttype-deviceonly/) == null) {
533 
534  /* The device medialist whose originItemGuid corresponded to the removed
535  * medialist's guid was not labeled 'deviceonly' and should be. */
536  var classes = node.className.split(/\s/);
537  classes.push("medialisttype-deviceonly");
538  node.className = classes.join(" ");
539  return true;
540  }
541  }
542  }
543 }
544 
546 // Private Methods //
548 
552 sbDeviceServicePane.prototype._updateParentDeviceNode =
553 function sbDeviceServicePane__updateParentDeviceNode() {
554  try {
555  // Check to see if the devices group should be hidden or not
556  let hidden = true;
557  let devicesNode = this._servicePane.getNode("SB:Devices");
558  if (!devicesNode) {
559  // there's no devices to look at, we don't care
560  return;
561  }
562  for (let node = devicesNode.firstChild; node; node = node.nextSibling) {
563  if (node && !node.hidden) {
564  hidden = false;
565  break;
566  }
567  }
568 
569  if (devicesNode.hidden != hidden) {
570  this.log("Hiding devices node since all children are gone or hidden");
571  devicesNode.hidden = hidden;
572  }
573  }
574  catch (e) {
575  this.log("Execption updating device node: " + e);
576  }
577 };
578 
582 sbDeviceServicePane.prototype._deviceURN =
583 function sbDeviceServicePane__deviceURN(aDevice, aDeviceIdentifier) {
584  return URN_PREFIX_DEVICE + aDevice.deviceCategory + ":" + aDeviceIdentifier;
585 }
586 
590 sbDeviceServicePane.prototype._ensureDevicesGroupExists =
591 function sbDeviceServicePane__ensureDevicesGroupExists() {
592  this.log("ensureDevicesGroupExists");
593  let fnode = this._servicePane.getNode("SB:Devices");
594  if (!fnode) {
595  // make sure it exists
596  fnode = this._servicePane.createNode();
597  fnode.id = "SB:Devices";
598  fnode.name = "&servicesource.devices";
599  this._addClassNames(fnode, ["folder", this._makeCSSProperty(fnode.name)]);
600  fnode.contractid = CONTRACTID;
601  // XXXstevel need to set fnode.dndAcceptIn?
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");
608  }
609 
610  return fnode;
611 }
612 
613 sbDeviceServicePane.prototype._addClassNames =
614 function sbDeviceServicePane__addClassNames(aNode, aList) {
615  let className = aNode.className || "";
616  let existing = {};
617  for each (let name in className.split(" "))
618  existing[name] = true;
619 
620  for each (let name in aList)
621  if (!existing.hasOwnProperty(name))
622  className += (className ? " " : "") + name;
623 
624  aNode.className = className;
625 }
626 
627 
628 sbDeviceServicePane.prototype._makeCSSProperty =
629 function sbDeviceServicePane__makeCSSProperty(aString) {
630  if ( aString[0] == "&" ) {
631  aString = aString.substr(1, aString.length);
632  aString = aString.replace(/\./g, "-");
633  }
634  return aString;
635 }
636 
637 
638 sbDeviceServicePane.prototype._deviceURN2 =
639 function sbDeviceServicePane__deviceURN2(aDevice) {
640  var id = "" + aDevice.id;
641 
642  if(id.charAt(0) == "{" &&
643  id.charAt(-1) == "}") {
644  id = id.substring(1, -1);
645  }
646 
647 
648  return URN_PREFIX_DEVICE + id;
649 }
650 
651 
658 sbDeviceServicePane.prototype._moveLibraryNodes =
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);
665  }
666 }
667 
668 
674 sbDeviceServicePane.prototype._getNodeIndexFromClassName =
675 function sbDeviceServicePane__getNodeIndexFromClassName(aNode) {
676  const K_TYPES = ["audio", "video", "podcast"];
677  var types = aNode.className.split(/\s/);
678  var index = -1;
679  for (let i = 0; i < types.length; ++i) {
680  if ((index = K_TYPES.indexOf(types[i])) > -1)
681  break;
682  }
683 
684  return index;
685 }
686 
687 
694 sbDeviceServicePane.prototype._moveLibraryResourceNode =
695 function sbDeviceServicePane__moveLibraryResourceNode(aNode) {
696  var resource = this._libraryServicePane.getLibraryResourceForNode(aNode);
697  if (!resource) {
698  return;
699  }
700  if (!(resource instanceof Ci.sbIMediaList)) {
701  // not a media list, we don't care
702  return;
703  }
704  var device = this._deviceMgr.getDeviceForItem(resource);
705  if (!device) {
706  // not a device playlist
707  return;
708  }
709 
710  // Only move nodes that the device supports
711  var functions = device.capabilities.getSupportedFunctionTypes({});
712  const CAPS_MAP = {
713  "audio": Ci.sbIDeviceCapabilities.FUNCTION_AUDIO_PLAYBACK,
714  "video": Ci.sbIDeviceCapabilities.FUNCTION_VIDEO_PLAYBACK
715  };
716 
717  var props = aNode.className.split(/\s/);
718  props = props.filter(function(val) val in CAPS_MAP);
719  // there should only be one anyway...
720  // assert(props.length < 2);
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");
724  return;
725  }
726 
727  // Set up the device library node info.
728  aNode.setAttributeNS(DEVICESP_NS, "device-id", device.id);
729  aNode.setAttributeNS(DEVICESP_NS, "deviceNodeType", "library");
730 
731  var deviceNode = this.getNodeForDevice(device);
732  if (deviceNode && aNode.parentNode != deviceNode) {
733  var index1 = this._getNodeIndexFromClassName(aNode);
734  if (index1 == -1) {
735  dump("_moveLibraryResourceNode: Not in the node array??!!\n");
736  deviceNode.appendChild(aNode);
737  return;
738  }
739 
740  var child = deviceNode.firstChild;
741  while (child) {
742  var index2 = this._getNodeIndexFromClassName(child);
743  if (index2 == -1 || index1 < index2)
744  break;
745 
746  child = child.nextSibling;
747  }
748  deviceNode.insertBefore(aNode, child);
749  }
750 }
751 
753 // XPCOM //
755 
756 var NSGetModule = XPCOMUtils.generateNSGetModule([sbDeviceServicePane]);
classDescription entry
Definition: FeedWriter.js:1427
function logcall(parentArgs)
menuItem id
Definition: FeedWriter.js:971
sbOSDControlService prototype className
function sbDeviceServicePane()
const CONTRACTID
function log(s)
const char * types
const URN_PREFIX_DEVICE
this _dialogInput val(dateText)
return null
Definition: FeedWriter.js:1143
let node
countRef value
Definition: FeedWriter.js:1423
Javascript wrappers for common library tasks.
var hidden
sbDeviceServicePane prototype _deviceURN
const DEVICE_NODE_WEIGHT
_getSelectedPageStyle s i
function DeviceLibraryItemUpdateListener()