home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 2008 February
/
PCWorld_2008-02_cd.bin
/
temacd
/
songbird
/
Songbird_0.4_windows-i686.exe
/
components
/
sbDataRemote.js
< prev
next >
Wrap
Text File
|
2007-12-21
|
17KB
|
524 lines
/**
//
// BEGIN SONGBIRD GPL
//
// This file is part of the Songbird web player.
//
// Copyright(c) 2005-2008 POTI, Inc.
// http://songbirdnest.com
//
// This file may be licensed under the terms of of the
// GNU General Public License Version 2 (the "GPL").
//
// Software distributed under the License is distributed
// on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
// express or implied. See the GPL for the specific language
// governing rights and limitations.
//
// You should have received a copy of the GPL along with this
// program. If not, go to http://www.gnu.org/licenses/gpl.html
// or write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// END SONGBIRD GPL
//
*/
/**
* \file sbDataRemote.js
* \brief Implementation of the interface sbIDataRemote
* This implementation of sbIDataRemote uses the mozilla pref system as a
* backend for storing key-value pairs.
* \sa sbIDataRemote.idl sbIDataRemote.js
*/
var Cr = Components.results;
var Ci = Components.interfaces;
var Cc = Components.classes;
const SONGBIRD_DATAREMOTE_CONTRACTID = "@songbirdnest.com/Songbird/DataRemote;1";
const SONGBIRD_DATAREMOTE_CLASSNAME = "Songbird Data Remote Service";
const SONGBIRD_DATAREMOTE_CID = Components.ID("{950952aa-cb6b-4806-b39a-307b1b1eadb6}");
const SONGBIRD_DATAREMOTE_IID = Ci.sbIDataRemote;
function DataRemote() {
// Nothing here...
}
// Define the prototype block before adding to the prototype object or the
// additions will get blown away (at least the setters/getters were).
DataRemote.prototype = {
_initialized: false, // has init been called
_observing: false, // are we hooked up to the pref branch as a listener
_prefBranch: null, // the pref branch associated with the root
_root: null, // the root used to retrieve the pref branch
_key: null, // the section of the branch we care about ("Domain")
_boundObserver: null, // the object observing the change
_boundElement: null, // the element containing the linked prop/attr.
_boundProperty: null, // the property linked to the data (of boundElement)
_boundAttribute: null, // the attribute linked to the data (of boundElement)
_isBool: false, // Is the data a yes/no true/false chunk of data?
_isNot: false, // Is the linked data state opposite of target data?
_evalString: "", // a string of js to evaluate when the data changes
init: function(aKey, aRoot) {
// Only allow initialization once per object
if (this._initialized)
throw Cr.NS_ERROR_UNEXPECTED;
// Set the strings
if (!aRoot) {
// The prefapi hashes fully qualified prefs, so using a simple root does not
// hurt us. Callbacks are in a (BIG) linked-list (ew), which sucks. Having
// a shorter root saves some strncmp() time.
this._root = "songbird.";
this._key = aKey;
} else {
// If a root is specified use that.
this._root = aRoot;
this._key = aKey;
}
// get the prefbranch for our root from the pref service
var prefsService = Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService);
this._prefBranch = prefsService.getBranch(this._root)
.QueryInterface(Ci.nsIPrefBranch2);
if (!this._prefBranch)
throw Cr.NS_ERROR_FAILURE;
this._initialized = true;
},
// only needs to be called if we have bound an attribute, property or observer
unbind: function() {
if (!this._initialized)
throw Cr.NS_ERROR_NOT_INITIALIZED;
if (this._prefBranch && this._observing)
this._prefBranch.removeObserver( this._key, this );
// clear the decks
this._observing = false;
this._boundObserver = null;
this._boundAttribute = null;
this._boundProperty = null;
this._boundElement = null;
},
bindObserver: function(aObserver, aSuppressFirst) {
if (!this._initialized)
throw Cr.NS_ERROR_NOT_INITIALIZED;
// Clear and reinsert ourselves as an observer.
if ( this._observing )
this._prefBranch.removeObserver(this._key, this);
// Temporary change in how we attach as observers
//this._prefBranch.addObserver(this._key, this, true);
this._prefBranch.addObserver(this._key, this, false);
this._observing = true;
// Now we are linked to an nsIObserver object
this._boundObserver = aObserver;
this._boundElement = null;
this._boundProperty = null;
this._boundAttribute = null;
this._isBool = false;
this._isNot = false;
this._evalString = "";
// If the caller wants to be notified, fire on attachment
if (!aSuppressFirst)
this.observe(null, null, this._key);
},
bindProperty: function(aElement, aProperty, aIsBool, aIsNot, aEvalString) {
if (!this._initialized)
throw Cr.NS_ERROR_NOT_INITIALIZED;
if (!aIsBool)
aIsBool = false;
if (!aIsNot)
aIsNot = false;
if (!aEvalString)
aEvalString = "";
// Clear and reinsert ourselves as an observer.
if ( this._observing )
this._prefBranch.removeObserver(this._key, this);
// Temporary change in how we attach as observers
//this._prefBranch.addObserver(this._key, this, true);
this._prefBranch.addObserver(this._key, this, false);
this._observing = true;
// Now we are linked to property on an element
this._boundObserver = null;
this._boundElement = aElement;
this._boundProperty = aProperty;
this._boundAttribute = null;
this._isBool = aIsBool;
this._isNot = aIsNot;
this._evalString = aEvalString;
// Set the value once
this.observe(null, null, this._key);
},
bindAttribute: function(aElement, aAttribute, aIsBool, aIsNot, aEvalString) {
if (!this._initialized)
throw Cr.NS_ERROR_NOT_INITIALIZED;
if (!aIsBool)
aIsBool = false;
if (!aIsNot)
aIsNot = false;
if (!aEvalString)
aEvalString = "";
// Clear and reinsert ourselves as an observer.
if ( this._observing )
this._prefBranch.removeObserver(this._key, this);
// Temporary change in how we attach as observers
//this._prefBranch.addObserver(this._key, this, true);
this._prefBranch.addObserver(this._key, this, false);
this._observing = true;
// Now we are linked to an attribute on an element
this._boundObserver = null;
this._boundElement = aElement;
this._boundProperty = null;
this._boundAttribute = aAttribute;
this._isBool = aIsBool;
this._isNot = aIsNot;
this._evalString = aEvalString;
// Set the value once
this.observe(null, null, this._key);
},
get stringValue() {
if (!this._initialized)
throw Cr.NS_ERROR_NOT_INITIALIZED;
return this._getValue();
},
set stringValue(aStringValue) {
if (!this._initialized)
throw Cr.NS_ERROR_NOT_INITIALIZED;
// Make sure there is a string object to pass.
if (aStringValue == null)
aStringValue = "";
this._setValue(aStringValue);
},
get boolValue() {
if (!this._initialized)
throw Cr.NS_ERROR_NOT_INITIALIZED;
return (this._makeIntValue(this._getValue()) != 0);
},
set boolValue(aBoolValue) {
if (!this._initialized)
throw Cr.NS_ERROR_NOT_INITIALIZED;
// convert the bool to a numeric string for easy getBoolValue calls.
aBoolValue = aBoolValue ? "1" : "0";
this._setValue(aBoolValue);
},
get intValue() {
if (!this._initialized)
throw Cr.NS_ERROR_NOT_INITIALIZED;
return this._makeIntValue(this._getValue());
},
set intValue(aIntValue) {
if (!this._initialized)
throw Cr.NS_ERROR_NOT_INITIALIZED;
this._setValue(aIntValue + "");
},
// internal helper function - all setters ultimately call this
_setValue: function(aValueStr) {
// assume we are being called after the init check in another method.
// Make a unicode string, assign the value, set it into the preferences.
var sString = Cc["@mozilla.org/supports-string;1"]
.createInstance(Ci.nsISupportsString);
sString.data = aValueStr;
this._prefBranch.setComplexValue(this._key,
Ci.nsISupportsString,
sString);
},
// internal helper function - all getters ultimately call this
_getValue: function() {
// assume we are being called after the init check in another method.
var retval = "";
try {
var prefValue = this._prefBranch.getComplexValue(this._key, Ci.nsISupportsString);
if (prefValue != "") {
retval = prefValue.data;
}
} catch (err) {
// when the pref does not exist in the branch the pref system returns an
// error code which changes to an exception. We do not want to throw
// here but return an empty string.
}
return retval;
},
// internal function for converting to an integer.
_makeIntValue: function(aValueStr) {
var retval = 0;
if (aValueStr && aValueStr.length)
retval = parseInt(aValueStr);
return retval;
},
// observe - Called when someone updates the remote data
// aSubject: The prefbranch object
// aTopic: NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
// aData: the domain (key)
observe: function(aSubject, aTopic, aData) {
if (!this._initialized)
throw Cr.NS_ERROR_NOT_INITIALIZED;
// Early bail conditions
if (aData != this._key)
return;
// Get the value as a string - this must be called value to not break
// evalStrings that do an eval of the value.
var value = this._getValue();
// Run the optional evaluation
if (this._evalString.length)
value = eval(this._evalString);
// Handle boolean and not states
if (this._isBool) {
// If we were not a bool, make us one (_evalString could change value)
if (typeof(value) != "boolean") {
if (value == "true")
value = true;
else if (value == "false")
value = false;
else
value = (this._makeIntValue(value) != 0);
}
// reverse ourself if neccessary
if (this._isNot)
value = !value;
}
// Handle callback states
if (this._boundObserver) {
try {
// pass useful information to the observer.
this._boundObserver.observe( this, this._key, value );
}
catch (err) {
dump("ERROR! Could not call boundObserver.observe(). Key = " + this._key + "\n" + err + "\n");
}
}
else if (this._boundElement && this._boundProperty) {
// Set the property of the callback object
this._boundElement[this._boundProperty] = value;
}
else if (this._boundElement && this._boundAttribute) {
// Set the attribute of the callback object
var valStr = value;
// If bool-type, convert to string.
if (this._isBool) {
if (value)
valStr = "true";
else
valStr = "false";
}
try {
this._boundElement.setAttribute(this._boundAttribute, valStr);
}
catch (err) {
dump("ERROR! Could not setAttribute in sbDataRemote.js\n " + err + "\n");
}
}
},
// nsIClassInfo
getInterfaces: function( count ) {
var ifaces = [ SONGBIRD_DATAREMOTE_IID,
Ci.nsIClassInfo,
Ci.nsIObserver,
Ci.nsISecurityCheckedComponent,
Ci.sbISecurityAggregator,
Ci.nsISupportsWeakReference ];
count.value = ifaces.length;
return ifaces;
},
get classDescription() {
return SONGBIRD_DATAREMOTE_CLASSNAME;
},
get contractID() {
return SONGBIRD_DATAREMOTE_CONTRACTID;
},
get classID() {
return SONGBIRD_DATAREMOTE_CID;
},
getHelperForLanguage: function( language ) { return null; },
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
// needs to be DOM_OBJECT to allow remoteAPI to access it.
flags: Ci.nsIClassInfo.DOM_OBJECT,
// nsISecurityCheckedComponent -- implemented by the security mixin
_securityMixin: null,
_initializedSCC: false,
_publicWProps: [ "internal:stringValue",
"internal:boolValue",
"internal:intValue" ],
_publicRProps: [ "internal:stringValue",
"internal:boolValue",
"internal:intValue",
"classinfo:classDescription",
"classinfo:contractID",
"classinfo:classID",
"classinfo:implementationLanguage",
"classinfo:flags" ],
_publicMethods: [ "internal:bindAttribute",
"internal:bindObserver",
"internal:bindProperty",
"internal:unbind",
"internal:init" ],
_publicInterfaces: [ Ci.nsISupports,
Ci.nsIClassInfo,
Ci.nsIObserver,
Ci.nsISecurityCheckedComponent,
SONGBIRD_DATAREMOTE_IID ],
_initSCC: function() {
this._securityMixin = Cc["@songbirdnest.com/remoteapi/security-mixin;1"]
.createInstance(Ci.nsISecurityCheckedComponent);
// initialize the security mixin with the cleared methods and props
this._securityMixin
.init(this, this._publicInterfaces, this._publicInterfaces.length,
this._publicMethods, this._publicMethods.length,
this._publicRProps, this._publicRProps.length,
this._publicWProps, this._publicWProps.length,
false);
this._initializedSCC = true;
},
canCreateWrapper: function(iid) {
if (! this._initializedSCC)
this._initSCC();
return this._securityMixin.canCreateWrapper(iid);
},
canCallMethod: function(iid, methodName) {
if (! this._initializedSCC)
this._initSCC();
return this._securityMixin.canCallMethod(iid, methodName);
},
canGetProperty: function(iid, propertyName) {
if (! this._initializedSCC)
this._initSCC();
return this._securityMixin.canGetProperty(iid, propertyName);
},
canSetProperty: function(iid, propertyName) {
if (! this._initializedSCC)
this._initSCC();
return this._securityMixin.canSetProperty(iid, propertyName);
},
// nsISupports
QueryInterface: function(iid) {
if (!iid.equals(SONGBIRD_DATAREMOTE_IID) &&
!iid.equals(Ci.nsIClassInfo) &&
!iid.equals(Ci.nsIObserver) &&
!iid.equals(Ci.nsISecurityCheckedComponent) &&
!iid.equals(Ci.nsISecurityAggregator) &&
!iid.equals(Ci.nsISupportsWeakReference) &&
!iid.equals(Ci.nsISupports)) {
throw Cr.NS_ERROR_NO_INTERFACE;
}
return this;
}
}; // DataRemote.prototype
// be specific
DataRemote.prototype.constructor = DataRemote;
/**
* ----------------------------------------------------------------------------
* Registration for XPCOM
* ----------------------------------------------------------------------------
*/
const gDataRemoteModule = {
registerSelf: function(compMgr, fileSpec, location, type) {
compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar);
compMgr.registerFactoryLocation(SONGBIRD_DATAREMOTE_CID,
SONGBIRD_DATAREMOTE_CLASSNAME,
SONGBIRD_DATAREMOTE_CONTRACTID,
fileSpec,
location,
type);
},
unregisterSelf : function (compMgr, location, type) {
compMgr.QueryInterface(Ci.nsIComponentRegistrar);
compMgr.unregisterFactoryLocation(SONGBIRD_DATAREMOTE_CID, location);
},
getClassObject : function (compMgr, cid, iid) {
if (!cid.equals(SONGBIRD_DATAREMOTE_CID))
throw Cr.NS_ERROR_NO_INTERFACE;
if (!iid.equals(Ci.nsIFactory))
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
return this.mFactory;
},
mFactory : {
createInstance : function (outer, iid) {
if (outer != null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return (new DataRemote()).QueryInterface(iid);
}
},
canUnload: function(compMgr) {
return true;
},
QueryInterface : function (iid) {
if ( !iid.equals(Ci.nsIModule) ||
!iid.equals(Ci.nsISupports) )
throw Cr.NS_ERROR_NO_INTERFACE;
return this;
}
}; // gDataRemoteModule
function NSGetModule(compMgr, fileSpec) {
return gDataRemoteModule;
} // NSGetModule