Bug 394522: architecture patch for SeaMonkey pref panes to use <preferences>;

r=Callek, sr=Neil
This commit is contained in:
mnyromyr%tprac.de 2007-10-27 20:08:43 +00:00
Родитель 6b7772ddde
Коммит 442da8c4ba
8 изменённых файлов: 255 добавлений и 68 удалений

Просмотреть файл

@ -392,7 +392,8 @@
<menuitem id="textfieldDirection-swap" hidden="true"/>
<menuseparator id="menu_PrefsSeparator"/>
<menuitem id="menu_preferences" oncommand="goPreferences('navigator', 'chrome://communicator/content/pref/pref-navigator.xul', 'navigator')"/>
<menuitem id="menu_preferences" oncommand="goPreferences('navigator_pane')"/>
<menuitem label="(Legacy Prefwindow...)" oncommand="goPreferences('navigator', 'chrome://communicator/content/pref/pref-navigator.xul', 'navigator')"/>
</menupopup>
</menu>

Просмотреть файл

@ -188,7 +188,8 @@ function openPreferences()
if (win)
win.focus();
else
openWindow(null, "chrome://communicator/content/pref/pref.xul", "chrome,titlebar,dialog=no", "");
openWindow(null, "chrome://communicator/content/pref/preferences.xul",
"chrome,titlebar,dialog=no,resizable", "");
}
function getMostRecentWindow(aType)

Просмотреть файл

