summaryrefslogtreecommitdiffstats
path: root/devtools/shared/gcli/source/lib/gcli/settings.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/gcli/source/lib/gcli/settings.js')
-rw-r--r--devtools/shared/gcli/source/lib/gcli/settings.js284
1 files changed, 284 insertions, 0 deletions
diff --git a/devtools/shared/gcli/source/lib/gcli/settings.js b/devtools/shared/gcli/source/lib/gcli/settings.js
new file mode 100644
index 000000000..29e608cbd
--- /dev/null
+++ b/devtools/shared/gcli/source/lib/gcli/settings.js
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+var imports = {};
+
+var Cc = require('chrome').Cc;
+var Ci = require('chrome').Ci;
+var Cu = require('chrome').Cu;
+
+var XPCOMUtils = Cu.import('resource://gre/modules/XPCOMUtils.jsm', {}).XPCOMUtils;
+var Services = require("Services");
+
+XPCOMUtils.defineLazyGetter(imports, 'prefBranch', function() {
+ var prefService = Cc['@mozilla.org/preferences-service;1']
+ .getService(Ci.nsIPrefService);
+ return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
+});
+
+XPCOMUtils.defineLazyGetter(imports, 'supportsString', function() {
+ return Cc['@mozilla.org/supports-string;1']
+ .createInstance(Ci.nsISupportsString);
+});
+
+var util = require('./util/util');
+
+/**
+ * All local settings have this prefix when used in Firefox
+ */
+var DEVTOOLS_PREFIX = 'devtools.gcli.';
+
+/**
+ * A manager for the registered Settings
+ */
+function Settings(types, settingValues) {
+ this._types = types;
+
+ if (settingValues != null) {
+ throw new Error('settingValues is not supported when writing to prefs');
+ }
+
+ // Collection of preferences for sorted access
+ this._settingsAll = [];
+
+ // Collection of preferences for fast indexed access
+ this._settingsMap = new Map();
+
+ // Flag so we know if we've read the system preferences
+ this._hasReadSystem = false;
+
+ // Event for use to detect when the list of settings changes
+ this.onChange = util.createEvent('Settings.onChange');
+}
+
+/**
+ * Load system prefs if they've not been loaded already
+ * @return true
+ */
+Settings.prototype._readSystem = function() {
+ if (this._hasReadSystem) {
+ return;
+ }
+
+ imports.prefBranch.getChildList('').forEach(function(name) {
+ var setting = new Setting(this, name);
+ this._settingsAll.push(setting);
+ this._settingsMap.set(name, setting);
+ }.bind(this));
+
+ this._settingsAll.sort(function(s1, s2) {
+ return s1.name.localeCompare(s2.name);
+ }.bind(this));
+
+ this._hasReadSystem = true;
+};
+
+/**
+ * Get an array containing all known Settings filtered to match the given
+ * filter (string) at any point in the name of the setting
+ */
+Settings.prototype.getAll = function(filter) {
+ this._readSystem();
+
+ if (filter == null) {
+ return this._settingsAll;
+ }
+
+ return this._settingsAll.filter(function(setting) {
+ return setting.name.indexOf(filter) !== -1;
+ }.bind(this));
+};
+
+/**
+ * Add a new setting
+ */
+Settings.prototype.add = function(prefSpec) {
+ var setting = new Setting(this, prefSpec);
+
+ if (this._settingsMap.has(setting.name)) {
+ // Once exists already, we're going to need to replace it in the array
+ for (var i = 0; i < this._settingsAll.length; i++) {
+ if (this._settingsAll[i].name === setting.name) {
+ this._settingsAll[i] = setting;
+ }
+ }
+ }
+
+ this._settingsMap.set(setting.name, setting);
+ this.onChange({ added: setting.name });
+
+ return setting;
+};
+
+/**
+ * Getter for an existing setting. Generally use of this function should be
+ * avoided. Systems that define a setting should export it if they wish it to
+ * be available to the outside, or not otherwise. Use of this function breaks
+ * that boundary and also hides dependencies. Acceptable uses include testing
+ * and embedded uses of GCLI that pre-define all settings (e.g. Firefox)
+ * @param name The name of the setting to fetch
+ * @return The found Setting object, or undefined if the setting was not found
+ */
+Settings.prototype.get = function(name) {
+ // We might be able to give the answer without needing to read all system
+ // settings if this is an internal setting
+ var found = this._settingsMap.get(name);
+ if (!found) {
+ found = this._settingsMap.get(DEVTOOLS_PREFIX + name);
+ }
+
+ if (found) {
+ return found;
+ }
+
+ if (this._hasReadSystem) {
+ return undefined;
+ }
+ else {
+ this._readSystem();
+ found = this._settingsMap.get(name);
+ if (!found) {
+ found = this._settingsMap.get(DEVTOOLS_PREFIX + name);
+ }
+ return found;
+ }
+};
+
+/**
+ * Remove a setting. A no-op in this case
+ */
+Settings.prototype.remove = function() {
+};
+
+exports.Settings = Settings;
+
+/**
+ * A class to wrap up the properties of a Setting.
+ * @see toolkit/components/viewconfig/content/config.js
+ */
+function Setting(settings, prefSpec) {
+ this._settings = settings;
+ if (typeof prefSpec === 'string') {
+ // We're coming from getAll() i.e. a full listing of prefs
+ this.name = prefSpec;
+ this.description = '';
+ }
+ else {
+ // A specific addition by GCLI
+ this.name = DEVTOOLS_PREFIX + prefSpec.name;
+
+ if (prefSpec.ignoreTypeDifference !== true && prefSpec.type) {
+ if (this.type.name !== prefSpec.type) {
+ throw new Error('Locally declared type (' + prefSpec.type + ') != ' +
+ 'Mozilla declared type (' + this.type.name + ') for ' + this.name);
+ }
+ }
+
+ this.description = prefSpec.description;
+ }
+
+ this.onChange = util.createEvent('Setting.onChange');
+}
+
+/**
+ * Reset this setting to it's initial default value
+ */
+Setting.prototype.setDefault = function() {
+ imports.prefBranch.clearUserPref(this.name);
+ Services.prefs.savePrefFile(null);
+};
+
+/**
+ * What type is this property: boolean/integer/string?
+ */
+Object.defineProperty(Setting.prototype, 'type', {
+ get: function() {
+ switch (imports.prefBranch.getPrefType(this.name)) {
+ case imports.prefBranch.PREF_BOOL:
+ return this._settings._types.createType('boolean');
+
+ case imports.prefBranch.PREF_INT:
+ return this._settings._types.createType('number');
+
+ case imports.prefBranch.PREF_STRING:
+ return this._settings._types.createType('string');
+
+ default:
+ throw new Error('Unknown type for ' + this.name);
+ }
+ },
+ enumerable: true
+});
+
+/**
+ * What type is this property: boolean/integer/string?
+ */
+Object.defineProperty(Setting.prototype, 'value', {
+ get: function() {
+ switch (imports.prefBranch.getPrefType(this.name)) {
+ case imports.prefBranch.PREF_BOOL:
+ return imports.prefBranch.getBoolPref(this.name);
+
+ case imports.prefBranch.PREF_INT:
+ return imports.prefBranch.getIntPref(this.name);
+
+ case imports.prefBranch.PREF_STRING:
+ var value = imports.prefBranch.getComplexValue(this.name,
+ Ci.nsISupportsString).data;
+ // In case of a localized string
+ if (/^chrome:\/\/.+\/locale\/.+\.properties/.test(value)) {
+ value = imports.prefBranch.getComplexValue(this.name,
+ Ci.nsIPrefLocalizedString).data;
+ }
+ return value;
+
+ default:
+ throw new Error('Invalid value for ' + this.name);
+ }
+ },
+
+ set: function(value) {
+ if (imports.prefBranch.prefIsLocked(this.name)) {
+ throw new Error('Locked preference ' + this.name);
+ }
+
+ switch (imports.prefBranch.getPrefType(this.name)) {
+ case imports.prefBranch.PREF_BOOL:
+ imports.prefBranch.setBoolPref(this.name, value);
+ break;
+
+ case imports.prefBranch.PREF_INT:
+ imports.prefBranch.setIntPref(this.name, value);
+ break;
+
+ case imports.prefBranch.PREF_STRING:
+ imports.supportsString.data = value;
+ imports.prefBranch.setComplexValue(this.name,
+ Ci.nsISupportsString,
+ imports.supportsString);
+ break;
+
+ default:
+ throw new Error('Invalid value for ' + this.name);
+ }
+
+ Services.prefs.savePrefFile(null);
+ },
+
+ enumerable: true
+});