home *** CD-ROM | disk | FTP | other *** search
/ Freelog 112 / FreelogNo112-NovembreDecembre2012.iso / Multimedia / Songbird / Songbird_2.0.0-2311_windows-i686-msvc8.exe / components / sbPlaylistCommandsBuilder.js < prev    next >
Text File  |  2012-06-08  |  53KB  |  1,419 lines

  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.  
  36. const SONGBIRD_PLAYLISTCOMMANDS_TYPE_ACTION     = "action";
  37. const SONGBIRD_PLAYLISTCOMMANDS_TYPE_SEPARATOR  = "separator";
  38. const SONGBIRD_PLAYLISTCOMMANDS_TYPE_MENU       = "submenu";
  39. const SONGBIRD_PLAYLISTCOMMANDS_TYPE_FLAG       = "flag";
  40. const SONGBIRD_PLAYLISTCOMMANDS_TYPE_VALUE      = "value";
  41. const SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICE     = "choice";
  42. const SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICEITEM = "choiceitem";
  43. const SONGBIRD_PLAYLISTCOMMANDS_TYPE_CUSTOM     = "custom";
  44. const SONGBIRD_PLAYLISTCOMMANDS_TYPE_SUBOBJECT  = "subobject";
  45.  
  46. const SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND = 0;
  47. const SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE = 1;
  48. const SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER  = 2;
  49.  
  50. // ----------------------------------------------------------------------------
  51.  
  52. function PlaylistCommandsBuilder() {
  53.   this.m_Context.commands = this;
  54.   this.m_root_commands = new Array();
  55.   this.m_menus = new Array();
  56.   var menuitem = {  id        : null,
  57.                     m_Type    : SONGBIRD_PLAYLISTCOMMANDS_TYPE_MENU,
  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.  
  68. PlaylistCommandsBuilder.prototype.constructor = PlaylistCommandsBuilder;
  69.  
  70. // ----------------------------------------------------------------------------
  71.  
  72. PlaylistCommandsBuilder.prototype = {
  73.   classDescription: SONGBIRD_PLAYLISTCOMMANDSBUILDER_CLASSNAME,
  74.   classID:          SONGBIRD_PLAYLISTCOMMANDSBUILDER_CID,
  75.   contractID:       SONGBIRD_PLAYLISTCOMMANDSBUILDER_CONTRACTID,
  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,
  88.   m_root_commands     : null,
  89.   m_InitCallback      : null,
  90.   m_ShutdownCallback  : null,
  91.   m_VisibleCallback   : null,
  92.   m_listeners         : null,
  93.  
  94. /**
  95.  * ----------------------------------------------------------------------------
  96.  * sbIPlaylistCommandsBuilder Implementation
  97.  * ----------------------------------------------------------------------------
  98.  */
  99.  
  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,
  122.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_MENU,
  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,
  140.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_MENU,
  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,
  158.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_MENU,
  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,
  181.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_ACTION,
  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,
  201.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_ACTION,
  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,
  221.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_ACTION,
  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,
  236.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_SEPARATOR,
  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,
  248.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_SEPARATOR,
  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,
  260.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_SEPARATOR,
  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,
  284.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_FLAG,
  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,
  307.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_FLAG,
  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,
  329.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_FLAG,
  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,
  354.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_VALUE,
  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,
  376.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_VALUE,
  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,
  398.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_VALUE,
  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,
  421.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICE,
  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,
  441.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICE,
  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,
  461.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICE,
  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,
  484.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICEITEM,
  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,
  504.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICEITEM,
  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,
  524.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICEITEM,
  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,
  545.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_CUSTOM,
  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,
  563.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_CUSTOM,
  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,
  581.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_CUSTOM,
  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,
  598.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_SUBOBJECT,
  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,
  613.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_SUBOBJECT,
  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,
  628.                         SONGBIRD_PLAYLISTCOMMANDS_TYPE_SUBOBJECT,
  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) {
  759.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_ACTION:
  760.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_SEPARATOR:
  761.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_MENU:
  762.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_FLAG:
  763.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_VALUE:
  764.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICE:
  765.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICEITEM:
  766.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_CUSTOM:
  767.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_SUBOBJECT:
  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) {
  786.       case SONGBIRD_PLAYLISTCOMMANDSBUILDER_APPEND:
  787.         break;
  788.       case SONGBIRD_PLAYLISTCOMMANDSBUILDER_AFTER:
  789.         vrefindex++;
  790.         // fallthru
  791.       case SONGBIRD_PLAYLISTCOMMANDSBUILDER_BEFORE:
  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) {
  826.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_SEPARATOR:
  827.         item.m_Flex = 1;
  828.         item.m_Name = "*separator*";
  829.         break;
  830.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_SUBOBJECT:
  831.         if (!aCommandSubObject) return 0;
  832.         aCommandSubObject = aCommandSubObject.QueryInterface(Components.
  833.                                                              interfaces.
  834.                                                              sbIPlaylistCommands);
  835.         aCommandSubObject.parentCommandObject = this;
  836.         item.m_CommandSubObject = aCommandSubObject;
  837.         break;
  838.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_MENU:
  839.       case SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICE:
  840.         var menuitem = { id     : aId,
  841.                          m_Type : aType,
  842.                          m_Menu : new Array() };
  843.         if (aType == SONGBIRD_PLAYLISTCOMMANDS_TYPE_CHOICE) {
  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.  
  1003. /**
  1004.  * ----------------------------------------------------------------------------
  1005.  * sbIPlaylistCommands Implementation
  1006.  * ----------------------------------------------------------------------------
  1007.  */
  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.  
  1407.   /**
  1408.    * See nsISupports.idl
  1409.    */
  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.  
  1419.