@ -60,6 +60,22 @@
navigation tree's top level. <treeitem>s can be nested as needed, but
<treeitem>s without a related <prefpane> will be hidden.
Furthermore, if the <prefwindow> has attribute "autopanes" set to "true",
non-existing <prefpane>s will be generated automatically from certain
attributes of the <treeitem>:
- "url" must contain the <prefpane>'s url
- "prefpane" should contain the <prefpane>'s desired id,
otherwise its url will be used as id
- "helpTopic" may contain an index into SeaMonkey's help
Unlike in XPFE, where preferences panels were loaded into a separate
iframe, <prefpane>s are an integral part of the <prefwindow> document,
by virtue of loadOverlay. Hence <script>s will be loaded into the
<prefwindow> scope and possibly clash. To avoid this, <prefpane>s should
specify a "script" attribute with a whitespace delimited list of scripts
to load into the <prefpane>'s context. The subscriptloader will take care
of any internal scoping, so no this.* fest is necessary inside the script.
<prefwindow> users who want to share the very same file between SeaMonkey
and other toolkit apps should hide the <tree> (set <tree>.hidden=true);
this binding will then unhide the <tree> if necessary, ie more than just
@ -67,7 +83,8 @@
Also, the <tree> will get the class "prefnavtree" added, so that it may be
prestyled by the SeaMonkey themes.
Setting <prefwindow xpfe="false"> will enforce the application of just the
basic toolkit <prefwindow> even in SeaMonkey.
basic toolkit <prefwindow> even in SeaMonkey. The same "xpfe" attribute
exists for <prefpane>, too.
-->
<!DOCTYPE bindings [
@ -83,9 +100,12 @@
<binding id="prefwindow"
extends="chrome://global/content/bindings/preferences.xml#prefwindow">
<resources>
<stylesheet src="chrome://communicator/skin/preferences.css"/>
</resources>
<!-- The only difference between the following <content> and its toolkit
ancestor is the 'navTrees' <vbox> before the 'paneDeck'! -->
ancestor is the help button and the 'navTrees' <vbox> before the 'paneDeck'! -->
<content dlgbuttons="accept,cancel" persist="lastSelected screenX screenY"
closebuttonlabel="&preferencesCloseButton.label;"
closebuttonaccesskey="&preferencesCloseButton.accesskey;"
@ -135,7 +155,6 @@
</content>
<implementation>
<constructor>
<![CDATA[
// grab the first child tree and try to tie it to the prefpanes
@ -162,34 +181,23 @@
if (aTreeElement.parentNode != this)
return;
// don't bother with a navigation tree if we only have one prefpane
aTreeElement.hidden = (this.preferencePanes.length < 2);
if (aTreeElement.hidden)
return;
this._navigationTree = aTreeElement;
// add the class "prefnavtree", so that themes can set defaults
this._navigationTree.className += ' prefnavtree';
// tie the <treeitem>s to the corresponding <prefpane>s
var treeitems = this._navigationTree.getElementsByTagName('treeitem');
for (var i = 0; i < treeitems.length; ++i)
// autogenerate <prefpane>s from <treecell>.url if requested
var autopanes = (this.getAttribute('autopanes') == 'true');
if (!autopanes)
{
var node = treeitems[i];
var pane = document.getElementById(node.getAttribute('prefpane'));
node.prefpane = pane;
if (pane)
pane.preftreeitem = node;
// hide unused treeitems
node.hidden = !pane;
// without autopanes, we can return early: don't bother
// with a navigation tree if we only have one prefpane
aTreeElement.hidden = (this.preferencePanes.length < 2);
if (aTreeElement.hidden)
return;
}
// ensure that we have a tree body (before checking for columns)
if (!this._navigationTree.body)
this._navigationTree.appendChild(document.createElement('treechildren'));
// ensure that we have a tree body
if (!aTreeElement.getElementsByTagName('treechildren').length)
aTreeElement.appendChild(document.createElement('treechildren'));
// ensure that we have a tree column
if (!this._navigationTree.columns.count)
if (!aTreeElement.getElementsByTagName('treecol').length)
{
var navcols = document.createElement('treecols');
var navcol = document.createElement('treecol');
@ -198,36 +206,134 @@
navcol.setAttribute('flex', 1);
navcol.setAttribute('hideheader', true);
navcols.appendChild(navcol);
this._navigationTree.appendChild(navcols);
this._navigationTree.setAttribute('hidecolumnpicker', true);
aTreeElement.appendChild(navcols);
aTreeElement.setAttribute('hidecolumnpicker', true);
}
// add the class "prefnavtree", so that themes can set defaults
aTreeElement.className += ' prefnavtree';
// Do some magic with the treeitem ingredient:
// - if it has a label attribute but no treerow child,
// generate a treerow with a treecell child with that label
// - if it has a prefpane attribute, tie it to that panel
// - if still no panel found and a url attribute is present,
// autogenerate the prefpane and connect to it
var treeitems = aTreeElement.getElementsByTagName('treeitem');
for (var i = 0; i < treeitems.length; ++i)
{
var node = treeitems[i];
var label = node.getAttribute('label');
if (label)
{
// autocreate the treecell?
var row = node.firstChild;
while (row && row.nodeName != 'treerow')
row = row.nextSibling;
if (!row)
{
var itemrow = document.createElement('treerow');
var itemcell = document.createElement('treecell');
itemcell.setAttribute('label', label);
itemrow.appendChild(itemcell);
node.appendChild(itemrow);
}
}
var paneID = node.getAttribute('prefpane');
var pane = paneID && document.getElementById(paneID);
if (!pane && autopanes)
{
// if we have a url, create a <prefpane> for it
var paneURL = node.getAttribute('url');
if (paneURL)
{
// reuse paneID if present, else use the url as id
pane = document.createElement('prefpane');
pane.setAttribute('id', paneID || paneURL);
pane.setAttribute('src', paneURL);
pane.setAttribute('label', label || paneID || paneURL);
var helpTopic = node.getAttribute('helpTopic');
if (helpTopic)
{
pane.setAttribute('helpURI', 'chrome://communicator/locale/help/suitehelp.rdf');
pane.setAttribute('helpTopic', helpTopic);
}
// add pane to prefwindow
this.appendChild(pane);
}
}
node.prefpane = pane;
if (pane)
pane.preftreeitem = node;
// hide unused treeitems
node.hidden = !pane;
}
// now that the number of <prefpane>s is known, try to return early:
// don't bother with a navigation tree if we only have one prefpane
aTreeElement.hidden = (this.preferencePanes.length < 2);
if (aTreeElement.hidden)
return;
this._navigationTree = aTreeElement;
// append any still unreferenced <prefpane>s to the tree's top level
for (var i = 0; i < this.preferencePanes.length; ++i)
for (var j = 0; j < this.preferencePanes.length; ++j)
{
// toolkit believes in fancy pane resizing - we don't
var pane = this.preferencePanes[i];
pane.setAttribute('flex', 1);
if (!("preftreeitem" in pane))
var lostpane = this.preferencePanes[j];
lostpane.setAttribute('flex', 1);
if (!("preftreeitem" in lostpane))
{
var treebody = this._navigationTree
.getElementsByTagName('treechildren')[0];
var treeitem = document.createElement('treeitem');
var treerow = document.createElement('treerow');
var treecell = document.createElement('treecell');
var label = pane.getAttribute('label');
var label = lostpane.getAttribute('label');
if (!label)
label = pane.getAttribute('id');
label = lostpane.getAttribute('id');
treecell.setAttribute('label', label);
treerow.appendChild(treecell);
treeitem.appendChild(treerow);
this._navigationTree.body.appendChild(treeitem);
treeitem.prefpane = pane;
pane.preftreeitem = treeitem;
treebody.appendChild(treeitem);
treeitem.prefpane = lostpane;
lostpane.preftreeitem = treeitem;
}
}
// some of the toolkit base binding's select events fire before we
// get here, so we may need to sync the tree manually now
if (this.currentPane && this.currentPane.loaded)
// Some of the toolkit base binding's select events fire before we
// get here, so we may need to sync the tree manually now.
// Furthermore, if the panel to load initially has just been created,
// we need to load it first.
// (This is a loose copy from the toolkit ctor.)
if (!this.currentPane)
{
var lastPane = this.lastSelected &&
document.getElementById(this.lastSelected);
if (!lastPane)
this.lastSelected = "";
var paneToLoad = null;
if ("arguments" in window && window.arguments[0])
{
var initialPane = document.getElementById(window.arguments[0]);
if (initialPane && initialPane.nodeName == "prefpane")
{
paneToLoad = initialPane;
this.lastSelected = paneToLoad.id;
}
}
else if (lastPane)
paneToLoad = lastPane;
else if (this.preferencePanes.length > 0)
paneToLoad = this.preferencePanes[0];
if (paneToLoad)
{
this.showPane(paneToLoad);
this.currentPane = paneToLoad;
}
}
if (this.currentPane)
this.syncTreeWithPane(this.currentPane);
]]>
</body>
@ -265,9 +371,22 @@
if ('prefpane' in treeitem)
{
pane = treeitem.prefpane;
this.showPane(pane);
if (pane && (this.currentPane != pane))
{
try
{
this.showPane(pane); // may need to load it first
}
catch (e)
{
dump('***** broken prefpane: ' + pane + '\n' + e + '\n');
pane = null;
}
}
}
}
// don't show broken panels
this._paneDeck.hidden = (pane == null);
this.setPaneTitle(pane);
]]>
</body>
@ -299,11 +418,9 @@
]]>
</body>
</method>
</implementation>
<handlers>
<handler event="select">
<![CDATA[
// navigation tree select or deck change?
@ -328,8 +445,60 @@
this.syncTreeWithPane(event.originalTarget);
]]>
</handler>
</handlers>
</binding>
<binding id="prefpane"
extends="chrome://global/content/bindings/preferences.xml#prefpane">
<handlers>
<handler event="paneload">
<![CDATA[
// Since all <prefpane>s now share the same global document, their
// <script>s might clash. Thus we expect the "script" attribute to
// contain a whitespace delimited list of script files to be loaded
// into the <prefpane>'s context.
var subScriptLoader = null;
try
{
subScriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
}
catch (e)
{
var msg = 'prefpane.paneload: no mozIJSSubScriptLoader!\n' + e;
Components.utils.reportError(msg);
return;
}
// list of scripts to load
var scripts = this.getAttribute('script').match(/\S+/g);
if (!scripts)
return;
var count = scripts.length;
for (var i = 0; i < count; ++i)
{
var script = scripts[i];
if (script)
{
try
{
subScriptLoader.loadSubScript(script, this);
}
catch (e)
{
var msg = 'prefpane.paneload: loadSubScript("'
+ script + '") failed:\n' + e;
Components.utils.reportError(msg);
}
}
}
// if we have a Startup method, call it
if ('Startup' in this)
this.Startup();
]]>
</handler>
</handlers>
</binding>
</bindings>

