48 "ExternalDropHandler",
49 "InternalDropHandler" ];
51 const Cc = Components.classes;
52 const Ci = Components.interfaces;
53 const Cr = Components.results;
54 const Ce = Components.Exception;
55 const Cu = Components.utils;
58 "chrome://songbird/skin/base-elements/icon-generic-addon.png";
60 Cu.import(
"resource://gre/modules/XPCOMUtils.jsm");
62 Cu.import(
"resource://app/jsmodules/ArrayConverter.jsm");
63 Cu.import(
"resource://app/jsmodules/sbProperties.jsm");
64 Cu.import(
"resource://app/jsmodules/SBJobUtils.jsm");
65 Cu.import(
"resource://app/jsmodules/sbLibraryUtils.jsm");
66 Cu.import(
"resource://app/jsmodules/SBUtils.jsm");
67 Cu.import(
"resource://app/jsmodules/StringUtils.jsm");
70 "@songbirdnest.com/Songbird/Library/medialistduplicatefilter;1";
83 isSupported:
function(aDragSession, aFlavourArray) {
84 for (var
i=0;
i<aFlavourArray.length;
i++) {
85 if (aDragSession.isDataFlavorSupported(aFlavourArray[
i])) {
93 addFlavours:
function(aFlavourSet, aFlavourArray) {
94 for (var
i=0;
i<aFlavourArray.length;
i++) {
95 aFlavourSet.appendFlavour(aFlavourArray[
i]);
100 getTransferDataForFlavour:
function(aFlavour, aSession, aArray) {
102 var dragService =
Cc[
"@mozilla.org/widget/dragservice;1"]
103 .getService(
Ci.nsIDragService);
104 aSession = dragService.getCurrentSession();
107 var nitems = aSession.numDropItems;
110 if (aSession.isDataFlavorSupported(aFlavour)) {
111 var transfer =
Cc[
"@mozilla.org/widget/transferable;1"]
112 .createInstance(
Ci.nsITransferable);
113 transfer.addDataFlavor(aFlavour);
115 for (var
i=0;
i<nitems;
i++) {
116 aSession.getData(transfer,
i);
119 transfer.getTransferData(aFlavour, data, length);
120 if (!r) r = data.value;
121 if (aArray) aArray.push([data.value, length.value, aFlavour]);
131 getInternalTransferDataForFlavour:
function(aSession, aFlavour, aInterface) {
132 var
data = this.getTransferDataForFlavour(aFlavour, aSession);
134 return this.getInternalTransferData(data, aInterface);
140 getInternalTransferData:
function(
aData, aInterface) {
142 var dnd = Components.classes[
"@songbirdnest.com/Songbird/DndSourceTracker;1"]
143 .getService(
Ci.sbIDndSourceTracker);
144 var source = dnd.getSourceSupports(
aData);
146 return source.QueryInterface(aInterface);
150 getTransferData:
function(aSession, aFlavourArray) {
154 var
data =
new Array(aSession.numDropItems);
155 for (var
i=0;
i<aFlavourArray.length;
i++) {
156 if (this.getTransferDataForFlavour(aFlavourArray[
i], aSession, data))
163 customReport:
function(aMessage) {
165 Components.Constructor(
"@songbirdnest.com/Songbird/DataRemote;1",
168 var statusOverrideText =
170 var statusOverrideType =
173 statusOverrideText.stringValue =
"";
174 statusOverrideText.stringValue = aMessage;
175 statusOverrideType.stringValue =
"report";
181 reportAddedTracks:
function(aAdded, aDups, aUnsupported, aDestName, aIsDevice) {
189 if (aDups && aUnsupported) {
191 [aAdded, aDestName, aDups, aUnsupported]);
195 [aAdded, aDestName, aDups]);
197 else if (aUnsupported) {
199 [aAdded, aDestName, aUnsupported]);
203 [aAdded, aDestName]);
206 this.customReport(msg);
211 standardReport:
function(aTargetList,
215 aInsertedInMediaList,
219 if ((aImportedInLibrary == 0) &&
220 (aInsertedInMediaList == 0) &&
221 (aDuplicates == 0) &&
222 (aUnsupported == 0) &&
223 (aOtherDropsHandled != 0))
228 if (aTargetList != aTargetList.library) {
229 DNDUtils.reportAddedTracks(aInsertedInMediaList,
235 DNDUtils.reportAddedTracks(aImportedInLibrary,
250 DNDUtils.MediaListViewSelectionTransferContext =
function (mediaListView) {
252 this.indexedItems =
null;
253 this.source = mediaListView.mediaList;
254 this.
count = mediaListView.selection.count;
255 this._mediaListView = mediaListView;
258 DNDUtils.MediaListViewSelectionTransferContext.prototype = {
262 var enumerator =
Cc[
"@songbirdnest.com/Songbird/Library/EnumeratorWrapper;1"]
263 .createInstance(
Ci.sbIMediaListEnumeratorWrapper);
264 enumerator.initialize(this._mediaListView
266 .selectedIndexedMediaItems);
267 this.items = enumerator;
270 this.indexedItems = this._mediaListView.selection.selectedIndexedMediaItems;
273 if (iid.equals(Components.interfaces.sbIMediaItemsTransferContext) ||
274 iid.equals(Components.interfaces.nsISupports))
276 throw Components.results.NS_NOINTERFACE;
286 DNDUtils.EntireMediaListViewTransferContext =
function(view) {
288 this.indexedItems =
null;
289 this.source = view.mediaList;
290 this.
count = view.length;
291 this._mediaListView = view;
294 DNDUtils.EntireMediaListViewTransferContext.prototype = {
301 return this.
i < that._mediaListView.length;
303 getNext :
function() {
304 var item = that._mediaListView.getItemByIndex(this.
i++);
305 item.setProperty(SBProperties.downloadStatusTarget,
306 item.library.guid +
"," + item.guid);
310 if (iid.equals(Components.interfaces.nsISimpleEnumerator) ||
311 iid.equals(Components.interfaces.nsISupports))
313 throw Components.results.NS_NOINTERFACE;
318 if (iid.equals(Components.interfaces.sbIMediaItemsTransferContext) ||
319 iid.equals(Components.interfaces.nsISupports))
321 throw Components.results.NS_NOINTERFACE;
332 DNDUtils.MediaListTransferContext =
function (item, mediaList) {
335 this.source = mediaList;
338 DNDUtils.MediaListTransferContext.prototype = {
340 if (iid.equals(Components.interfaces.sbIMediaListTransferContext) ||
341 iid.equals(Components.interfaces.nsISupports))
343 throw Components.results.NS_NOINTERFACE;
412 const TYPE_X_SB_TRANSFER_MEDIA_ITEM =
"application/x-sb-transfer-media-item";
416 var InternalDropHandler = {
418 supportedFlavours: [ TYPE_X_SB_TRANSFER_MEDIA_ITEM,
423 isSupported:
function(aDragSession) {
424 return DNDUtils.isSupported(aDragSession, this.supportedFlavours);
429 drop:
function(aWindow, aDragSession, aListener) {
430 var mainLibrary =
Cc[
"@songbirdnest.com/Songbird/library/Manager;1"]
431 .getService(
Ci.sbILibraryManager)
433 this.dropOnList(aWindow, aDragSession, mainLibrary, -1, aListener);
439 dropOnList:
function(aWindow,
445 throw new Error(
"No target medialist specified for dropOnList");
447 this._dropItems(aDragSession,
455 addFlavours:
function(aFlavourSet) {
456 DNDUtils.addFlavours(aFlavourSet, this.supportedFlavours);
460 getTransferData:
function(aSession) {
461 return DNDUtils.getTransferData(aSession, this.supportedFlavours);
466 getTransferDataForFlavour:
function(aFlavour, aSession, aArray) {
467 return DNDUtils.getTransferDataForFlavour(aFlavour, aSession, aArray);
485 _dropItems:
function(aDragSession, aTargetList, aDropPosition, aListener) {
487 if (aDragSession.isDataFlavorSupported(TYPE_X_SB_TRANSFER_MEDIA_LIST)) {
488 this._dropItemsList(aDragSession, aTargetList, aDropPosition, aListener);
490 this._dropItemsItems(aDragSession, aTargetList, aDropPosition, aListener);
497 _doesDeviceSupportPlaylist:
function(aDevice) {
501 var capabilities = aDevice.capabilities;
502 var sbIDC =
Ci.sbIDeviceCapabilities;
504 if (capabilities.supportsContent(sbIDC.FUNCTION_DEVICE,
505 sbIDC.CONTENT_PLAYLIST) ||
506 capabilities.supportsContent(sbIDC.FUNCTION_AUDIO_PLAYBACK,
507 sbIDC.CONTENT_PLAYLIST)) {
517 _getTransferForDeviceChanges:
function(aDevice, aSourceItems, aSourceList,
519 var differ =
Cc[
"@songbirdnest.com/Songbird/Device/DeviceLibrarySyncDiff;1"]
520 .createInstance(
Ci.sbIDeviceLibrarySyncDiff);
524 sourceLibrary = aSourceItems.queryElementAt(0,
Ci.sbIMediaItem).library;
526 sourceLibrary = aSourceList.library;
530 differ.generateDropLists(sourceLibrary,
537 return {changeset: changeset.value, items: destItems.value};
540 _notifyListeners:
function(aListener, aTargetList, aNewList, aSourceItems,
541 aSourceList, aIsDevice) {
542 var sourceLength = 0;
545 sourceLength = aSourceList.length;
546 else if (aSourceItems)
547 sourceLength = aSourceItems.length;
552 aListener.onCopyMediaList(aTargetList, aNewList);
556 aListener.onFirstMediaItem(aSourceList.getItemByIndex(0));
557 else if (aSourceItems)
558 aListener.onFirstMediaItem(
559 aSourceItems.queryElementAt(0,
Ci.sbIMediaItem));
565 this._dropComplete(aListener,
577 _getDeviceLibraryForItem:
function(aDevice, aItem) {
578 var lib = aItem.library;
580 var libs = aDevice.content.libraries;
581 for (var
i = 0;
i < libs.length;
i++) {
582 var deviceLib = libs.queryElementAt(
i,
Ci.sbIDeviceLibrary);
583 if (lib.equals(deviceLib))
592 _dropListFromDevice:
function(aDevice, aSourceList, aTargetList,
593 aDropPosition, aListener)
596 var changes = this._getTransferForDeviceChanges(aDevice,
597 null, aSourceList, aTargetList.library);
598 var changeset = changes.changeset;
600 var targetLibrary = aTargetList.library;
602 aDevice.importFromDevice(targetLibrary, changeset);
606 var changes = changeset.changes;
607 for (var
i = 0;
i < changes.length;
i++) {
608 var change = changes.queryElementAt(
i,
Ci.sbILibraryChange);
609 if (change.itemIsList) {
610 if (change.operation ==
Ci.sbIChangeOperation.ADD) {
612 change.sourceItem.getProperty(SBProperties.originItemGuid);
613 newlist = targetLibrary.getItemByGuid(originGUID);
619 this._notifyListeners(aListener, aTargetList, newlist,
620 null, aSourceList,
true);
623 _dropItemsFromDevice:
function(aDevice, aSourceItems, aTargetList,
624 aDropPosition, aListener)
627 var changes = this._getTransferForDeviceChanges(aDevice,
628 aSourceItems,
null, aTargetList.library);
629 var changeset = changes.changeset;
631 var targetLibrary = aTargetList.library;
633 aDevice.importFromDevice(targetLibrary, changeset);
635 if (aTargetList.library != aTargetList) {
638 if (aTargetList instanceof
Ci.sbIOrderableMediaList &&
639 aDropPosition != -1) {
640 aTargetList.insertSomeBefore(aDropPosition,
641 ArrayConverter.enumerator(changes.items));
644 aTargetList.addSome(ArrayConverter.enumerator(changes.items));
648 this._notifyListeners(aListener, aTargetList,
null,
649 aSourceItems,
null,
true);
656 _dropListOnDevice:
function(aDevice, aSourceList, aTargetList,
657 aDropPosition, aListener) {
659 var changes = this._getTransferForDeviceChanges(aDevice,
660 null, aSourceList, aTargetList.library);
661 var changeset = changes.changeset;
663 var deviceLibrary = this._getDeviceLibraryForItem(aDevice, aTargetList);
669 aDevice.exportToDevice(deviceLibrary, changeset);
673 var changes = changeset.changes;
674 for (var
i = 0;
i < changes.length;
i++) {
675 var change = changes.queryElementAt(
i,
Ci.sbILibraryChange);
676 if (change.itemIsList) {
677 if (change.operation ==
Ci.sbIChangeOperation.ADD) {
679 this.deviceLibrary.getItemsByProperty(SBProperties.originItemGuid,
680 change.sourceItem.guid);
681 if (foundLists.length > 0) {
682 newlist = foundLists[0];
689 this._notifyListeners(aListener, aTargetList, newlist,
690 null, aSourceList,
true);
696 _dropItemsOnDevice:
function(aDevice, aSourceItems, aTargetList,
697 aDropPosition, aListener) {
699 var changes = this._getTransferForDeviceChanges(aDevice,
700 aSourceItems,
null, aTargetList.library);
701 var changeset = changes.changeset;
703 var deviceLibrary = this._getDeviceLibraryForItem(aDevice, aTargetList);
708 aDevice.exportToDevice(deviceLibrary, changeset);
710 if (aTargetList.library != aTargetList) {
713 if (aTargetList instanceof
Ci.sbIOrderableMediaList &&
714 aDropPosition != -1) {
715 aTargetList.insertSomeBefore(aDropPosition,
716 ArrayConverter.enumerator(changes.items));
719 aTargetList.addSome(ArrayConverter.enumerator(changes.items));
723 this._notifyListeners(aListener, aTargetList,
null,
724 aSourceItems,
null,
true);
728 _dropItemsSimple:
function(aItems, aTargetList, aDropPosition, aListener) {
729 if (aTargetList instanceof
Ci.sbIOrderableMediaList &&
730 aDropPosition != -1) {
731 aTargetList.insertSomeBefore(aDropPosition,
732 ArrayConverter.enumerator(aItems));
735 aTargetList.addSome(ArrayConverter.enumerator(aItems));
738 this._notifyListeners(aListener, aTargetList,
null, aItems,
null,
false);
742 _dropListSimple:
function(aSourceList, aTargetList,
743 aDropPosition, aListener) {
746 var targetIsLibrary = (aTargetList instanceof
Ci.sbILibrary);
747 if (targetIsLibrary) {
748 newlist = aTargetList.copyMediaList(
'simple', aSourceList,
false);
751 if (aTargetList instanceof
Ci.sbIOrderableMediaList &&
754 aTargetList.insertAllBefore(aDropPosition, aSourceList);
757 aTargetList.addAll(aSourceList);
761 this._notifyListeners(aListener, aTargetList, newlist,
null, aSourceList,
770 _dropItemsList:
function(aDragSession, aTargetList,
771 aDropPosition, aListener) {
772 var context = DNDUtils.
773 getInternalTransferDataForFlavour(aDragSession,
774 TYPE_X_SB_TRANSFER_MEDIA_LIST,
775 Ci.sbIMediaListTransferContext);
776 var sourceList = context.list;
777 if (sourceList == aTargetList) {
779 this._dropComplete(aListener, aTargetList, 0, context.count, 0, 0, 0,
785 var deviceManager =
Cc[
"@songbirdnest.com/Songbird/DeviceManager;2"]
786 .getService(
Ci.sbIDeviceManager2);
787 var destDevice = deviceManager.getDeviceForItem(aTargetList);
788 var sourceDevice = deviceManager.getDeviceForItem(sourceList);
792 if (aTargetList.library == aTargetList) {
794 this._dropListOnDevice(destDevice, sourceList, aTargetList,
795 aDropPosition, aListener);
800 items = this._itemsFromList(sourceList);
801 this._dropItemsOnDevice(destDevice, items, aTargetList,
802 aDropPosition, aListener);
805 else if (sourceDevice) {
807 if (aTargetList.library == aTargetList) {
809 this._dropListFromDevice(sourceDevice, sourceList, aTargetList,
810 aDropPosition, aListener);
814 items = this._itemsFromList(sourceList);
815 this._dropItemsFromDevice(destDevice, items, aTargetList,
816 aDropPosition, aListener);
821 this._dropListSimple(sourceList, aTargetList,
822 aDropPosition, aListener);
827 _itemsFromList:
function(list)
829 var items =
Cc[
"@mozilla.org/array;1"].createInstance(
Ci.nsIMutableArray);
831 onEnumerationBegin :
function(aMediaList) {
832 return Ci.sbIMediaListEnumerationListener.CONTINUE;
834 onEnumeratedItem :
function(aMediaList, aMediaItem) {
835 items.appendElement(aMediaItem,
false);
836 return Ci.sbIMediaListEnumerationListener.CONTINUE;
838 onEnumerationEnd :
function(aMediaList, aStatusCode) {
841 list.enumerateAllItems(listener,
Ci.sbIMediaList.ENUMERATIONTYPE_SNAPSHOT);
847 _itemsFromEnumerator:
function(itemEnum) {
848 var items =
Cc[
"@mozilla.org/array;1"].createInstance(
Ci.nsIMutableArray);
850 while (itemEnum.hasMoreElements())
851 items.appendElement(itemEnum.getNext(),
false);
861 _dropItemsItems:
function(aDragSession, aTargetList,
862 aDropPosition, aListener) {
863 var context = DNDUtils.
864 getInternalTransferDataForFlavour(aDragSession,
866 Ci.sbIMediaItemsTransferContext);
868 var itemEnumerator = context.items;
870 var items = this._itemsFromEnumerator(itemEnumerator);
874 if (aTargetList instanceof
Ci.sbILibrary) {
875 if (items.length > 0 &&
876 items.queryElementAt(0,
Ci.sbIMediaItem).library == aTargetList)
879 this._dropComplete(aListener, aTargetList, 0, context.count, 0, 0, 0,
885 var deviceManager =
Cc[
"@songbirdnest.com/Songbird/DeviceManager;2"]
886 .getService(
Ci.sbIDeviceManager2);
887 var destDevice = deviceManager.getDeviceForItem(aTargetList);
888 var sourceDevice =
null;
889 if (items.length > 0)
890 sourceDevice = deviceManager.getDeviceForItem(
891 items.queryElementAt(0,
Ci.sbIMediaItem));
895 this._dropItemsOnDevice(destDevice, items, aTargetList,
896 aDropPosition, aListener);
898 else if (sourceDevice) {
899 this._dropItemsFromDevice(sourceDevice, items, aTargetList,
900 aDropPosition, aListener);
905 this._dropItemsSimple(items, aTargetList,
906 aDropPosition, aListener);
922 if (
listener.onDropComplete(targetList,
928 DNDUtils.standardReport(targetList,
937 DNDUtils.standardReport(targetList,
1036 var ExternalDropHandler = {
1038 supportedFlavours: [
"application/x-moz-file",
1043 isSupported:
function(aDragSession) {
1044 return DNDUtils.isSupported(aDragSession, this.supportedFlavours);
1049 drop:
function(aWindow, aDragSession, aListener) {
1050 var mainLibrary =
Cc[
"@songbirdnest.com/Songbird/library/Manager;1"]
1051 .getService(
Ci.sbILibraryManager)
1053 this.dropOnList(aWindow, aDragSession, mainLibrary, -1, aListener);
1058 dropUrls:
function(aWindow, aUrlArray, aListener) {
1059 var mainLibrary =
Cc[
"@songbirdnest.com/Songbird/library/Manager;1"]
1060 .getService(
Ci.sbILibraryManager)
1062 this.dropUrlsOnList(aWindow, aUrlArray, mainLibrary, -1, aListener);
1068 dropOnList:
function(aWindow,
1074 throw new Error(
"No target medialist specified for dropOnList");
1076 this._dropFiles(aWindow,
1087 dropUrlsOnList:
function(aWindow,
1093 throw new Error(
"No target medialist specified for dropOnList");
1095 this._dropFiles(aWindow,
1105 addFlavours:
function(aFlavourSet) {
1106 DNDUtils.addFlavours(aFlavourSet, this.supportedFlavours);
1110 getTransferData:
function(aSession) {
1111 return DNDUtils.getTransferData(aSession, this.supportedFlavours);
1116 getTransferDataForFlavour:
function(aFlavour, aSession, aArray) {
1117 return DNDUtils.getTransferDataForFlavour(aFlavour, aSession, aArray);
1141 if (session && !this.isSupported(session)) {
1146 var lcase = (this._getPlatformString() ==
"Windows_NT");
1149 var dropdata = session ? this.getTransferData(session) : urlarray;
1152 this._firstMediaItem =
null;
1161 var uriList =
Cc[
"@songbirdnest.com/moz/xpcom/threadsafe-array;1"]
1162 .createInstance(
Ci.nsIMutableArray);
1164 var
ioService =
Cc[
"@mozilla.org/network/io-service;1"]
1165 .getService(
Ci.nsIIOService);
1168 for (var dropentry in dropdata) {
1169 var dropitem = dropdata[dropentry];
1174 flavour = dropitem[2];
1177 flavour =
"text/x-moz-url";
1184 if (flavour ==
"application/x-moz-file") {
1185 var ioService =
Cc[
"@mozilla.org/network/io-service;1"]
1186 .getService(
Ci.nsIIOService);
1187 var fileHandler = ioService.getProtocolHandler(
"file")
1188 .QueryInterface(
Ci.nsIFileProtocolHandler);
1189 rawData = fileHandler.getURLSpecFromFile(item);
1192 if ( /\.(xpi|jar)$/
i.test(rawData) && (item instanceof
Ci.nsIFile) ) {
1193 xpiArray[item.leafName] = {
1196 toString:
function() {
return this.URL; }
1201 if (item instanceof
Ci.nsISupportsString) {
1202 rawData = item.toString();
1206 if (rawData.toLowerCase().indexOf(
"http://") >= 0) {
1209 }
else if (rawData.toLowerCase().indexOf(
"file://") >= 0) {
1220 var separator = rawData.indexOf(
"\n");
1221 if (separator != -1) {
1222 prettyName = rawData.substr(separator+1);
1223 rawData = rawData.substr(0,separator);
1227 if (lcase && islocal) {
1228 rawData = rawData.toLowerCase();
1232 uriList.appendElement(ioService.newURI(rawData,
null,
null),
false);
1237 window.setTimeout(
window.installXPIArray, 10, xpiArray);
1240 var uriImportService =
Cc[
"@songbirdnest.com/uri-import-service;1"]
1241 .getService(
Ci.sbIURIImportService);
1242 uriImportService.importURIArray(uriList,
1250 onImportComplete:
function(aTargetMediaList,
1262 device = aTargetMediaList.library.device;
1267 isDevice = (device !==
null);
1269 if (this._listener) {
1270 if (this._listener.onDropComplete(aTargetMediaList,
1276 DNDUtils.standardReport(aTargetMediaList,
1286 DNDUtils.standardReport(aTargetMediaList,
1297 onFirstMediaItem:
function(aTargetMediaList, aTargetMediaItem)
1299 if (this._listener) {
1300 this._listener.onFirstMediaItem(aTargetMediaList, aTargetMediaItem);
1305 _getPlatformString:
function() {
1308 Components.classes[
"@mozilla.org/system-info;1"]
1309 .getService(Components.interfaces.nsIPropertyBag2);
1310 return sysInfo.getProperty(
"name");
1313 var user_agent = navigator.userAgent;
1314 if (user_agent.indexOf(
"Windows") != -1)
1315 return "Windows_NT";
1316 else if (user_agent.indexOf(
"Mac OS X") != -1)
1318 else if (user_agent.indexOf(
"Linux") != -1)
1320 else if (user_agent.indexOf(
"SunOS") != -1)
function SBFormattedString(aKey, aParams, aDefault, aStringBundle)
const URI_GENERIC_ICON_XPINSTALL
sbOSDControlService prototype QueryInterface
const TYPE_X_SB_TRANSFER_MEDIA_ITEMS
const SB_MEDIALISTDUPLICATEFILTER_CONTRACTID
const TYPE_X_SB_TRANSFER_MEDIA_LIST
SimpleArrayEnumerator prototype hasMoreElements
_getSelectedPageStyle s i
_updateTextAndScrollDataForFrame aData