sbPlaylistCommandsBuilder.js
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2011 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://gre/modules/XPCOMUtils.jsm");
26 Components.utils.import("resource://app/jsmodules/ArrayConverter.jsm");
27 Components.utils.import("resource://app/jsmodules/DebugUtils.jsm");
28 
29 const Ci = Components.interfaces;
30 
31 const SONGBIRD_PLAYLISTCOMMANDSBUILDER_CONTRACTID = "@songbirdnest.com/Songbird/PlaylistCommandsBuilder;1";
32 const SONGBIRD_PLAYLISTCOMMANDSBUILDER_CLASSNAME = "Songbird Playlist Commands Builder";
33 const SONGBIRD_PLAYLISTCOMMANDSBUILDER_CID = Components.ID("{18c4b63c-d5b4-4aa2-918f-a31304d254ec}");
34 const SONGBIRD_PLAYLISTCOMMANDSBUILDER_IID = Ci.sbIPlaylistCommandsBuilder;
35 
45 
49 
50 // ----------------------------------------------------------------------------
51 
53  this.m_Context.commands = this;
54  this.m_root_commands = new Array();
55  this.m_menus = new Array();
56  var menuitem = { id : null,
58  m_Menu : this.m_root_commands};
59  this.m_menus.push(menuitem);
60  this.m_listeners = new Array();
61  this.id = null;
62  this.parentCommandObject = null;
63  this.targetFlags = 0;
64 }
65 
66 // ----------------------------------------------------------------------------
67 
69 
70 // ----------------------------------------------------------------------------
71 
76 
77  m_Context : {
78  medialist : null,
79  playlist : null,
80  window : null,
81  commands : null,
82  implementorContext: null,
83  QueryInterface : XPCOMUtils.generateQI([Ci.sbIPlaylistCommandsContext,
84  Ci.sbIPlaylistCommandsBuilderContext]),
85  },
86 
87  m_menus : null,
89  m_InitCallback : null,
90  m_ShutdownCallback : null,
91  m_VisibleCallback : null,
92  m_listeners : null,
93 
100 // ----------------------------------------------------------------------------
101 // Submenus
102 // ----------------------------------------------------------------------------
103 
104  init: function PlaylistCommandsBuilder_init(aId)
105  {
106  this.m_menus[0].id = aId;
107  this.id = aId;
108  },
109 
110  appendSubmenu: function
111  PlaylistCommandsBuilder_appendSubmenu(aParentSubMenuId,
112  aSubMenuId,
113  aLabel,
114  aTooltipText)
115  {
116  var props = { m_Name : aLabel,
117  m_Tooltip : aTooltipText };
118 
119  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND,
120  null,
121  aParentSubMenuId,
123  aSubMenuId,
124  props);
125  },
126 
127  insertSubmenuBefore: function
128  PlaylistCommandsBuilder_insertSubmenuBefore(aParentSubMenuId,
129  aBeforeId,
130  aSubMenuId,
131  aLabel,
132  aTooltipText)
133  {
134  var props = { m_Name : aLabel,
135  m_Tooltip : aTooltipText };
136 
137  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE,
138  aBeforeId,
139  aParentSubMenuId,
141  aSubMenuId,
142  props);
143  },
144 
145  insertSubmenuAfter: function
146  PlaylistCommandsBuilder_insertSubmenuAfter(aParentSubMenuId,
147  aAfterId,
148  aSubMenuId,
149  aLabel,
150  aTooltipText)
151  {
152  var props = { m_Name : aLabel,
153  m_Tooltip : aTooltipText };
154 
155  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER,
156  aAfterId,
157  aParentSubMenuId,
159  aSubMenuId,
160  props);
161  },
162 
163 // ----------------------------------------------------------------------------
164 // Actions
165 // ----------------------------------------------------------------------------
166 
167  appendAction: function
168  PlaylistCommandsBuilder_appendAction(aParentSubMenuId,
169  aId,
170  aLabel,
171  aTooltipText,
172  aTriggerCallback)
173  {
174  var props = { m_Name : aLabel,
175  m_Tooltip : aTooltipText,
176  m_TriggerCallback : aTriggerCallback }
177 
178  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND,
179  null,
180  aParentSubMenuId,
182  aId,
183  props);
184  },
185 
186  insertActionBefore:
187  function PlaylistCommandsBuilder_insertActionBefore(aParentSubMenuId,
188  aBeforeId,
189  aId,
190  aLabel,
191  aTooltipText,
192  aTriggerCallback)
193  {
194  var props = { m_Name : aLabel,
195  m_Tooltip : aTooltipText,
196  m_TriggerCallback : aTriggerCallback }
197 
198  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE,
199  aBeforeId,
200  aParentSubMenuId,
202  aId,
203  props);
204  },
205 
206  insertActionAfter: function
207  PlaylistCommandsBuilder_insertActionAfter(aParentSubMenuId,
208  aAfterId,
209  aId,
210  aLabel,
211  aTooltipText,
212  aTriggerCallback)
213  {
214  var props = { m_Name : aLabel,
215  m_Tooltip : aTooltipText,
216  m_TriggerCallback : aTriggerCallback }
217 
218  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER,
219  aAfterId,
220  aParentSubMenuId,
222  aId,
223  props);
224  },
225 
226 // ----------------------------------------------------------------------------
227 // Separators
228 // ----------------------------------------------------------------------------
229 
230  appendSeparator: function
231  PlaylistCommandsBuilder_appendSeparator(aParentSubMenuId, aId)
232  {
233  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND,
234  null,
235  aParentSubMenuId,
237  aId);
238  },
239 
240  insertSeparatorBefore: function
241  PlaylistCommandsBuilder_insertSeparatorBefore(aParentSubMenuId,
242  aBeforeId,
243  aId)
244  {
245  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE,
246  aBeforeId,
247  aParentSubMenuId,
249  aId);
250  },
251 
252  insertSeparatorAfter: function
253  PlaylistCommandsBuilder_insertSeparatorAfter(aParentSubMenuId,
254  aAfterId,
255  aId)
256  {
257  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER,
258  aAfterId,
259  aParentSubMenuId,
261  aId);
262  },
263 
264 // ----------------------------------------------------------------------------
265 // Flag
266 // ----------------------------------------------------------------------------
267 
268  appendFlag: function
269  PlaylistCommandsBuilder_appendFlag(aParentSubMenuId,
270  aId,
271  aLabel,
272  aTooltipText,
273  aTriggerCallback,
274  aValueCallback)
275  {
276  var props = { m_Name : aLabel,
277  m_Tooltip : aTooltipText,
278  m_TriggerCallback : aTriggerCallback,
279  m_ValueCallback : aValueCallback };
280 
281  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND,
282  null,
283  aParentSubMenuId,
285  aId,
286  props);
287 
288  },
289 
290  insertFlagBefore: function
291  PlaylistCommandsBuilder_insertFlagBefore(aParentSubMenuId,
292  aBeforeId,
293  aId,
294  aLabel,
295  aTooltipText,
296  aTriggerCallback,
297  aValueCallback)
298  {
299  var props = { m_Name : aLabel,
300  m_Tooltip : aTooltipText,
301  m_TriggerCallback : aTriggerCallback,
302  m_ValueCallback : aValueCallback };
303 
304  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE,
305  aBeforeId,
306  aParentSubMenuId,
308  aId,
309  props);
310  },
311 
312  insertFlagAfter: function
313  PlaylistCommandsBuilder_insertFlagAfter(aParentSubMenuId,
314  aAfterId,
315  aId,
316  aLabel,
317  aTooltipText,
318  aTriggerCallback,
319  aValueCallback)
320  {
321  var props = { m_Name : aLabel,
322  m_Tooltip : aTooltipText,
323  m_TriggerCallback : aTriggerCallback,
324  m_ValueCallback : aValueCallback };
325 
326  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER,
327  aAfterId,
328  aParentSubMenuId,
330  aId,
331  props);
332  },
333 
334 // ----------------------------------------------------------------------------
335 // Value
336 // ----------------------------------------------------------------------------
337 
338  appendValue: function
339  PlaylistCommandsBuilder_appendValue(aParentSubMenuId,
340  aId,
341  aLabel,
342  aTooltipText,
343  aTriggerCallback,
344  aValueCallback)
345  {
346  var props = { m_Name : aLabel,
347  m_Tooltip : aTooltipText,
348  m_TriggerCallback : aTriggerCallback,
349  m_ValueCallback : aValueCallback };
350 
351  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND,
352  null,
353  aParentSubMenuId,
355  aId,
356  props);
357  },
358 
359  insertValueBefore: function
360  PlaylistCommandsBuilder_insertValueBefore(aParentSubMenuId,
361  aBeforeId,
362  aId,
363  aLabel,
364  aTooltipText,
365  aTriggerCallback,
366  aValueCallback)
367  {
368  var props = { m_Name : aLabel,
369  m_Tooltip : aTooltipText,
370  m_TriggerCallback : aTriggerCallback,
371  m_ValueCallback : aValueCallback };
372 
373  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE,
374  aBeforeId,
375  aParentSubMenuId,
377  aId,
378  props);
379  },
380 
381  insertValueAfter: function
382  PlaylistCommandsBuilder_insertValueAfter(aParentSubMenuId,
383  aAfterId,
384  aId,
385  aLabel,
386  aTooltipText,
387  aTriggerCallback,
388  aValueCallback)
389  {
390  var props = { m_Name : aLabel,
391  m_Tooltip : aTooltipText,
392  m_TriggerCallback : aTriggerCallback,
393  m_ValueCallback : aValueCallback };
394 
395  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER,
396  aAfterId,
397  aParentSubMenuId,
399  aId,
400  props);
401  },
402 
403 // ----------------------------------------------------------------------------
404 // Choice menus
405 // ----------------------------------------------------------------------------
406 
407  appendChoiceMenu: function
408  PlaylistCommandsBuilder_appendChoiceMenu(aParentSubMenuId,
409  aId,
410  aLabel,
411  aTooltipText,
412  aItemCallback)
413  {
414  var props = { m_Name : aLabel,
415  m_Tooltip : aTooltipText,
416  m_ItemCallback : aItemCallback };
417 
418  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND,
419  null,
420  aParentSubMenuId,
422  aId,
423  props);
424  },
425 
426  insertChoiceMenuBefore: function
427  PlaylistCommandsBuilder_insertChoiceMenuBefore(aParentSubMenuId,
428  aBeforeId,
429  aId,
430  aLabel,
431  aTooltipText,
432  aItemCallback)
433  {
434  var props = { m_Name : aLabel,
435  m_Tooltip : aTooltipText,
436  m_ItemCallback : aItemCallback };
437 
438  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE,
439  aBeforeId,
440  aParentSubMenuId,
442  aId,
443  props);
444  },
445 
446  insertChoiceMenuAfter: function
447  PlaylistCommandsBuilder_insertChoiceMenuAfter(aParentSubMenuId,
448  aAfterId,
449  aId,
450  aLabel,
451  aTooltipText,
452  aItemCallback)
453  {
454  var props = { m_Name : aLabel,
455  m_Tooltip : aTooltipText,
456  m_ItemCallback : aItemCallback };
457 
458  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER,
459  aAfterId,
460  aParentSubMenuId,
462  aId,
463  props);
464  },
465 
466 // ----------------------------------------------------------------------------
467 // Choice Menu Items
468 // ----------------------------------------------------------------------------
469 
470  appendChoiceMenuItem: function
471  PlaylistCommandsBuilder_appendChoiceMenuItem(aParentSubMenuId,
472  aId,
473  aLabel,
474  aTooltipText,
475  aTriggerCallback)
476  {
477  var props = { m_Name : aLabel,
478  m_Tooltip : aTooltipText,
479  m_TriggerCallback : aTriggerCallback };
480 
481  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND,
482  null,
483  aParentSubMenuId,
485  aId,
486  props);
487  },
488 
489  insertChoiceMenuItemBefore: function
490  PlaylistCommandsBuilder_insertChoiceMenuItemBefore(aParentSubMenuId,
491  aBeforeId,
492  aId,
493  aLabel,
494  aTooltipText,
495  aTriggerCallback)
496  {
497  var props = { m_Name : aLabel,
498  m_Tooltip : aTooltipText,
499  m_TriggerCallback : aTriggerCallback };
500 
501  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE,
502  aBeforeId,
503  aParentSubMenuId,
505  aId,
506  props);
507  },
508 
509  insertChoiceMenuItemAfter: function
510  PlaylistCommandsBuilder_insertChoiceMenuItemAfter(aParentSubMenuId,
511  aAfterId,
512  aId,
513  aLabel,
514  aTooltipText,
515  aTriggerCallback)
516  {
517  var props = { m_Name : aLabel,
518  m_Tooltip : aTooltipText,
519  m_TriggerCallback : aTriggerCallback };
520 
521  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER,
522  aAfterId,
523  aParentSubMenuId,
525  aId,
526  props);
527  },
528 
529 // ----------------------------------------------------------------------------
530 // Custom Items
531 // ----------------------------------------------------------------------------
532 
533  appendCustomItem: function
534  PlaylistCommandsBuilder_appendCustomItem(aParentSubMenuId,
535  aId,
536  aInstantiationCallback,
537  aRefreshCallback)
538  {
539  var props = { m_InstantiationCallback : aInstantiationCallback,
540  m_RefreshCallback : aRefreshCallback};
541 
542  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND,
543  null,
544  aParentSubMenuId,
546  aId,
547  props);
548  },
549 
550  insertCustomItemBefore: function
551  PlaylistCommandsBuilder_insertCustomItemBefore(aParentSubMenuId,
552  aBeforeId,
553  aId,
554  aInstantiationCallback,
555  aRefreshCallback)
556  {
557  var props = { m_InstantiationCallback : aInstantiationCallback,
558  m_RefreshCallback : aRefreshCallback};
559 
560  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE,
561  aBeforeId,
562  aParentSubMenuId,
564  aId,
565  props);
566  },
567 
568  insertCustomItemAfter: function
569  PlaylistCommandsBuilder_insertCustomItemAfter(aParentSubMenuId,
570  aAfterId,
571  aId,
572  aInstantiationCallback,
573  aRefreshCallback)
574  {
575  var props = { m_InstantiationCallback : aInstantiationCallback,
576  m_RefreshCallback : aRefreshCallback};
577 
578  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER,
579  aAfterId,
580  aParentSubMenuId,
582  aId,
583  props);
584  },
585 
586 // ----------------------------------------------------------------------------
587 // sbIPlaylistCommands Items
588 // ----------------------------------------------------------------------------
589 
590  appendPlaylistCommands: function
591  PlaylistCommandsBuilder_appendPlaylistCommands(aParentSubMenuId,
592  aId,
593  aPlaylistCommands)
594  {
595  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND,
596  null,
597  aParentSubMenuId,
599  aId,
600  null,
601  aPlaylistCommands);
602  },
603 
604  insertPlaylistCommandsBefore: function
605  PlaylistCommandsBuilder_insertPlaylistCommandsBefore(aParentSubMenuId,
606  aBeforeId,
607  aId,
608  aPlaylistCommands)
609  {
610  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE,
611  aBeforeId,
612  aParentSubMenuId,
614  aId,
615  null,
616  aPlaylistCommands);
617  },
618 
619  insertPlaylistCommandsAfter: function
620  PlaylistCommandsBuilder_insertPlaylistCommandsAfter(aParentSubMenuId,
621  aAfterId,
622  aId,
623  aPlaylistCommands)
624  {
625  this._insertCommand(SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER,
626  aAfterId,
627  aParentSubMenuId,
629  aId,
630  null,
631  aPlaylistCommands);
632  },
633 
634 // ----------------------------------------------------------------------------
635 
636  setCommandShortcut: function
637  PlaylistCommandsBuilder_setCommandShortcut(aParentSubMenuId,
638  aCommandId,
639  aShortcutKey,
640  aShortcutKeyCode,
641  aShortcutModifiers,
642  aShortcutIsLocal)
643  {
644  var props = { m_ShortcutKey : aShortcutKey,
645  m_ShortcutKeycode : aShortcutKeyCode,
646  m_ShortcutModifiers : aShortcutModifiers,
647  m_ShortcutIsLocal : aShortcutIsLocal };
648 
649  this._setCommandProperties(aParentSubMenuId, aCommandId, props);
650  },
651 
652  setCommandEnabledCallback: function
653  PlaylistCommandsBuilder_setCommandEnabledCallback(aParentSubMenuId,
654  aCommandId,
655  aEnabledCallback)
656  {
657  var props = { m_EnabledCallback : aEnabledCallback };
658 
659  this._setCommandProperties(aParentSubMenuId, aCommandId, props);
660  },
661 
662  setCommandVisibleCallback: function
663  PlaylistCommandsBuilder_setCommandVisibleCallback(aParentSubMenuId,
664  aCommandId,
665  aVisibleCallback)
666  {
667  var props = { m_VisibleCallback : aVisibleCallback };
668 
669  this._setCommandProperties(aParentSubMenuId, aCommandId, props);
670  },
671 
672  setInitCallback: function
673  PlaylistCommandsBuilder_setInitCallback(aInitCallback)
674  {
675  this.m_InitCallback = aInitCallback;
676  },
677 
678  setShutdownCallback: function
679  PlaylistCommandsBuilder_setShutdownCallback(aShutdownCallback)
680  {
681  this.m_ShutdownCallback = aShutdownCallback;
682  },
683 
684  setVisibleCallback: function
685  PlaylistCommandsBuilder_setVisibleCallback(aVisibleCallback)
686  {
687  this.m_VisibleCallback = aVisibleCallback;
688  },
689 
690 // ----------------------------------------------------------------------------
691 
692  removeCommand: function
693  PlaylistCommandsBuilder_removeCommand(aParentSubMenuId,
694  aCommandId)
695  {
696  var menu = this._getMenu(aParentSubMenuId);
697  var index = this._getCommandIndex(menu, aCommandId);
698  if (index != -1)
699  {
700  this._removeCommandTree(menu, index);
701  }
702  else {
703  this.LOG("A command object with an id of " + aCommandId +
704  " could not be found for removal");
705  }
706  },
707 
708  removeAllCommands: function
709  PlaylistCommandsBuilder_removeAllCommands(aParentSubMenuId)
710  {
711  var menu = this._getMenu(aParentSubMenuId);
712  while (menu.length) {
713  this._removeCommandTree(menu, 0);
714  }
715  if (!aParentSubMenuId) {
716  // after removing all commands, the only remaining menu is the root menu
717  if (this.m_menus.length != 1) {
718  throw new Error("Menu list is not empty after removeAllCommands (item 1 = " +
719  this.m_menus[1].id + ")");
720  }
721  }
722  },
723 
724  shutdown: function PlaylistCommandsBuilder_shutdown()
725  {
726  // empty arrays, remove any remaining sbIPlaylistCommands reference
727  // this also removes all references to item callback functions
728  this.removeAllCommands();
729  // reset references for all callback functions for the entire command set
730  this.m_InitCallback = null;
731  this.m_ShutdownCallback = null;
732  this.m_VisibleCallback = null;
733  // and forget context
734  if (this.m_Context)
735  {
736  this.m_Context.playlist = null;
737  this.m_Context.medialist = null;
738  this.m_Context.window = null;
739  this.m_Context.commands = this;
740  this.m_Context = null;
741  this.m_CommandSubObject = null;
742  this.parentCommandObject = null;
743  }
744  },
745 
746 // ----------------------------------------------------------------------------
747 
748  _insertCommand: function
749  PlaylistCommandsBuilder__insertCommand(aInsertHow,
750  aRefPointId,
751  aParentSubMenuId,
752  aType,
753  aId,
754  aPropArray,
755  aCommandSubObject)
756  {
757  if (!aId) return;
758  switch (aType) {
768  break;
769  default:
770  // unknown type !
771  throw new Error("Unknown type in insertCommand");
772  }
773  var menu = this._getMenu(aParentSubMenuId);
774  var index = this._getCommandIndex(menu, aId);
775  if (index >= 0) {
776  throw new Error("Duplicate command '" +
777  aId +
778  "' in menu '" +
779  (aParentSubMenuId ? aParentSubMenuId : "<rootmenu>"));
780  }
781  var refindex = ((aInsertHow != SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND) &&
782  aRefPointId) ?
783  this._getCommandIndex(menu, aRefPointId) : -1;
784  var vrefindex = refindex;
785  switch (aInsertHow) {
787  break;
789  vrefindex++;
790  // fallthru
792  if (refindex < 0) {
793  throw new Error("Reference command '" +
794  aRefPointId +
795  "' not found in menu '" +
796  (aParentSubMenuId ? aParentSubMenuId : "<rootmenu>"));
797  }
798  break;
799  }
800  this._insertCommandInArray(menu,
801  vrefindex,
802  aType,
803  aId,
804  aPropArray,
805  aCommandSubObject);
806  },
807 
808  _insertCommandInArray: function
809  PlaylistCommandsBuilder__insertCommandInArray(aMenu,
810  aInsertionIndex,
811  aType,
812  aId,
813  aPropArray,
814  aCommandSubObject)
815  {
816  var item = { m_ParentMenu : aMenu,
817  m_Type : aType,
818  id : aId };
819  if (aPropArray) {
820  for (var i in aPropArray) {
821  item[i] = aPropArray[i];
822  }
823  }
824 
825  switch (aType) {
827  item.m_Flex = 1;
828  item.m_Name = "*separator*";
829  break;
831  if (!aCommandSubObject) return 0;
832  aCommandSubObject = aCommandSubObject.QueryInterface(Components.
833  interfaces.
835  aCommandSubObject.parentCommandObject = this;
836  item.m_CommandSubObject = aCommandSubObject;
837  break;
840  var menuitem = { id : aId,
841  m_Type : aType,
842  m_Menu : new Array() };
844  menuitem.m_ItemCallback = aPropArray.m_ItemCallback;
845  }
846  this.m_menus.push(menuitem);
847  break;
848  }
849 
850  // insert the item in the menu at the requested position
851  if (aInsertionIndex < 0 || aInsertionIndex >= aMenu.length)
852  aMenu.push(item);
853  else
854  aMenu.splice(aInsertionIndex, 0, item);
855  },
856 
857  _removeCommandTree: function
858  PlaylistCommandsBuilder__removeCommandTree(aMenu, aIndex) {
859  if (aIndex >= aMenu.length || aIndex < 0) {
860  throw new Error("Invalid index " + aIndex + " in _removeCommandTree");
861  }
862 
863  var item = aMenu[aIndex];
864 
865  if (item.m_Type == SONGBIRD_PLAYLISTCOMMANDS_TYPE_MENU ||
866  item.m_Type == SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICE) {
867  var submenu = this._getMenu(item.id);
868  if (submenu && submenu != this.m_root_commands) {
869  while(submenu.length > 0) {
870  this._removeCommandTree(submenu, 0);
871  }
872  var idx = this._getMenuIndex(item.id);
873  if (idx > 0 && idx < this.m_menus.length) { // yes, '>', we do not want the root menu
874  // discard the item callback in case this is a choicemenu
875  this.m_menus[idx].m_ItemCallback = null;
876  // command array is empty by now, discard it now
877  this.m_menus[idx].m_Menu = null;
878  // remove the menu entry
879  this.m_menus.splice(idx, 1);
880  }
881  }
882  }
883 
884  // Remove the command item
885  aMenu[aIndex].m_InstantiationCallback = null;
886  aMenu[aIndex].m_RefreshCallback = null;
887  aMenu[aIndex].m_ValueCallback = null;
888  aMenu[aIndex].m_EnabledCallback = null;
889  aMenu[aIndex].m_VisibleCallback = null;
890  aMenu[aIndex].m_TriggerCallback = null;
891  aMenu.splice(aIndex, 1);
892  },
893 
894  _getMenu: function PlaylistCommandsBuilder__getMenu(aSubMenuId)
895  {
896  // null is the root menu
897  if (!aSubMenuId) return this.m_root_commands;
898  for (var i=0;i<this.m_menus.length;i++) {
899  if (this.m_menus[i].id == aSubMenuId) {
900  return this.m_menus[i].m_Menu;
901  }
902  }
903  throw new Error("Submenu " + aSubMenuId + " not found");
904  },
905 
906  _getMenuIndex: function PlaylistCommandsBuilder__getMenuIndex(aSubMenuId)
907  {
908  if (!aSubMenuId) return 0;
909  for (var i=0;i<this.m_menus.length;i++) {
910  if (this.m_menus[i].id == aSubMenuId) {
911  return i;
912  }
913  }
914  throw new Error("Submenu " + aSubMenuId + " not found");
915  return -1;
916  },
917 
918  _getCommandIndex: function
919  PlaylistCommandsBuilder__getCommandIndex(aSubMenu, aCommandId)
920  {
921  if (!aSubMenu) return -1;
922  for (var i=0;i<aSubMenu.length;i++) {
923  if (aSubMenu[i].id == aCommandId) {
924  return i;
925  }
926  }
927  return -1;
928  },
929 
930  _getCommandProperty: function
931  PlaylistCommandsBuilder__getCommandProperty(aSubMenuId,
932  aIndex,
933  aHost,
934  aProperty,
935  aDefault)
936  {
937  try {
938  var menu = this._getMenu(aSubMenuId);
939  if (!menu) return aDefault;
940  if (aIndex >= menu.length) return aDefault;
941  var prop = menu[aIndex][aProperty];
942  if (prop === undefined) return aDefault;
943  if (typeof(prop) == "object" && prop.handleCallback) {
944  return prop.handleCallback(this.m_Context,
945  aSubMenuId,
946  menu[aIndex].id,
947  aHost,
948  aProperty.substr(2));
949  }
950  return prop;
951  } catch (e) {
952  this.LOG("_getCommandProperty(" + aSubMenuId + ", " + aIndex + " (" +
953  menu[aIndex].id + "), " + aHost + ", " + aProperty + ", " +
954  aDefault + ") - " + e);
955  }
956  return aDefault;
957  },
958 
959  _getMenuProperty: function
960  PlaylistCommandsBuilder__getMenuProperty(aMenu, aHost, aProperty, aDefault)
961  {
962  try {
963  var prop = aMenu[aProperty];
964  if (prop === undefined) return aDefault;
965  if (typeof(prop) == "object" && prop.handleCallback) {
966  return prop.handleCallback(this.m_Context,
967  aMenu.m_ParentMenu,
968  aMenu.id,
969  aHost,
970  aProperty.substr(2));
971  }
972  return prop;
973  } catch (e) {
974  this.LOG("_getMenuProperty(" + aMenu.id + ", " + aHost +
975  ", " + aProperty + ", " + aDefault + ") - " + e);
976  }
977  return aDefault;
978  },
979 
980  _setCommandProperties: function
981  PlaylistCommandsBuilder__setCommandProperties(aSubMenuId, aCommandId, aPropArray)
982  {
983  var menu = this._getMenu(aSubMenuId);
984  var index = this._getCommandIndex(menu, aCommandId);
985  if (index >= menu.length || index < 0) {
986  throw new Error("Invalid command index " + index + " in _setCommandProperties");
987  }
988  for (var i in aPropArray) {
989  menu[index][i] = aPropArray[i];
990  }
991  },
992 
993  // not used for now, this may eventually be needed if we want to allow
994  // changing the item callback for a choicemenu
995  _setMenuProperties: function
996  PlaylistCommandsBuilder__setMenuProperties(aMenu, aPropArray)
997  {
998  for (var i in aPropArray) {
999  aMenu[i] = aPropArray[i];
1000  }
1001  },
1002 
1008  addCommandObject: function PlaylistCommandsBuilder_addCommandObject
1009  ( aCommandObject )
1010  {
1011  this.appendPlaylistCommands(null,
1012  aCommandObject.id,
1013  aCommandObject);
1014 
1015  this.notifyListeners("onCommandAdded", aCommandObject);
1016  },
1017 
1018  removeCommandObject: function PlaylistCommandsBuilder_removeCommandObject
1019  ( aCommandObject )
1020  {
1021  this.removeCommand(null, aCommandObject.id);
1022 
1023  this.notifyListeners("onCommandRemoved", aCommandObject);
1024  },
1025 
1026  addListener: function PlaylistCommandsBuilder_addListener ( aListener )
1027  {
1028  this.m_listeners.push(aListener);
1029  },
1030 
1031  removeListener: function PlaylistCommandsBuilder_removeListener ( aListener )
1032  {
1033  let index = this.m_listeners.indexOf(aListener);
1034  if (index >= 0) {
1035  // remove it
1036  this.m_listeners.splice(index, 1);
1037  }
1038  },
1039 
1040  notifyListeners: function PlaylistCommandsBuilder_notifyListeners
1041  ( aTriggerFunction, aCommandObject )
1042  {
1043  for (var i = 0 ; i < this.m_listeners.length; i++) {
1044  var listener = this.m_listeners[i]
1045  if (listener instanceof Ci.sbIPlaylistCommandsListener)
1046  {
1047  try
1048  {
1049  listener[aTriggerFunction](aCommandObject);
1050  }
1051  catch (err) {
1052  Components.utils.reportError("Could not signal " + aTriggerFunction +
1053  " to PlaylistCommandsListener. Failed with error: " + err.description);
1054  }
1055  }
1056  }
1057 
1058  if (this.parentCommandObject)
1059  {
1060  // bubble the signal to the parent command object
1061  this.parentCommandObject.notifyListeners(aTriggerFunction, aCommandObject);
1062  }
1063  },
1064 
1065  getVisible: function PlaylistCommandsBuilder_getVisible( aHost )
1066  {
1067  if (this.m_VisibleCallback &&
1068  typeof(this.m_VisibleCallback) == "object" &&
1069  this.m_VisibleCallback.handleCallback) {
1070  return this.m_VisibleCallback.handleCallback(this.m_Context, aHost, "Visible");
1071  }
1072  return true;
1073  },
1074 
1075  getNumCommands: function
1076  PlaylistCommandsBuilder_getNumCommands( aSubMenuId, aHost )
1077  {
1078  var menu = this._getMenu(aSubMenuId);
1079  return menu.length;
1080  },
1081 
1082  getCommandId: function
1083  PlaylistCommandsBuilder_getCommandId( aSubMenuId, aIndex, aHost )
1084  {
1085  return this._getCommandProperty(aSubMenuId,
1086  aIndex,
1087  aHost,
1088  "id",
1089  "");
1090  },
1091 
1092  getCommandType: function
1093  PlaylistCommandsBuilder_getCommandType( aSubMenuId, aIndex, aHost )
1094  {
1095  return this._getCommandProperty(aSubMenuId,
1096  aIndex,
1097  aHost,
1098  "m_Type",
1099  "");
1100  },
1101 
1102  getCommandText: function
1103  PlaylistCommandsBuilder_getCommandText( aSubMenuId, aIndex, aHost )
1104  {
1105  return this._getCommandProperty(aSubMenuId,
1106  aIndex,
1107  aHost,
1108  "m_Name",
1109  "");
1110  },
1111 
1112  getCommandFlex: function
1113  PlaylistCommandsBuilder_getCommandFlex( aSubMenuId, aIndex, aHost )
1114  {
1115  return this._getCommandProperty(aSubMenuId,
1116  aIndex,
1117  aHost,
1118  "m_Flex",
1119  false);
1120  },
1121 
1122  getCommandToolTipText: function
1123  PlaylistCommandsBuilder_getCommandToolTipText( aSubMenuId, aIndex, aHost )
1124  {
1125  return this._getCommandProperty(aSubMenuId,
1126  aIndex,
1127  aHost,
1128  "m_Tooltip",
1129  "");
1130  },
1131 
1132  getCommandValue: function
1133  PlaylistCommandsBuilder_getCommandValue( aSubMenuId, aIndex, aHost )
1134  {
1135  return this._getCommandProperty(aSubMenuId,
1136  aIndex,
1137  aHost,
1138  "m_ValueCallback",
1139  "");
1140  },
1141 
1142  instantiateCustomCommand: function
1143  PlaylistCommandsBuilder_instantiateCustomCommand( aSubMenuId,
1144  aIndex,
1145  aHost,
1146  aId,
1147  aDocument )
1148  {
1149  var menu = this._getMenu(aSubMenuId);
1150  if (aIndex >= menu.length || aIndex < 0) {
1151  throw new Error("Invalid index " + index + " in instantiateCustomCommand");
1152  }
1153  var cb = menu[aIndex].m_InstantiationCallback;
1154  if (cb) return cb.handleCallback(this.m_Context,
1155  menu[aIndex].m_ParentMenu,
1156  menu[aIndex].id,
1157  aHost,
1158  aDocument);
1159  throw new Error("No custom command instantiation callback defined for command " + aId);
1160  },
1161 
1162  refreshCustomCommand: function
1163  PlaylistCommandsBuilder_refreshCustomCommand( aSubMenuId,
1164  aIndex,
1165  aHost,
1166  aId,
1167  aElement )
1168  {
1169  var menu = this._getMenu(aSubMenuId);
1170  if (aIndex >= menu.length || aIndex < 0) {
1171  throw new Error("Invalid index " + index + " in refreshCustomCommand");
1172  }
1173  var cb = menu[aIndex].m_RefreshCallback;
1174  if (cb) cb.handleCallback(this.m_Context,
1175  menu[aIndex].m_ParentMenu,
1176  menu[aIndex].id,
1177  aHost,
1178  aElement);
1179  },
1180 
1181  getCommandVisible: function
1182  PlaylistCommandsBuilder_getCommandVisible( aSubMenuId, aIndex, aHost )
1183  {
1184  return this._getCommandProperty(aSubMenuId,
1185  aIndex,
1186  aHost,
1187  "m_VisibleCallback",
1188  true);
1189  },
1190 
1191  getCommandFlag: function
1192  PlaylistCommandsBuilder_getCommandFlag( aSubMenuId, aIndex, aHost )
1193  {
1194  return this._getCommandProperty(aSubMenuId,
1195  aIndex,
1196  aHost,
1197  "m_ValueCallback",
1198  false);
1199  },
1200 
1201  getCommandChoiceItem: function
1202  PlaylistCommandsBuilder_getCommandChoiceItem( aChoiceMenu, aHost )
1203  {
1204  var menuindex = this._getMenuIndex(aChoiceMenu);
1205  if (menuindex < 0 || menuindex >= this.m_menus.length) {
1206  throw new Error("Choice menu id not found : " + aChoiceMenu + " in getCommandChoiceItem");
1207  }
1208  var menu = this.m_menus[menuindex];
1209  if (menu.m_Type != SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICE) return "";
1210  return this._getMenuProperty(menu, aHost, "m_ItemCallback", "");
1211  },
1212 
1213  getCommandEnabled: function
1214  PlaylistCommandsBuilder_getCommandEnabled( aSubMenuId, aIndex, aHost )
1215  {
1216  return this._getCommandProperty(aSubMenuId,
1217  aIndex,
1218  aHost,
1219  "m_EnabledCallback",
1220  true);
1221  },
1222 
1223  getCommandShortcutModifiers: function
1224  PlaylistCommandsBuilder_getCommandShortcutModifiers( aSubMenuId, aIndex, aHost )
1225  {
1226  return this._getCommandProperty(aSubMenuId,
1227  aIndex,
1228  aHost,
1229  "m_ShortcutModifiers",
1230  "");
1231  },
1232 
1233  getCommandShortcutKey: function
1234  PlaylistCommandsBuilder_getCommandShortcutKey( aSubMenuId, aIndex, aHost )
1235  {
1236  return this._getCommandProperty(aSubMenuId,
1237  aIndex,
1238  aHost,
1239  "m_ShortcutKey",
1240  "");
1241  },
1242 
1243  getCommandShortcutKeycode: function
1244  PlaylistCommandsBuilder_getCommandShortcutKeycode( aSubMenuId, aIndex, aHost )
1245  {
1246  return this._getCommandProperty(aSubMenuId,
1247  aIndex,
1248  aHost,
1249  "m_ShortcutKeycode",
1250  "");
1251  },
1252 
1253  getCommandShortcutLocal: function
1254  PlaylistCommandsBuilder_getCommandShortcutLocal( aSubMenuId, aIndex, aHost )
1255  {
1256  return this._getCommandProperty(aSubMenuId,
1257  aIndex,
1258  aHost,
1259  "m_ShortcutIsLocal",
1260  false);
1261  },
1262 
1263  getCommandSubObject: function
1264  PlaylistCommandsBuilder_getCommandSubObject( aSubMenuId, aIndex, aHost )
1265  {
1266  return this._getCommandProperty(aSubMenuId,
1267  aIndex,
1268  aHost,
1269  "m_CommandSubObject",
1270  null);
1271  },
1272 
1273  getChildrenCommandObjects: function
1274  PlaylistCommandsBuilder_getChildrenCommandObjects()
1275  {
1276  var subCommandArray = new Array();
1277  for (var i=0; i < this.getNumCommands(null, null); i++) {
1278  var subCommand = this.getCommandSubObject("", i, "");
1279  subCommandArray.push(subCommand);
1280  }
1281  return ArrayConverter.enumerator(subCommandArray);
1282  },
1283 
1284  onCommand: function
1285  PlaylistCommandsBuilder_onCommand(aSubMenuId, aIndex, aHost, id, value)
1286  {
1287  var menu = this._getMenu(aSubMenuId);
1288  if (aIndex >= menu.length || aIndex < 0) {
1289  throw new Error("Invalid index " + index + " in PlaylistCommandsBuilder::onCommand");
1290  }
1291 
1292  if (menu[aIndex].id != id) {
1293  throw new Error("Id do not match in PlaylistCommandsBuilder::onCommand (" +
1294  id +
1295  "/" +
1296  menu[aIndex].id +
1297  ")");
1298  }
1299  var cb = menu[aIndex].m_TriggerCallback;
1300  if (cb === undefined || !cb.handleCallback) {
1301  throw new Error("No callback defined for command " + id);
1302  }
1303  cb.handleCallback(this.m_Context,
1304  aSubMenuId,
1305  menu[aIndex].id,
1306  aHost,
1307  value);
1308  },
1309 
1310  duplicate: function PlaylistCommandsBuilder_duplicate()
1311  {
1312  // duplicate this
1313  var obj = this.dupObject(this);
1314 
1315  // after duplication, the arrays are shared between the two objects,
1316  // so copy the command structure over to the new object, with new arrays
1317  obj.m_menus = new Array();
1318  for (var i=0;i<this.m_menus.length;i++) {
1319  var menuitem = this.dupObject(this.m_menus[i]);
1320  menuitem.m_Menu = new Array();
1321  for (var j=0;j<this.m_menus[i].m_Menu.length;j++) {
1322  var item = this.dupObject(this.m_menus[i].m_Menu[j]);
1323  // if the item is an sbIPlaylistCommands sub-object, duplicate it as well
1324  if (item.m_CommandSubObject) {
1325  item.m_CommandSubObject = item.m_CommandSubObject.duplicate();
1326  }
1327  menuitem.m_Menu.push(item);
1328  }
1329  obj.m_menus.push(menuitem);
1330  }
1331  obj.m_root_commands = obj.m_menus[0].m_Menu;
1332  obj.m_Context = this.dupObject(this.m_Context);
1333 
1334  // return the copy
1335  return obj;
1336  },
1337 
1338  dupObject: function PlaylistCommandsBuilder_dupObject(obj) {
1339  var r = {};
1340  for ( var i in obj )
1341  {
1342  r[ i ] = obj[ i ];
1343  }
1344  return r;
1345  },
1346 
1347  initCommands: function PlaylistCommandsBuilder_initCommands(aHost) {
1348  for (var i=0;i<this.m_menus.length;i++) {
1349  for (var j=0;j<this.m_menus[i].m_Menu.length;j++) {
1350  if (this.m_menus[i].m_Menu[j].m_CommandSubObject) {
1351  this.m_menus[i].m_Menu[j].m_CommandSubObject.initCommands(aHost);
1352  }
1353  }
1354  }
1355  if (this.m_InitCallback &&
1356  typeof(this.m_InitCallback) == "object" &&
1357  this.m_InitCallback.handleCallback) {
1358  this.m_InitCallback.handleCallback(this.m_Context, aHost, null);
1359  }
1360  },
1361 
1362  shutdownCommands: function PlaylistCommandsBuilder_shutdownCommands() {
1363  for (var i=0;i<this.m_menus.length;i++) {
1364  for (var j=0;j<this.m_menus[i].m_Menu.length;j++) {
1365  if (this.m_menus[i].m_Menu[j].m_CommandSubObject) {
1366  try {
1367  this.m_menus[i].m_Menu[j].m_CommandSubObject.shutdownCommands();
1368  }
1369  catch (e)
1370  {
1371  Components.utils.reportError(e);
1372  }
1373  }
1374  }
1375  }
1376  if (this.m_ShutdownCallback &&
1377  typeof(this.m_ShutdownCallback) == "object" &&
1378  this.m_ShutdownCallback.handleCallback) {
1379  this.m_ShutdownCallback.handleCallback(this.m_Context, null, null);
1380  }
1381  this.shutdown();
1382  },
1383 
1384  setContext: function PlaylistCommandsBuilder_setContext( context )
1385  {
1386  for (var i=0;i<this.m_menus.length;i++) {
1387  for (var j=0;j<this.m_menus[i].m_Menu.length;j++) {
1388  if (this.m_menus[i].m_Menu[j].m_CommandSubObject) {
1389  this.m_menus[i].m_Menu[j].m_CommandSubObject.setContext(context);
1390  }
1391  }
1392  }
1393 
1394  this.m_Context.playlist = context.playlist;
1395  this.m_Context.medialist = context.medialist;
1396  this.m_Context.window = context.window;
1397  this.m_Context.commands = this;
1398  },
1399 
1400 
1401 // ----------------------------------------------------------------------------
1402 
1403  LOG: DebugUtils.generateLogFunction("sbPlaylistCommandsBuilder"),
1404 
1405 // ----------------------------------------------------------------------------
1406 
1410  QueryInterface: XPCOMUtils.generateQI([Ci.sbIPlaylistCommands,
1411  Ci.sbIPlaylistCommandsBuilder]),
1412 }; // PlaylistCommandsBuilder.prototype
1413 
1414 
1415 function NSGetModule(compMgr, fileSpec) {
1416  return XPCOMUtils.generateModule([PlaylistCommandsBuilder]);
1417 }
1418 
const SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICE
const SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE
#define LOG(args)
const SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICEITEM
sbDeviceFirmwareAutoCheckForUpdate prototype contractID
_updateCookies aHost
var menu
sbOSDControlService prototype QueryInterface
sbDeviceFirmwareAutoCheckForUpdate prototype classDescription
const SONGBIRD_PLAYLISTCOMMANDS_TYPE_CUSTOM
function PlaylistCommandsBuilder()
sbDownloadDeviceServicePaneModule prototype shutdown
const SONGBIRD_PLAYLISTCOMMANDSBUILDER_CLASSNAME
let window
const SONGBIRD_PLAYLISTCOMMANDS_TYPE_VALUE
_window init
Definition: FeedWriter.js:1144
_collectFormDataForFrame aDocument
const SONGBIRD_PLAYLISTCOMMANDS_TYPE_ACTION
return null
Definition: FeedWriter.js:1143
An interface that represents the set of command buttons and context menu items available on a display...
countRef value
Definition: FeedWriter.js:1423
const SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER
const SONGBIRD_PLAYLISTCOMMANDS_TYPE_SEPARATOR
SBPlaylistCommand_DownloadToPlaylist m_root_commands
sbDeviceFirmwareAutoCheckForUpdate prototype classID
const SONGBIRD_PLAYLISTCOMMANDS_TYPE_SUBOBJECT
sbDeviceFirmwareAutoCheckForUpdate prototype interfaces
const SONGBIRD_PLAYLISTCOMMANDS_TYPE_FLAG
const SONGBIRD_PLAYLISTCOMMANDSBUILDER_IID
window addListener("unload", function(){window.removeListener("unload", arguments.callee);document.purge();if(Browser.Engine.trident){CollectGarbage();}})
function NSGetModule(compMgr, fileSpec)
_getSelectedPageStyle s i
const SONGBIRD_PLAYLISTCOMMANDSBUILDER_CONTRACTID
const SONGBIRD_PLAYLISTCOMMANDSBUILDER_CID
const SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND
const SONGBIRD_PLAYLISTCOMMANDS_TYPE_MENU