Просмотреть файл

@ -68,6 +68,10 @@ prefwindow[xpfe="false"] {
-moz-binding: url("chrome://global/content/bindings/preferences.xml#prefwindow");
}
prefpane[xpfe="false"] {
-moz-binding: url("chrome://global/content/bindings/preferences.xml#prefpane");
}
/******* SeaMonkey XPFE *******/
/* These bindings reflect SeaMonkey XPFE, modulo new toolkit features. */
toolbox {
@ -89,3 +93,7 @@ menubar {
prefwindow {
-moz-binding: url("chrome://communicator/content/bindings/prefwindow.xml#prefwindow");
}
prefpane {
-moz-binding: url("chrome://communicator/content/bindings/prefwindow.xml#prefpane");
}

Просмотреть файл

@ -136,16 +136,22 @@ comm.jar:
content/communicator/permissions/permissionsNavigatorOverlay.xul (permissions/permissionsNavigatorOverlay.xul)
content/communicator/permissions/permissionsOverlay.js (permissions/permissionsOverlay.js)
content/communicator/permissions/treeUtils.js (permissions/treeUtils.js)
# preferences.xul will replace all the files marked below, once we have migrated all our pref panels
# to toolkit style - begone, foul spirits of the past!
content/communicator/pref/preferences.xul (pref/preferences.xul)
# files deprecated by preferences.xul: begin
content/communicator/pref/nsPrefWindow.js (pref/nsPrefWindow.js)
content/communicator/pref/nsWidgetStateManager.js (/xpfe/global/resources/content/nsWidgetStateManager.js)
content/communicator/pref/overrideHandler.js (pref/overrideHandler.js)
content/communicator/pref/pref.xul (pref/pref.xul)
content/communicator/pref/preftree.xul (pref/preftree.xul)
content/communicator/pref/pref-help.js (pref/pref-help.js)
# files deprecated by preferences.xul: end
content/communicator/pref/pref-advanced.xul (pref/pref-advanced.xul)
content/communicator/pref/pref-appearance.xul (pref/pref-appearance.xul)
content/communicator/pref/pref-applications.xul (pref/pref-applications.xul)
content/communicator/pref/pref-applications.js (pref/pref-applications.js)
content/communicator/pref/pref-applications-edit.xul (pref/pref-applications-edit.xul)
content/communicator/pref/overrideHandler.js (pref/overrideHandler.js)
content/communicator/pref/pref-cache.js (pref/pref-cache.js)
content/communicator/pref/pref-cache.xul (pref/pref-cache.xul)
content/communicator/pref/pref-charset.js (pref/pref-charset.js)
@ -156,7 +162,6 @@ comm.jar:
content/communicator/pref/pref-download.xul (pref/pref-download.xul)
content/communicator/pref/pref-fonts.js (pref/pref-fonts.js)
content/communicator/pref/pref-fonts.xul (pref/pref-fonts.xul)
content/communicator/pref/pref-help.js (pref/pref-help.js)
content/communicator/pref/pref-history.xul (pref/pref-history.xul)
content/communicator/pref/pref-http.js (pref/pref-http.js)
content/communicator/pref/pref-http.xul (pref/pref-http.xul)

Просмотреть файл

@ -237,31 +237,32 @@ function getBrowserURL() {
function goPreferences(containerID, paneURL, itemID)
{
var resizable;
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
try {
// We are resizable ONLY if in box debugging mode, because in
// this special debug mode it is often impossible to see the
// content of the debug panel in order to disable debug mode.
resizable = pref.getBoolPref("xul.debug.box");
}
catch (e) {
resizable = false;
}
//check for an existing pref window and focus it; it's not application modal
const kWindowMediatorContractID = "@mozilla.org/appshell/window-mediator;1";
const kWindowMediatorIID = Components.interfaces.nsIWindowMediator;
const kWindowMediator = Components.classes[kWindowMediatorContractID].getService(kWindowMediatorIID);
var lastPrefWindow = kWindowMediator.getMostRecentWindow("mozilla:preferences");
const kWindowMediator = Components.classes[kWindowMediatorContractID]
.getService(kWindowMediatorIID);
// Bug 394522:
// Until all our pref panels have been migrated to the toolkit way,
// we need to distinguish between old and new methods of opening a specific
// panel -> prefwindow only needs the prefpane id in window.arguments[0], so
// this function here only needs to get one param passed in the future
// -> we assume that a new style style pref panel is requested if only one
// (the first) parameter is passed.
var legacyPrefWindow = paneURL || itemID;
var prefWindowFragment = legacyPrefWindow ? "pref" : "preferences";
var lastPrefWindow = kWindowMediator.getMostRecentWindow("mozilla:" + prefWindowFragment);
if (lastPrefWindow)
lastPrefWindow.focus();
else {
var resizability = resizable ? "yes" : "no";
var features = "chrome,titlebar,resizable=" + resizability;
openDialog("chrome://communicator/content/pref/pref.xul","PrefWindow",
features, paneURL, containerID, itemID);
if (!legacyPrefWindow) {
paneURL = containerID;
containerID = null;
}
openDialog("chrome://communicator/content/pref/" + prefWindowFragment + ".xul",
"PrefWindow", "chrome,titlebar,dialog=no,resizable",
paneURL, containerID, itemID);
}
}

Просмотреть файл

@ -11,6 +11,7 @@ classic.jar:
skin/classic/communicator/communicator.css (communicator/communicator.css)
skin/classic/communicator/communicatorBindings.xml (communicator/communicatorBindings.xml)
skin/classic/communicator/helpOverlay.css (communicator/helpOverlay.css)
skin/classic/communicator/preferences.css (communicator/preferences.css)
skin/classic/communicator/prefpanels.css (communicator/prefpanels.css)
skin/classic/communicator/smileys.css (communicator/smileys.css)
skin/classic/communicator/bookmarks/bookmark-folder-button.gif (communicator/bookmarks/bookmark-folder-button.gif)

Просмотреть файл

@ -7,6 +7,7 @@ modern.jar:
% skin navigator modern/1.0 %skin/modern/navigator/
skin/modern/communicator/brand.css (communicator/brand.css)
skin/modern/communicator/prefpanels.css (communicator/prefpanels.css)
skin/modern/communicator/preferences.css (communicator/preferences.css)
skin/modern/communicator/tasksOverlay.css (communicator/tasksOverlay.css)
skin/modern/communicator/button.css (communicator/button.css)
skin/modern/communicator/toolbar.css (communicator/toolbar.css)