Bug 402252 - application details should be accessible from prefs UI. r=Mano, ui-r=beltzner (over IRC), a1.9=damons.

This commit is contained in:
florian@queze.net 2008-01-29 07:30:53 -08:00
Родитель 98cdbd0d05
Коммит 508586ad0a
7 изменённых файлов: 366 добавлений и 37 удалений

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

@ -0,0 +1,132 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (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.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org Code.
#
# The Initial Developer of the Original Code is
# Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2008
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Florian Queze <florian@queze.net> (Original author)
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
const Ci = Components.interfaces;
const Cc = Components.classes;
var TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
var gAppManagerDialog = {
_removed: [],
init: function appManager_init() {
this.handlerInfo = window.arguments[0];
var bundle = document.getElementById("appManagerBundle");
var contentText;
if (this.handlerInfo.type == TYPE_MAYBE_FEED)
contentText = bundle.getString("handleWebFeeds");
else {
var description = gApplicationsPane._describeType(this.handlerInfo);
var key =
(this.handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo) ? "handleFile"
: "handleProtocol";
contentText = bundle.getFormattedString(key, [description]);
}
contentText = bundle.getFormattedString("descriptionApplications", [contentText]);
document.getElementById("appDescription").textContent = contentText;
var list = document.getElementById("appList");
var apps = this.handlerInfo.possibleApplicationHandlers.enumerate();
while (apps.hasMoreElements()) {
let app = apps.getNext();
app.QueryInterface(Ci.nsIHandlerApp);
var item = list.appendItem(app.name);
item.setAttribute("image", gApplicationsPane._getIconURLForHandlerApp(app));
item.className = "listitem-iconic";
item.app = app;
}
list.selectedIndex = 0;
},
onOK: function appManager_onOK() {
if (!this._removed.length) {
// return early to avoid calling the |store| method.
return;
}
for (var i = 0; i < this._removed.length; ++i)
this.handlerInfo.removePossibleApplicationHandler(this._removed[i]);
this.handlerInfo.store();
},
onCancel: function appManager_onCancel() {
// do nothing
},
remove: function appManager_remove() {
var list = document.getElementById("appList");
this._removed.push(list.selectedItem.app);
var index = list.selectedIndex;
list.removeItemAt(index);
if (list.getRowCount() == 0) {
// The list is now empty, make the bottom part disappear
document.getElementById("appDetails").hidden = true;
}
else {
// Select the item at the same index, if we removed the last
// item of the list, select the previous item
if (index == list.getRowCount())
--index;
list.selectedIndex = index;
}
},
onSelect: function appManager_onSelect() {
var list = document.getElementById("appList");
if (!list.selectedItem) {
document.getElementById("remove").disabled = true;
return;
}
document.getElementById("remove").disabled = false;
var app = list.selectedItem.app;
var address = "";
if (app instanceof Ci.nsILocalHandlerApp)
address = app.executable.path;
else if (app instanceof Ci.nsIWebHandlerApp)
address = app.uriTemplate;
else if (app instanceof Ci.nsIWebContentHandlerInfo)
address = app.uri;
document.getElementById("appLocation").value = address;
var bundle = document.getElementById("appManagerBundle");
var appType = app instanceof Ci.nsILocalHandlerApp ? "descriptionLocalApp"
: "descriptionWebApp";
document.getElementById("appType").value = bundle.getString(appType);
}
};

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

@ -0,0 +1,90 @@
<?xml version="1.0"?>
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (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.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org Code.
#
# The Initial Developer of the Original Code is
# Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2008
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Florian Queze <florian@queze.net> (Original author)
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
<?xml-stylesheet href="chrome://global/skin/"?>
<!DOCTYPE dialog SYSTEM "chrome://browser/locale/preferences/applicationManager.dtd">
<dialog id="appManager"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
buttons="accept,cancel"
onload="gAppManagerDialog.init();"
ondialogaccept="gAppManagerDialog.onOK();"
ondialogcancel="gAppManagerDialog.onCancel();"
title="&appManager.title;"
style="&appManager.style;"
persist="screenX screenY">
<script type="application/javascript"
src="chrome://browser/content/preferences/applicationManager.js"/>
<script type="application/javascript"
src="chrome://browser/content/preferences/applications.js"/>
<commandset id="appManagerCommandSet">
<command id="cmd_remove"
oncommand="gAppManagerDialog.remove();"
disabled="true"/>
</commandset>
<keyset id="appManagerKeyset">
<key id="delete" keycode="VK_DELETE" command="cmd_remove"/>
</keyset>
<stringbundleset id="appManagerBundleset">
<stringbundle id="appManagerBundle"
src="chrome://browser/locale/preferences/applicationManager.properties"/>
</stringbundleset>
<description id="appDescription"/>
<separator class="thin"/>
<hbox flex="1">
<listbox id="appList" onselect="gAppManagerDialog.onSelect();" flex="1"/>
<vbox>
<button id="remove"
label="&remove.label;"
accesskey="&remove.accesskey;"
command="cmd_remove"/>
<spacer flex="1"/>
</vbox>
</hbox>
<vbox id="appDetails">
<separator class="thin"/>
<label id="appType"/>
<textbox id="appLocation" readonly="true" class="plain"/>
</vbox>
</dialog>

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

@ -25,6 +25,7 @@
# Jeff Walden <jwalden+code@mit.edu>
# Asaf Romano <mozilla.mano@sent.com>
# Myk Melez <myk@mozilla.org>
# Florian Queze <florian@queze.net>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
@ -272,6 +273,25 @@ HandlerInfoWrapper.prototype = {
this.possibleApplicationHandlers.appendElement(aNewHandler, false);
},
removePossibleApplicationHandler: function(aHandler) {
var defaultApp = this.preferredApplicationHandler;
if (defaultApp && aHandler.equals(defaultApp)) {
// If the app we remove was the default app, we must make sure
// it won't be used anymore
this.alwaysAskBeforeHandling = true;
this.preferredApplicationHandler = null;
}
var handlers = this.possibleApplicationHandlers;
for (var i = 0; i < handlers.length; ++i) {
var handler = handlers.queryElementAt(i, Ci.nsIHandlerApp);
if (handler.equals(aHandler)) {
handlers.removeElementAt(i);
break;
}
}
},
get hasDefaultHandler() {
return this.wrappedHandlerInfo.hasDefaultHandler;
},
@ -566,6 +586,7 @@ var feedHandlerInfo = {
// methods its callers invoke, namely appendElement and nsIArray::enumerate.
this._possibleApplicationHandlers = {
_inner: [],
_removed: [],
QueryInterface: function(aIID) {
if (aIID.equals(Ci.nsIMutableArray) ||
@ -576,12 +597,25 @@ var feedHandlerInfo = {
throw Cr.NS_ERROR_NO_INTERFACE;
},
get length() {
return this._inner.length;
},
enumerate: function() {
return new ArrayEnumerator(this._inner);
},
appendElement: function(aHandlerApp, aWeak) {
this._inner.push(aHandlerApp);
},
removeElementAt: function(aIndex) {
this._removed.push(this._inner[aIndex]);
this._inner.splice(aIndex, 1);
},
queryElementAt: function(aIndex, aInterface) {
return this._inner[aIndex].QueryInterface(aInterface);
}
};
@ -748,11 +782,28 @@ var feedHandlerInfo = {
// Storage
// Changes to the preferred action and handler take effect immediately
// (we write them out to the preferences right as they happen), so we don't
// need to do anything when the controller calls store() after modifying
// the handler.
// (we write them out to the preferences right as they happen),
// so we when the controller calls store() after modifying the handlers,
// the only thing we need to store is the removal of possible handlers
// XXX Should we hold off on making the changes until this method gets called?
store: function() {},
store: function() {
for each (let app in this._possibleApplicationHandlers._removed) {
if (app instanceof Ci.nsILocalHandlerApp) {
let pref = this.element(PREF_FEED_SELECTED_APP);
var preferredAppFile = pref.value;
if (preferredAppFile) {
let preferredApp = getLocalHandlerApp(preferredAppFile);
if (app.equals(preferredApp))
pref.reset();
}
}
else {
app.QueryInterface(Ci.nsIWebContentHandlerInfo);
this._converterSvc.removeContentHandler(app.contentType, app.uri);
}
}
this._possibleApplicationHandlers._removed = [];
},
//**************************************************************************//
@ -1137,15 +1188,17 @@ var gApplicationsPane = {
case Ci.nsIHandlerInfo.useHelperApp:
var preferredApp = aHandlerInfo.preferredApplicationHandler;
var name;
if (preferredApp instanceof Ci.nsILocalHandlerApp)
return getDisplayNameForFile(preferredApp.executable);
name = getDisplayNameForFile(preferredApp.executable);
else
return preferredApp.name;
name = preferredApp.name;
return this._prefsBundle.getFormattedString("useApp", [name]);
case Ci.nsIHandlerInfo.handleInternally:
// For the feed type, handleInternally means live bookmarks.
if (aHandlerInfo.type == TYPE_MAYBE_FEED)
return this._prefsBundle.getFormattedString("liveBookmarksInApp",
return this._prefsBundle.getFormattedString("addLiveBookmarksInApp",
[this._brandShortName]);
// For other types, handleInternally looks like either useHelperApp
@ -1162,10 +1215,11 @@ var gApplicationsPane = {
// in the first place?
case Ci.nsIHandlerInfo.useSystemDefault:
return aHandlerInfo.defaultDescription;
return this._prefsBundle.getFormattedString("useDefault",
[aHandlerInfo.defaultDescription]);
case kActionUsePlugin:
return this._prefsBundle.getFormattedString("pluginName",
return this._prefsBundle.getFormattedString("usePluginIn",
[aHandlerInfo.plugin.name,
this._brandShortName]);
}
@ -1247,7 +1301,7 @@ var gApplicationsPane = {
menuPopup.removeChild(menuPopup.lastChild);
{
var askMenuItem = document.createElementNS(kXULNS, "menuitem");
var askMenuItem = document.createElement("menuitem");
askMenuItem.setAttribute("alwaysAsk", "true");
let label;
if (handlerInfo.type == TYPE_MAYBE_FEED)
@ -1261,28 +1315,45 @@ var gApplicationsPane = {
menuPopup.appendChild(askMenuItem);
}
// Create a menu item for saving to disk.
// Note: this option isn't available to protocol types, since we don't know
// what it means to save a URL having a certain scheme to disk, nor is it
// available to feeds, since the feed code doesn't implement the capability.
if ((handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo) &&
handlerInfo.type != TYPE_MAYBE_FEED) {
var saveMenuItem = document.createElement("menuitem");
saveMenuItem.setAttribute("action", Ci.nsIHandlerInfo.saveToDisk);
let label = this._prefsBundle.getString("saveFile");
saveMenuItem.setAttribute("label", label);
saveMenuItem.setAttribute("tooltiptext", label);
saveMenuItem.setAttribute(APP_ICON_ATTR_NAME, "save");
menuPopup.appendChild(saveMenuItem);
}
// If this is the feed type, add a Live Bookmarks item.
if (handlerInfo.type == TYPE_MAYBE_FEED) {
var internalMenuItem = document.createElementNS(kXULNS, "menuitem");
var internalMenuItem = document.createElement("menuitem");
internalMenuItem.setAttribute("action", Ci.nsIHandlerInfo.handleInternally);
let label = this._prefsBundle.getFormattedString("liveBookmarksInApp",
let label = this._prefsBundle.getFormattedString("addLiveBookmarksInApp",
[this._brandShortName]);
internalMenuItem.setAttribute("label", label);
internalMenuItem.setAttribute("tooltiptext", label);
internalMenuItem.setAttribute(APP_ICON_ATTR_NAME, "feed");
menuPopup.appendChild(internalMenuItem);
// Add a separator to distinguish these items from the helper app items
// that follow them.
let menuItem = document.createElementNS(kXULNS, "menuseparator");
menuPopup.appendChild(menuItem);
}
// Add a separator to distinguish these items from the helper app items
// that follow them.
let menuItem = document.createElement("menuseparator");
menuPopup.appendChild(menuItem);
// Create a menu item for the OS default application, if any.
if (handlerInfo.hasDefaultHandler) {
var defaultMenuItem = document.createElementNS(kXULNS, "menuitem");
var defaultMenuItem = document.createElement("menuitem");
defaultMenuItem.setAttribute("action", Ci.nsIHandlerInfo.useSystemDefault);
defaultMenuItem.setAttribute("label", handlerInfo.defaultDescription);
let label = this._prefsBundle.getFormattedString("useDefault",
[handlerInfo.defaultDescription]);
defaultMenuItem.setAttribute("label", label);
defaultMenuItem.setAttribute("tooltiptext", handlerInfo.defaultDescription);
defaultMenuItem.setAttribute("image", this._getIconURLForSystemDefault(handlerInfo));
@ -1298,13 +1369,14 @@ var gApplicationsPane = {
if (!this.isValidHandlerApp(possibleApp))
continue;
let menuItem = document.createElementNS(kXULNS, "menuitem");
let menuItem = document.createElement("menuitem");
menuItem.setAttribute("action", Ci.nsIHandlerInfo.useHelperApp);
let label;
if (possibleApp instanceof Ci.nsILocalHandlerApp)
label = getDisplayNameForFile(possibleApp.executable);
else
label = possibleApp.name;
label = this._prefsBundle.getFormattedString("useApp", [label]);
menuItem.setAttribute("label", label);
menuItem.setAttribute("tooltiptext", label);
menuItem.setAttribute("image", this._getIconURLForHandlerApp(possibleApp));
@ -1319,9 +1391,9 @@ var gApplicationsPane = {
// Create a menu item for the plugin.
if (handlerInfo.plugin) {
var pluginMenuItem = document.createElementNS(kXULNS, "menuitem");
var pluginMenuItem = document.createElement("menuitem");
pluginMenuItem.setAttribute("action", kActionUsePlugin);
let label = this._prefsBundle.getFormattedString("pluginName",
let label = this._prefsBundle.getFormattedString("usePluginIn",
[handlerInfo.plugin.name,
this._brandShortName]);
pluginMenuItem.setAttribute("label", label);
@ -1339,27 +1411,22 @@ var gApplicationsPane = {
if (handlerInfo.type != executableType)
#endif
{
let menuItem = document.createElementNS(kXULNS, "menuitem");
let menuItem = document.createElement("menuitem");
menuItem.setAttribute("oncommand", "gApplicationsPane.chooseApp(event)");
let label = this._prefsBundle.getString("chooseApp");
let label = this._prefsBundle.getString("useOtherApp");
menuItem.setAttribute("label", label);
menuItem.setAttribute("tooltiptext", label);
menuPopup.appendChild(menuItem);
}
// Create a menu item for saving to disk.
// Note: this option isn't available to protocol types, since we don't know
// what it means to save a URL having a certain scheme to disk, nor is it
// available to feeds, since the feed code doesn't implement the capability.
if ((handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo) &&
handlerInfo.type != TYPE_MAYBE_FEED) {
var saveMenuItem = document.createElementNS(kXULNS, "menuitem");
saveMenuItem.setAttribute("action", Ci.nsIHandlerInfo.saveToDisk);
let label = this._prefsBundle.getString("saveFile");
saveMenuItem.setAttribute("label", label);
saveMenuItem.setAttribute("tooltiptext", label);
saveMenuItem.setAttribute(APP_ICON_ATTR_NAME, "save");
menuPopup.appendChild(saveMenuItem);
// Create a menu item for managing applications.
if (possibleAppMenuItems.length) {
let menuItem = document.createElement("menuseparator");
menuPopup.appendChild(menuItem);
menuItem = document.createElement("menuitem");
menuItem.setAttribute("oncommand", "gApplicationsPane.manageApp(event)");
menuItem.setAttribute("label", this._prefsBundle.getString("manageApp"));
menuPopup.appendChild(menuItem);
}
// Select the item corresponding to the preferred action. If the always
@ -1553,6 +1620,28 @@ var gApplicationsPane = {
}
},
manageApp: function(aEvent) {
// Don't let the normal "on select action" handler get this event,
// as we handle it specially ourselves.
aEvent.stopPropagation();
var typeItem = this._list.selectedItem;
var handlerInfo = this._handledTypes[typeItem.type];
document.documentElement.openSubDialog("chrome://browser/content/preferences/applicationManager.xul",
"", handlerInfo);
// Rebuild the actions menu so that we revert to the previous selection,
// or "Always ask" if the previous default application has been removed
this.rebuildActionsMenu();
// update the richlistitem too. Will be visible when selecting another row
typeItem.setAttribute("actionDescription",
this._describePreferredAction(handlerInfo));
typeItem.setAttribute("actionIcon",
this._getIconURLForPreferredAction(handlerInfo));
},
chooseApp: function(aEvent) {
// Don't let the normal "on select action" handler get this event,
// as we handle it specially ourselves.

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

@ -4,6 +4,8 @@ browser.jar:
* content/browser/preferences/advanced-scripts.xul
* content/browser/preferences/applications.xul
* content/browser/preferences/applications.js
* content/browser/preferences/applicationManager.xul
* content/browser/preferences/applicationManager.js
* content/browser/preferences/colors.xul
* content/browser/preferences/cookies.xul
* content/browser/preferences/cookies.js

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

@ -0,0 +1,4 @@
<!ENTITY appManager.title "Application details">
<!ENTITY appManager.style "width: 30em; min-height: 20em;">
<!ENTITY remove.label "Remove">
<!ENTITY remove.accesskey "R">

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

@ -0,0 +1,10 @@
# LOCALIZATION NOTE
# in descriptionApplications, %S will be replaced by one of the 3 following strings
descriptionApplications=The following applications can be used to handle %S.
handleProtocol=%S links
handleWebFeeds=Web Feeds
handleFile=%S content
descriptionWebApp=This web application is hosted at:
descriptionLocalApp=This application is located at:

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

@ -46,6 +46,8 @@
locale/browser/migration/migration.properties (%chrome/browser/migration/migration.properties)
locale/browser/preferences/advanced.dtd (%chrome/browser/preferences/advanced.dtd)
* locale/browser/preferences/advanced-scripts.dtd (%chrome/browser/preferences/advanced-scripts.dtd)
locale/browser/preferences/applicationManager.dtd (%chrome/browser/preferences/applicationManager.dtd)
locale/browser/preferences/applicationManager.properties (%chrome/browser/preferences/applicationManager.properties)
locale/browser/preferences/colors.dtd (%chrome/browser/preferences/colors.dtd)
locale/browser/preferences/cookies.dtd (%chrome/browser/preferences/cookies.dtd)
locale/browser/preferences/content.dtd (%chrome/browser/preferences/content.dtd)