Bug 107148 about:config todo list r=callion rs=sspitzer

This commit is contained in:
neil%parkwaycc.co.uk 2003-01-16 09:50:27 +00:00
parent 01167ac507
commit 1c150b0e04
3 changed files with 423 additions and 230 deletions

View File

@ -20,245 +20,410 @@
* Contributors:
* Chip Clark <chipc@netscape.com>
* Seth Spitzer <sspitzer@netscape.com>
* Neil Rashbrook <neil@parkwaycc.co.uk>
*/
var baseArray = new Array();
const kDefault = 0;
const kUserSet = 1;
const kLocked = 2;
const nsIPrefLocalizedString = Components.interfaces.nsIPrefLocalizedString;
const nsISupportsString = Components.interfaces.nsISupportsString;
const nsIPromptService = Components.interfaces.nsIPromptService;
const nsIPrefService = Components.interfaces.nsIPrefService;
const nsIPrefBranch = Components.interfaces.nsIPrefBranch;
const nsIClipboardHelper = Components.interfaces.nsIClipboardHelper;
const nsIAtomService = Components.interfaces.nsIAtomService;
const nsSupportsString_CONTRACTID = "@mozilla.org/supports-string;1";
const nsPrompt_CONTRACTID = "@mozilla.org/embedcomp/prompt-service;1";
const nsPrefService_CONTRACTID = "@mozilla.org/preferences-service;1";
const nsClipboardHelper_CONTRACTID = "@mozilla.org/widget/clipboardhelper;1";
const nsAtomService_CONTRACTID = "@mozilla.org/atom-service;1";
var atomService = Components.classes[nsAtomService_CONTRACTID].getService(nsIAtomService);
var gLockAtoms = [atomService.getAtom("default"), atomService.getAtom("user"), atomService.getAtom("locked")];
const gPromptService = Components.classes[nsPrompt_CONTRACTID].getService(nsIPromptService);
const gPrefService = Components.classes[nsPrefService_CONTRACTID].getService(nsIPrefService);
const gPrefBranch = gPrefService.getBranch(null).QueryInterface(Components.interfaces.nsIPrefBranchInternal);
const gClipboardHelper = Components.classes[nsClipboardHelper_CONTRACTID].getService(nsIClipboardHelper);
const gAtomService = Components.classes[nsAtomService_CONTRACTID].getService(nsIAtomService);
var gLockAtoms = [gAtomService.getAtom("default"), gAtomService.getAtom("user"), gAtomService.getAtom("locked")];
// XXX get these from a string bundle
var gLockStrs = ["default", "user set","locked"];
var gLockStrs = ["default", "user set", "locked"];
var gTypeStrs = [];
gTypeStrs[nsIPrefBranch.PREF_STRING] = "string";
gTypeStrs[nsIPrefBranch.PREF_INT] = "integer";
gTypeStrs[nsIPrefBranch.PREF_BOOL] = "boolean";
const kStrType = 0;
const kIntType = 1;
const kBoolType = 2;
const PREF_IS_DEFAULT_VALUE = 0;
const PREF_IS_USER_SET = 1;
const PREF_IS_LOCKED = 2;
var gTypeStrs = ["string","int","bool"];
var gPrefHash = {};
var gPrefArray = [];
var gFastIndex = 0;
var gSortedColumn = "prefCol";
var gSortFunction = null;
var gSortDirection = 1; // 1 is ascending; -1 is descending
var gTree;
var view = {
get rowCount() { return gPrefArray.length; },
getCellText : function(k, col) {
if (!(k in gPrefArray))
return "";
var value = gPrefArray[k][col];
var view = ({
rowCount : 0,
getCellText : function(k, col) {
if (!baseArray[k])
return "";
var value = baseArray[k][col];
var strvalue;
switch (col) {
case "lockCol":
return gLockStrs[value];
case "typeCol":
return gTypeStrs[value];
default:
return value;
}
},
getRowProperties : function(index, prop) {},
getCellProperties : function(index, col, prop) {
prop.AppendElement(gLockAtoms[gPrefArray[index].lockCol]);
},
getColumnProperties : function(col, elt, prop) {},
treebox : null,
selection : null,
isContainer : function(index) { return false; },
isContainerOpen : function(index) { return false; },
isContainerEmpty : function(index) { return false; },
isSorted : function() { return true; },
canDropOn : function(index) { return false; },
canDropBeforeAfter : function(index, before) { return false; },
drop : function(row,orientation) {},
setTree : function(out) { this.treebox = out; },
getParentIndex: function(rowIndex) { return -1; },
hasNextSibling: function(rowIndex, afterIndex) { return false; },
getLevel: function(index) { return 1; },
getImageSrc: function(row, colID) { return ""; },
toggleOpenState : function(index) {},
cycleHeader: function(colID, elt) {
var index = this.selection.currentIndex;
if (colID == gSortedColumn)
gSortDirection = -gSortDirection;
if (colID == gSortedColumn && gFastIndex == gPrefArray.length) {
gPrefArray.reverse();
if (index >= 0)
index = gPrefArray.length - index - 1;
}
else {
var pref = null;
if (index >= 0)
pref = gPrefArray[index];
var old = document.getElementById(gSortedColumn);
old.setAttribute("sortDirection", "");
gPrefArray.sort(gSortFunction = gSortFunctions[colID]);
gSortedColumn = colID;
if (pref)
index = getIndexOfPref(pref);
}
elt.setAttribute("sortDirection", gSortDirection > 0 ? "ascending" : "descending");
this.treebox.invalidate();
if (index >= 0) {
this.selection.select(index);
this.treebox.ensureRowIsVisible(index);
}
gFastIndex = gPrefArray.length;
},
selectionChanged : function() {},
cycleCell: function(row, colID) {},
isEditable: function(row, colID) {return false; },
setCellText: function(row, colID, value) {},
performAction: function(action) {},
performActionOnRow: function(action, row) {},
performActionOnCell: function(action, row, colID) {},
isSeparator: function(index) {return false; }
};
switch (col) {
case "lockCol":
strvalue = gLockStrs[value];
break;
case "typeCol":
strvalue = gTypeStrs[value];
break;
default:
// already a str.
strvalue = value;
break;
}
return strvalue;
},
getRowProperties : function(index, prop) {},
getCellProperties : function(index, col, prop) {
prop.AppendElement(gLockAtoms[baseArray[index]["lockCol"]]);
},
getColumnProperties : function(col, elt, prop) {},
treebox : null,
selection : null,
isContainer : function(index) { return false; },
isContainerOpen : function(index) { return false; },
isContainerEmpty : function(index) { return false; },
isSorted : function() { },
canDropOn : function(index) { return false; },
canDropBeforeAfter : function(index,before) { return false; },
drop : function(row,orientation) {},
setTree : function(out) { this.treebox = out; },
getParentIndex: function(rowIndex) { return -1 },
hasNextSibling: function(rowIndex, afterIndex) { return false },
getLevel: function(index) { return 1},
getImageSrc: function(row, colID) { return ""},
toggleOpenState : function(index) {},
cycleHeader: function(colID, elt) {},
selectionChanged : function() {},
cycleCell: function(row, colID) {},
isEditable: function(row, valueCol) {return true},
isEditable: function(row, colID) {return false},
setCellText: function(row, colID, value) {},
performAction: function(action) {},
performActionOnRow: function(action, row) {},
performActionOnCell: function(action, row, colID) {},
isSeparator: function(index) {return false}
});
// find the index in gPrefArray of a pref object
// either one that was looked up in gPrefHash
// or in case it was moved after sorting
function getIndexOfPref(pref)
{
var low = -1, high = gFastIndex;
var index = (low + high) >> 1;
while (index > low) {
var mid = gPrefArray[index];
if (mid == pref)
return index;
if (gSortFunction(mid, pref) < 0)
low = index;
else
high = index;
index = (low + high) >> 1;
}
for (index = gFastIndex; index < gPrefArray.length; ++index)
if (gPrefArray[index] == pref)
break;
return index;
}
function getNearestIndexOfPref(pref)
{
var low = -1, high = gFastIndex;
var index = (low + high) >> 1;
while (index > low) {
if (gSortFunction(gPrefArray[index], pref) < 0)
low = index;
else
high = index;
index = (low + high) >> 1;
}
return high;
}
var gPrefListener =
{
observe: function(subject, topic, prefName)
{
if (topic != "nsPref:changed")
return;
if (/capability/.test(prefName)) // avoid displaying "private" preferences
return;
var index = gPrefArray.length;
if (prefName in gPrefHash) {
index = getIndexOfPref(gPrefHash[prefName]);
fetchPref(prefName, index);
view.treebox.invalidateRow(index);
if (gSortedColumn == "lockCol" || gSortedColumn == "valueCol")
gFastIndex = 1; // TODO: reinsert and invalidate range
} else {
fetchPref(prefName, index);
if (index == gFastIndex) {
// Keep the array sorted by reinserting the pref object
var pref = gPrefArray.pop();
index = getNearestIndexOfPref(pref);
gPrefArray.splice(index, 0, pref);
gFastIndex = gPrefArray.length;
}
view.treebox.rowCountChanged(index, 1);
}
}
};
function prefObject(prefName, prefIndex)
{
this.prefCol = prefName;
}
prefObject.prototype =
{
lockCol: PREF_IS_DEFAULT_VALUE,
typeCol: nsIPrefBranch.PREF_STRING,
valueCol: ""
};
function fetchPref(prefName, prefIndex)
{
var pref = new prefObject(prefName);
gPrefHash[prefName] = pref;
gPrefArray[prefIndex] = pref;
if (gPrefBranch.prefIsLocked(prefName))
pref.lockCol = PREF_IS_LOCKED;
else if (gPrefBranch.prefHasUserValue(prefName))
pref.lockCol = PREF_IS_USER_SET;
try {
switch (gPrefBranch.getPrefType(prefName)) {
case gPrefBranch.PREF_BOOL:
pref.typeCol = gPrefBranch.PREF_BOOL;
// convert to a string
pref.valueCol = gPrefBranch.getBoolPref(prefName).toString();
break;
case gPrefBranch.PREF_INT:
pref.typeCol = gPrefBranch.PREF_INT;
// convert to a string
pref.valueCol = gPrefBranch.getIntPref(prefName).toString();
break;
default:
case gPrefBranch.PREF_STRING:
pref.valueCol = gPrefBranch.getComplexValue(prefName, nsISupportsString).data;
// Try in case it's a localized string (will throw an exception if not)
if (pref.lockCol == PREF_IS_DEFAULT_VALUE)
pref.valueCol = gPrefBranch.getComplexValue(prefName, nsIPrefLocalizedString).data;
break;
}
} catch (e) {
// Also catch obscure cases in which you can't tell in advance
// that the pref exists but has no user or default value...
}
}
function onConfigLoad()
{
document.title = "about:config";
document.title = "about:config";
var prefCount = {value:0};
var prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
var prefBranch = prefService.getBranch(null);
var prefArray = prefBranch.getChildList("" , prefCount);
var prefName, prefType, prefValue, prefIndex, prefLockState;
var prefCount = { value: 0 };
var prefArray = gPrefBranch.getChildList("", prefCount);
var i = 0;
var j = 0; // This is used to avoid counting the "capability" preferences
var k = 0; // This is to maintain a count of prefs (not including the "capability" prefs);
for (var i = 0; i < prefCount.value; ++i)
{
var prefName = prefArray[i];
if (/capability/.test(prefName)) // avoid displaying "private" preferences
continue;
prefArray.sort();
for (i = 0; i < prefCount.value; i++)
{
if((prefArray[i].indexOf("capability", 0) + 1) > 0) // avoid displaying "private" preferences
{
j++;
continue;
}
fetchPref(prefName, gPrefArray.length);
}
k = (i - j); // avoid numbering "capability" prefs
prefIndex = k + 1;
if (prefBranch.prefIsLocked(prefArray[i]))
prefLockState = kLocked;
else if(prefBranch.prefHasUserValue(prefArray[i]))
prefLockState = kUserSet;
else
prefLockState = kDefault;
const nsIPrefBranch = Components.interfaces.nsIPrefBranch;
switch (prefBranch.getPrefType(prefArray[i])) {
case nsIPrefBranch.PREF_INT:
prefType = kIntType;
// convert to a string
prefValue = "" + prefBranch.getIntPref(prefArray[i]);
break;
case nsIPrefBranch.PREF_BOOL:
prefType = kBoolType;
// convert to a string
if (prefBranch.getBoolPref(prefArray[i]))
prefValue = "true";
else
prefValue = "false";
break;
case nsIPrefBranch.PREF_STRING:
default:
prefType = kStrType;
prefValue = htmlEscape(prefBranch.getCharPref(prefArray[i]));
break;
}
prefArray[i] = htmlEscape(prefArray[i]);
baseArray[k] = {indexCol:prefIndex, prefCol:prefArray[i], lockCol:prefLockState, typeCol:prefType, valueCol:prefValue};
}
view.rowCount = k + 1;
gTree = document.getElementById("configTree");
gTree.treeBoxObject.view = view;
}
function htmlEscape(s)
{
s = s.replace(/\&/g, "&amp;");
s = s.replace(/\>/g, "&gt;");
s = s.replace(/\</g, "&lt;");
return s;
}
function ConfigOnClick(event)
{
// we only care about button 0 (left click) events
if (event.button != 0) return;
var t = event.originalTarget;
if (t.localName == "treecol") {
HandleColumnClick(t.id);
}
}
var gSortedColumn = "indexCol";
var gSortAscending = true;
function stringSortFunction(a,b)
{
var value;
if (a<b)
value = 1;
else if (a>b)
value = -1;
else
value = 0;
if (gSortAscending)
return value;
else
return (value * -1);
}
function intSortFunction(a,b)
{
if (gSortAscending)
return (a - b);
else
return (b - a);
}
function indexColSortFunction(x,y)
{
return intSortFunction(x.indexCol, y.indexCol);
}
function prefColSortFunction(x,y)
{
return stringSortFunction(x.prefCol, y.prefCol);
}
function lockColSortFunction(x,y)
{
return stringSortFunction(x.lockCol, y.lockCol);
}
function typeColSortFunction(x,y)
{
return intSortFunction(x.typeCol, y.typeCol);
}
function valueColSortFunction(x,y)
{
return stringSortFunction(x.valueCol, y.valueCol);
}
var gSortFunctions = {indexCol:indexColSortFunction,
prefCol:prefColSortFunction,
lockCol:lockColSortFunction,
typeCol:typeColSortFunction,
valueCol:valueColSortFunction};
function HandleColumnClick(id)
{
if (id == gSortedColumn) {
gSortAscending = !gSortAscending;
baseArray.reverse();
var descending = document.getElementsByAttribute("sortDirection", "descending");
if (descending.length) {
gSortedColumn = descending[0].id;
gSortDirection = -1;
}
else {
baseArray.sort(gSortFunctions[id]);
gSortedColumn = id;
var ascending = document.getElementsByAttribute("sortDirection", "ascending");
if (ascending.length)
gSortedColumn = ascending[0].id;
else
document.getElementById(gSortedColumn).setAttribute("sortDirection", "ascending");
}
gSortFunction = gSortFunctions[gSortedColumn];
gPrefArray.sort(gSortFunction);
gFastIndex = gPrefArray.length;
gPrefBranch.addObserver("", gPrefListener, false);
gTree.treeBoxObject.invalidate();
document.getElementById("configTree").view = view;
}
function onConfigUnload()
{
gPrefBranch.removeObserver("", gPrefListener);
}
function prefColSortFunction(x, y)
{
if (x.prefCol > y.prefCol)
return gSortDirection;
if (x.prefCol < y.prefCol)
return -gSortDirection;
return 0;
}
function lockColSortFunction(x, y)
{
if (x.lockCol != y.lockCol)
return gSortDirection * (y.lockCol - x.lockCol);
return prefColSortFunction(x, y);
}
function typeColSortFunction(x, y)
{
if (x.typeCol != y.typeCol)
return gSortDirection * (y.typeCol - x.typeCol);
return prefColSortFunction(x, y);
}
function valueColSortFunction(x, y)
{
if (x.valueCol > y.valueCol)
return gSortDirection;
if (x.valueCol < y.valueCol)
return -gSortDirection;
return prefColSortFunction(x, y);
}
const gSortFunctions =
{
prefCol: prefColSortFunction,
lockCol: lockColSortFunction,
typeCol: typeColSortFunction,
valueCol: valueColSortFunction
};
function updateContextMenu(popup) {
if (view.selection.currentIndex < 0)
return false;
var pref = gPrefArray[view.selection.currentIndex];
var reset = popup.lastChild;
reset.setAttribute("disabled", pref.lockCol != PREF_IS_USER_SET);
var modify = reset.previousSibling;
modify.setAttribute("disabled", pref.lockCol == PREF_IS_LOCKED);
return true;
}
function copyName()
{
gClipboardHelper.copyString(gPrefArray[view.selection.currentIndex].prefCol);
}
function copyValue()
{
gClipboardHelper.copyString(gPrefArray[view.selection.currentIndex].valueCol);
}
function ModifySelected()
{
ModifyPref(gPrefArray[view.selection.currentIndex]);
}
function ResetSelected()
{
var entry = gPrefArray[view.selection.currentIndex];
gPrefBranch.clearUserPref(entry.prefCol);
}
function NewPref(type)
{
var result = { value: "" };
var dummy = { value: 0 };
// XXX get these from a string bundle
if (gPromptService.prompt(window,
"New " + gTypeStrs[type] + " value",
"Enter the preference name",
result,
null,
dummy)) {
var pref;
if (result.value in gPrefHash)
pref = gPrefHash[result.value];
else
pref = { prefCol: result.value, lockCol: PREF_IS_DEFAULT_VALUE, typeCol: type, valueCol: "" };
if (ModifyPref(pref))
setTimeout(gotoPref, 0, result.value);
}
}
function gotoPref(prefCol) {
var index = getIndexOfPref(gPrefHash[prefCol]);
view.selection.select(index);
view.treebox.ensureRowIsVisible(index);
}
function ModifyPref(entry)
{
if (entry.lockCol == PREF_IS_LOCKED)
return false;
var result = { value: entry.valueCol };
var dummy = { value: 0 };
// XXX get this from a string bundle
if (!gPromptService.prompt(window,
"Enter " + gTypeStrs[entry.typeCol] + " value",
entry.prefCol,
result,
null,
dummy))
return false;
switch (entry.typeCol) {
case nsIPrefBranch.PREF_BOOL:
gPrefBranch.setBoolPref(entry.prefCol, eval(result.value));
break;
case nsIPrefBranch.PREF_INT:
gPrefBranch.setIntPref(entry.prefCol, eval(result.value));
break;
default:
case nsIPrefBranch.PREF_STRING:
var supportsString = Components.classes[nsSupportsString_CONTRACTID].createInstance(nsISupportsString);
supportsString.data = result.value;
gPrefBranch.setComplexValue(entry.prefCol, nsISupportsString, supportsString);
break;
}
return true;
}

View File

@ -24,6 +24,7 @@ Rights Reserved.
Contributors:
Chip Clark <chipc@netscape.com>
Seth Spitzer <sspitzer@netscape.com>
Neil Rashbrook <neil@parkwaycc.co.uk>
-->
<!DOCTYPE window SYSTEM "chrome://global/locale/config.dtd">
@ -32,34 +33,47 @@ Seth Spitzer <sspitzer@netscape.com>
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
width="750"
height="500"
onunload="onConfigUnload();"
onload="onConfigLoad();">
<script src="chrome://global/content/config.js"/>
<tree id="configTree" flex="1" onclick="ConfigOnClick(event);" class="plain">
<popup id="configContext" onpopupshowing="return updateContextMenu(this);">
<menuitem label="&copyName.label;" accesskey="&copyName.accesskey;" oncommand="copyName();"/>
<menuitem label="&copyValue.label;" accesskey="&copyValue.accesskey;" oncommand="copyValue();"/>
<menu label="&new.label;" accesskey="&new.accesskey;">
<menupopup>
<menuitem label="&string.label;" accesskey="&string.accesskey;" oncommand="NewPref(nsIPrefBranch.PREF_STRING);"/>
<menuitem label="&integer.label;" accesskey="&integer.accesskey;" oncommand="NewPref(nsIPrefBranch.PREF_INT);"/>
<menuitem label="&boolean.label;" accesskey="&boolean.accesskey;" oncommand="NewPref(nsIPrefBranch.PREF_BOOL);"/>
</menupopup>
</menu>
<menuitem label="&modify.label;" accesskey="&modify.accesskey;" oncommand="ModifySelected();"/>
<menuitem label="&reset.label;" accesskey="&reset.accesskey;" oncommand="ResetSelected();"/>
</popup>
<tree id="configTree" flex="1" class="plain" seltype="single"
enableColumnDrag="true" context="configContext">
<treecols>
<treecol id="indexCol" label="&idxColumn.label;" flex="1"
class="sortDirectionIndicator"
persist="hidden width sortActive sortDirection"/>
<splitter class="tree-splitter" />
<treecol id="prefCol" label="&prefColumn.label;" flex="7"
class="sortDirectionIndicator"
persist="hidden width sortActive sortDirection"/>
ignoreincolumnpicker="true"
persist="hidden width ordinal sortDirection"/>
<splitter class="tree-splitter" />
<treecol id="lockCol" label="&lockColumn.label;" flex="1"
<treecol id="lockCol" label="&lockColumn.label;" flex="1"
class="sortDirectionIndicator"
persist="hidden width sortActive sortDirection"/>
persist="hidden width ordinal sortDirection"/>
<splitter class="tree-splitter" />
<treecol id="typeCol" label="&typeColumn.label;" flex="1"
<treecol id="typeCol" label="&typeColumn.label;" flex="1"
class="sortDirectionIndicator"
persist="hidden width sortActive sortDirection"/>
persist="hidden width ordinal sortDirection"/>
<splitter class="tree-splitter" />
<treecol id="valueCol" label="&valueColumn.label;" flex="10"
class="sortDirectionIndicator"
persist="hidden width sortActive sortDirection"/>
persist="hidden width ordinal sortDirection"/>
</treecols>
<treechildren id="configTreeBody"/>
<treechildren id="configTreeBody" ondblclick="if (event.button == 0) ModifySelected();"/>
</tree>
</window>

View File

@ -28,6 +28,20 @@ Rights Reserved.
<!ENTITY prefColumnHeader.tooltip "Click to sort">
<!ENTITY columnChooser.tooltip "Click to select columns to display">
<!--Context Menu-->
<!ENTITY copyName.label "Copy Name">
<!ENTITY copyName.accesskey "C">
<!ENTITY copyValue.label "Copy Value">
<!ENTITY copyValue.accesskey "V">
<!ENTITY modify.label "Modify">
<!ENTITY modify.accesskey "M">
<!ENTITY reset.label "Reset">
<!ENTITY reset.accesskey "R">
<!ENTITY new.label "New">
<!ENTITY new.accesskey "N">
<!ENTITY string.label "String">
<!ENTITY string.accesskey "S">
<!ENTITY integer.label "Integer">
<!ENTITY integer.accesskey "I">
<!ENTITY boolean.label "Boolean">
<!ENTITY boolean.accesskey "B">