home *** CD-ROM | disk | FTP | other *** search
/ Freelog 100 / FreelogNo100-NovembreDecembre2010.iso / Multimedia / Songbird / Songbird_1.8.0-1800_windows-i686-msvc8.exe / components / sbFaceplateManager.js < prev    next >
Text File  |  2010-08-30  |  14KB  |  509 lines

  1. /** vim: ts=2 sw=2 expandtab
  2. //
  3. // BEGIN SONGBIRD GPL
  4. //
  5. // This file is part of the Songbird web player.
  6. //
  7. // Copyright(c) 2005-2008 POTI, Inc.
  8. // http://songbirdnest.com
  9. //
  10. // This file may be licensed under the terms of of the
  11. // GNU General Public License Version 2 (the "GPL").
  12. //
  13. // Software distributed under the License is distributed
  14. // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
  15. // express or implied. See the GPL for the specific language
  16. // governing rights and limitations.
  17. //
  18. // You should have received a copy of the GPL along with this
  19. // program. If not, go to http://www.gnu.org/licenses/gpl.html
  20. // or write to the Free Software Foundation, Inc.,
  21. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. //
  23. // END SONGBIRD GPL
  24. //
  25.  */
  26.  
  27. /**
  28.  * \file sbFaceplateManager.js
  29.  * \brief Manages the lifecycle of faceplate pane bindings
  30.  */
  31.  
  32.  
  33. const Cc = Components.classes;
  34. const Ci = Components.interfaces;
  35. const Cr = Components.results;
  36. const Ce = Components.Exception;
  37.  
  38. const URL_BINDING_DEFAULT_PANE = "chrome://songbird/content/bindings/facePlate.xml#default-pane";
  39. const URL_BINDING_DASHBOARD_PANE = "chrome://songbird/content/bindings/facePlate.xml#playback-pane"; 
  40.  
  41. const DATAREMOTE_PLAYBACK = "faceplate.playing";
  42.  
  43.  
  44.  
  45. /**
  46.  * \class ArrayEnumerator
  47.  * \brief Wraps a js array in an nsISimpleEnumerator
  48.  */
  49. function ArrayEnumerator(array) 
  50. {
  51.   this.data = array;
  52. }
  53. ArrayEnumerator.prototype = {
  54.     
  55.   index: 0,
  56.     
  57.   getNext: function() {
  58.     return this.data[this.index++];
  59.   },
  60.  
  61.   /**
  62.    *  Gah. nsISimpleEnumerator uses hasMoreElements, but 
  63.    *  nsIStringEnumerator uses hasMore.  
  64.    */
  65.   hasMoreElements: function() {
  66.     if (this.index < this.data.length)
  67.       return true;
  68.     else
  69.       return false;
  70.   },
  71.   hasMore: function () {
  72.     return this.hasMoreElements();
  73.   },
  74.   
  75.   QueryInterface: function(iid)
  76.   {
  77.     if (!iid.equals(Ci.nsISimpleEnumerator) &&
  78.         !iid.equals(Ci.nsIStringEnumerator) &&        
  79.         !iid.equals(Ci.nsISupports))
  80.       throw Components.results.NS_ERROR_NO_INTERFACE;
  81.     return this;
  82.   }
  83. }
  84.  
  85.  
  86.  
  87.  
  88.  
  89.  
  90. /**
  91.  * \class FaceplatePane
  92.  * \brief An implementation of nsIFaceplatePane.  Acts as a single
  93.  *        representation the many instances of a faceplate pane.
  94.  * \sa sbIFaceplatePane 
  95.  */
  96. function FaceplatePane(aID, aName, aBindingURL) 
  97. {
  98.   this._id = aID;
  99.   this._name = aName;
  100.   this._bindingURL = aBindingURL;
  101.   this._data = {};
  102.   this._observers = [];
  103. }
  104. FaceplatePane.prototype = {
  105.  
  106.   _id: null,
  107.   _name: null,
  108.   _bindingURL: null,
  109.  
  110.   _data: null,
  111.   
  112.   _observers: null,
  113.   
  114.   get id() { return this._id; },
  115.   get name() { return this._name; },
  116.   get bindingURL() { return this._bindingURL; }, 
  117.   
  118.   /**
  119.    * \sa sbIFaceplatePane
  120.    */
  121.   
  122.   setData: function FaceplatePane_setData(aKey, aValue) {
  123.     if (!aKey) {
  124.       throw Components.results.NS_ERROR_INVALID_ARG;      
  125.     }
  126.     
  127.     this._data[aKey] = aValue;
  128.     this._notify(aKey);
  129.   },
  130.  
  131.   getData: function FaceplatePane_getData(aKey) {
  132.     return this._data[aKey];
  133.   },
  134.  
  135.   getKeys: function FaceplatePane_getKeys() {
  136.     // Copy all the data keys into an array, and then return an enumerator
  137.     return new ArrayEnumerator( [key for (key in this._data)] );     
  138.   },
  139.   
  140.   addObserver: function FaceplatePane_addObserver(aObserver) {
  141.     if (! (aObserver instanceof Ci.nsIObserver)) {
  142.       throw Components.results.NS_ERROR_INVALID_ARG;
  143.     }
  144.     if (this._observers.indexOf(aObserver) == -1) {
  145.       this._observers.push(aObserver);
  146.     }
  147.   },
  148.   
  149.   removeObserver: function FaceplatePane_removeObserver(aObserver) {
  150.     var index = this._observers.indexOf(aObserver);
  151.     if (index > -1) {
  152.       this._observers.splice(index,1);
  153.     }     
  154.   },
  155.   
  156.   _notify: function FaceplatePane_notify(topic) {
  157.     var thisPane = this.QueryInterface(Ci.sbIFaceplatePane);
  158.     this._observers.forEach( function (observer) {
  159.       observer.observe(thisPane, topic, null);
  160.     });    
  161.   },
  162.   
  163.   QueryInterface: function(iid)
  164.   {
  165.     if (!iid.equals(Components.interfaces.sbIFaceplatePane) &&
  166.         !iid.equals(Components.interfaces.nsISupports))
  167.       throw Components.results.NS_ERROR_NO_INTERFACE;
  168.     return this;
  169.   }
  170. }
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177. /**
  178.  * \class FaceplateManager
  179.  * \brief Manages the lifecycle of faceplate panes
  180.  * \sa sbIFaceplateManager
  181.  */
  182. function FaceplateManager() {
  183.  
  184.   var os      = Components.classes["@mozilla.org/observer-service;1"]
  185.                       .getService(Components.interfaces.nsIObserverService);
  186.   
  187.   // We want to wait till profile-after-change to initialize
  188.   os.addObserver(this, 'songbird-library-manager-ready', false);
  189.  
  190.   // We need to unhook things on shutdown
  191.   os.addObserver(this, "songbird-library-manager-before-shutdown", false);
  192.   
  193.   this._listeners = [];
  194.   this._panes = {};
  195.  
  196. };
  197. FaceplateManager.prototype = {
  198.   constructor: FaceplateManager,
  199.  
  200.   _listeners: null,
  201.   _paneCount: 0,
  202.   
  203.   // Map of pane IDs to sbIFaceplatePanes
  204.   _panes: null,
  205.   
  206.   // Most recently shown pane ID
  207.   _defaultPaneID: null,
  208.   
  209.   /**
  210.    * Initialize the faceplate manager. Called after profile load.
  211.    * Sets up the intro pane and playback dashboard pane.
  212.    */
  213.   _init: function init() {
  214.  
  215.     // Come up with some localized names for the default panes.
  216.     var strings = Cc["@mozilla.org/intl/stringbundle;1"]
  217.                   .getService(Ci.nsIStringBundleService)
  218.                   .createBundle("chrome://songbird/locale/songbird.properties"); 
  219.     var getString = function(aStringId, aDefault) {
  220.       try {
  221.         return strings.GetStringFromName(aStringId);
  222.       } catch (e) {
  223.         return aDefault;
  224.       }
  225.     }
  226.     var introName = getString("faceplate.pane.intro.name", "Intro");
  227.     var dashboardName = getString("faceplate.pane.dashboard.name", "Dashboard");
  228.     
  229.     // Create the panes
  230.     this.createPane("songbird-intro", introName, URL_BINDING_DEFAULT_PANE);
  231.     this.createPane("songbird-dashboard", dashboardName, URL_BINDING_DASHBOARD_PANE);
  232.     
  233.     // Set up a dataremote to show the dashboard on first playback.
  234.     var createDataRemote =  new Components.Constructor(
  235.                                    "@songbirdnest.com/Songbird/DataRemote;1",
  236.                                    Components.interfaces.sbIDataRemote, "init");
  237.     
  238.     this._playbackDataRemote = createDataRemote(DATAREMOTE_PLAYBACK, null);
  239.     this._playbackDataRemote.bindObserver(this, true);
  240.   },
  241.   
  242.   /**
  243.    * Called on xpcom-shutdown
  244.    */
  245.   _deinit: function deinit() {
  246.     this._listeners = null;
  247.     this._panes = null;
  248.     if (this._playbackDataRemote) {
  249.       this._playbackDataRemote.unbind();
  250.       this._playbackDataRemote = null;
  251.     }
  252.   },
  253.  
  254.   
  255.   /**
  256.    * \sa sbIFaceplateManager
  257.    */  
  258.   
  259.   get paneCount() {
  260.     return this._paneCount;
  261.   },
  262.     
  263.   createPane:  function FaceplateManager_createPane(aID, aName, aBindingURL) {
  264.     if (!aID || !aName || !aBindingURL) {
  265.       throw Components.results.NS_ERROR_INVALID_ARG;
  266.     }
  267.     if (this._panes[aID]) {
  268.       throw Components.results.NS_ERROR_FAILURE;
  269.     }
  270.     
  271.     var pane = new FaceplatePane(aID, aName, aBindingURL);
  272.     this._panes[aID] = pane;
  273.     this._paneCount++;
  274.     
  275.     // Announce this faceplate to the world.  All listening faceplate
  276.     // widgets should receive this message and then instantiate
  277.     // the requested binding
  278.     this._onCreate(pane);
  279.     
  280.     return pane;
  281.   },
  282.     
  283.   showPane: function FaceplateManager_showPane(aPane) {
  284.     if (!aPane || !aPane.id || !this._panes[aPane.id]) {
  285.       throw Components.results.NS_ERROR_INVALID_ARG;
  286.     }
  287.     this._defaultPaneID = aPane.id;
  288.     this._onShow(this._panes[aPane.id]);
  289.   },
  290.   
  291.   destroyPane: function FaceplateManager_destroyPane(aPane) {
  292.     if (!aPane || !aPane.id || !this._panes[aPane.id]) {
  293.       throw Components.results.NS_ERROR_INVALID_ARG;
  294.     }
  295.     var pane = this._panes[aPane.id];
  296.     delete this._panes[pane.id];
  297.     this._paneCount--;
  298.     this._onDestroy(pane);
  299.   },
  300.   
  301.   getPane: function FaceplateManager_getPane(aID) {
  302.     return this._panes[aID];
  303.   },
  304.   
  305.   getPanes: function FaceplateManager_getPanes() {
  306.     // Copy all the faceplates into an array, and then return an enumerator
  307.     return new ArrayEnumerator( [this._panes[key] for (key in this._panes)] ); 
  308.   },
  309.   
  310.   getDefaultPane: function FaceplateManager_getDefaultPane() {
  311.     var pane = this.getPane(this._defaultPaneID);
  312.     if (!pane) {
  313.       pane = this.getPane("songbird-intro");
  314.     }
  315.     return pane;
  316.   },
  317.   
  318.   addListener: function FaceplateManager_addListener(aListener) {
  319.     if (! (aListener instanceof Ci.sbIFaceplateManagerListener)) {
  320.       throw Components.results.NS_ERROR_INVALID_ARG;
  321.     }
  322.     if (this._listeners.indexOf(aListener) == -1) {
  323.       this._listeners.push(aListener);
  324.     }
  325.   },
  326.  
  327.   removeListener: function FaceplateManager_removeListener(aListener) {
  328.     var index = this._listeners.indexOf(aListener);
  329.     if (index > -1) {
  330.       this._listeners.splice(index,1);
  331.     }    
  332.   },
  333.     
  334.    
  335.   /**
  336.    * Broadcasts a notification to create the given faceplate pane.
  337.    */
  338.   _onCreate: function FaceplateManager__onCreate(aFaceplatePane) {
  339.     aFaceplatePane = aFaceplatePane.QueryInterface(Ci.sbIFaceplatePane);
  340.     this._listeners.forEach( function (listener) {
  341.       listener.onCreatePane(aFaceplatePane);
  342.     });
  343.   },
  344.  
  345.   /**
  346.    * Broadcasts a notification to show the given faceplate pane.
  347.    */
  348.   _onShow: function FaceplateManager__onShow(aFaceplatePane) {
  349.     aFaceplatePane = aFaceplatePane.QueryInterface(Ci.sbIFaceplatePane);    
  350.     this._listeners.forEach( function (listener) {
  351.       listener.onShowPane(aFaceplatePane);
  352.     });
  353.   },
  354.   
  355.   /**
  356.    * Broadcasts a notification to destory the given faceplate.
  357.    */
  358.   _onDestroy: function FaceplateManager__onDestroy(aFaceplatePane) {
  359.     aFaceplatePane = aFaceplatePane.QueryInterface(Ci.sbIFaceplatePane);    
  360.     this._listeners.forEach( function (listener) {
  361.       listener.onDestroyPane(aFaceplatePane);
  362.     });
  363.   },
  364.   
  365.   
  366.   /**
  367.    * Cause the playback dashboard pane to show in all 
  368.    * faceplates.  Called by a dataremote when playback 
  369.    * starts for the first time.
  370.    */  
  371.   _showDashboardPane: function FaceplateManager__showDashboardPane() {
  372.     var pane = this.getPane("songbird-dashboard");
  373.     if (pane) {
  374.       this.showPane(pane);
  375.     } else {
  376.       dump("FaceplateManager__showDashboardPane: dashboard not found\n");
  377.     }
  378.   },
  379.   
  380.   
  381.   /**
  382.    * Called by dataremotes and the observer service.
  383.    */
  384.   observe: function(subject, topic, data) {
  385.     var os      = Components.classes["@mozilla.org/observer-service;1"]
  386.                       .getService(Components.interfaces.nsIObserverService);
  387.  
  388.     switch (topic) {
  389.     case "songbird-library-manager-ready":
  390.       os.removeObserver(this, "songbird-library-manager-ready");
  391.       this._init();
  392.       break;
  393.     case "songbird-library-manager-before-shutdown":
  394.       os.removeObserver(this, "songbird-library-manager-before-shutdown");
  395.       this._deinit();
  396.       break;
  397.     // When playback begins for the first time, jump
  398.     // to the playback dashboard
  399.     case DATAREMOTE_PLAYBACK:
  400.       if (this._playbackDataRemote.boolValue) {
  401.         this._playbackDataRemote.unbind();
  402.         this._playbackDataRemote = null;
  403.         this._showDashboardPane();
  404.       }
  405.     }
  406.   },
  407.  
  408.   /**
  409.    * See nsISupports.idl
  410.    */
  411.   QueryInterface: function(iid) {
  412.     if (!iid.equals(Components.interfaces.sbIFaceplateManager) &&
  413.         !iid.equals(Components.interfaces.nsIObserver) && 
  414.         !iid.equals(Components.interfaces.nsISupports))
  415.       throw Components.results.NS_ERROR_NO_INTERFACE;
  416.     return this;
  417.   }
  418. }; // FaceplateManager.prototype
  419.  
  420.  
  421.  
  422.  
  423.  
  424.  
  425. /**
  426.  * \brief XPCOM initialization code
  427.  */
  428. function makeGetModule(CONSTRUCTOR, CID, CLASSNAME, CONTRACTID, CATEGORIES) {
  429.   return function (comMgr, fileSpec) {
  430.     return {
  431.       registerSelf : function (compMgr, fileSpec, location, type) {
  432.         compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  433.         compMgr.registerFactoryLocation(CID,
  434.                         CLASSNAME,
  435.                         CONTRACTID,
  436.                         fileSpec,
  437.                         location,
  438.                         type);
  439.         if (CATEGORIES && CATEGORIES.length) {
  440.           var catman =  Cc["@mozilla.org/categorymanager;1"]
  441.               .getService(Ci.nsICategoryManager);
  442.           for (var i=0; i<CATEGORIES.length; i++) {
  443.             var e = CATEGORIES[i];
  444.             catman.addCategoryEntry(e.category, e.entry, e.value, 
  445.               true, true);
  446.           }
  447.         }
  448.       },
  449.  
  450.       getClassObject : function (compMgr, cid, iid) {
  451.         if (!cid.equals(CID)) {
  452.           throw Cr.NS_ERROR_NO_INTERFACE;
  453.         }
  454.  
  455.         if (!iid.equals(Ci.nsIFactory)) {
  456.           throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  457.         }
  458.  
  459.         return this._factory;
  460.       },
  461.  
  462.       _factory : {
  463.         createInstance : function (outer, iid) {
  464.           if (outer != null) {
  465.             throw Cr.NS_ERROR_NO_AGGREGATION;
  466.           }
  467.           return (new CONSTRUCTOR()).QueryInterface(iid);
  468.         }
  469.       },
  470.  
  471.       unregisterSelf : function (compMgr, location, type) {
  472.         compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  473.         compMgr.unregisterFactoryLocation(CID, location);
  474.         if (CATEGORIES && CATEGORIES.length) {
  475.           var catman =  Cc["@mozilla.org/categorymanager;1"]
  476.               .getService(Ci.nsICategoryManager);
  477.           for (var i=0; i<CATEGORIES.length; i++) {
  478.             var e = CATEGORIES[i];
  479.             catman.deleteCategoryEntry(e.category, e.entry, true);
  480.           }
  481.         }
  482.       },
  483.  
  484.       canUnload : function (compMgr) {
  485.         return true;
  486.       },
  487.  
  488.       QueryInterface : function (iid) {
  489.         if ( !iid.equals(Ci.nsIModule) ||
  490.              !iid.equals(Ci.nsISupports) )
  491.           throw Cr.NS_ERROR_NO_INTERFACE;
  492.         return this;
  493.       }
  494.  
  495.     };
  496.   }
  497. }
  498.  
  499. var NSGetModule = makeGetModule (
  500.   FaceplateManager,
  501.   Components.ID("{eb5c665a-bfe2-49f0-a747-cd3554e55606}"),
  502.   "Songbird Faceplate Pane Manager Service",
  503.   "@songbirdnest.com/faceplate/manager;1",
  504.   [{
  505.     category: 'app-startup',
  506.     entry: 'faceplate-pane-manager',
  507.     value: 'service,@songbirdnest.com/faceplate/manager;1'
  508.   }]);
  509.