bug 395182: also display the MIME types for types with identical descriptions in the Applications prefpane; r=gavin

This commit is contained in:
myk%mozilla.org 2007-10-09 19:16:00 +00:00
Родитель 6333deb41a
Коммит dce9dc2693
2 изменённых файлов: 120 добавлений и 68 удалений

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

@ -668,12 +668,6 @@ var feedHandlerInfo = {
},
//**************************************************************************//
// Plugin Handling
handledOnlyByPlugin: false,
//**************************************************************************//
// Storage
@ -706,6 +700,21 @@ var gApplicationsPane = {
// The set of types the app knows how to handle. A hash of HandlerInfoWrapper
// objects, indexed by type.
_handledTypes: {},
// The list of types we can show, sorted by the sort column/direction.
// An array of HandlerInfoWrapper objects. We build this list when we first
// load the data and then rebuild it when users change a pref that affects
// what types we can show or change the sort column/direction.
// Note: this isn't necessarily the list of types we *will* show; if the user
// provides a filter string, we'll only show the subset of types in this list
// that match that string.
_visibleTypes: [],
// A count of the number of times each visible type description appears.
// We use these counts to determine whether or not to annotate descriptions
// with their types to distinguish duplicate descriptions from each other.
// A hash of integer counts, indexed by string description.
_visibleTypeDescriptionCount: {},
//**************************************************************************//
@ -760,7 +769,7 @@ var gApplicationsPane = {
window.addEventListener("unload", this, false);
// Figure out how we should be sorting the list. We persist sort settings
// across sessions, so we can't assume the default sort column and direction.
// across sessions, so we can't assume the default sort column/direction.
// XXX should we be using the XUL sort service instead?
if (document.getElementById("typeColumn").hasAttribute("sortDirection"))
this._sortColumn = document.getElementById("typeColumn");
@ -776,7 +785,9 @@ var gApplicationsPane = {
// XXX Shouldn't we perhaps just set a max-height on the richlistbox?
var _delayedPaneLoad = function(self) {
self._loadData();
self.rebuildView();
self._rebuildVisibleTypes();
self._sortVisibleTypes();
self._rebuildView();
}
setTimeout(_delayedPaneLoad, 0, this);
},
@ -811,8 +822,19 @@ var gApplicationsPane = {
observe: function (aSubject, aTopic, aData) {
// Rebuild the list when there are changes to preferences that influence
// whether or not to show certain entries in the list.
if (aTopic == "nsPref:changed")
this.rebuildView();
if (aTopic == "nsPref:changed") {
// These two prefs alter the list of visible types, so we have to rebuild
// that list when they change.
if (aData == PREF_SHOW_PLUGINS_IN_LIST ||
aData == PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS) {
this._rebuildVisibleTypes();
this._sortVisibleTypes();
}
// All the prefs we observe can affect what we display, so we rebuild
// the view when any of them changes.
this._rebuildView();
}
},
@ -837,6 +859,7 @@ var gApplicationsPane = {
_loadFeedHandler: function() {
this._handledTypes[TYPE_MAYBE_FEED] = feedHandlerInfo;
feedHandlerInfo.handledOnlyByPlugin = false;
},
/**
@ -864,19 +887,19 @@ var gApplicationsPane = {
let plugin = navigator.plugins[i];
for (let j = 0; j < plugin.length; ++j) {
let type = plugin[j].type;
let handlerInfoWrapper;
if (typeof this._handledTypes[type] == "undefined") {
let handlerInfoWrapper;
if (type in this._handledTypes)
handlerInfoWrapper = this._handledTypes[type];
else {
let wrappedHandlerInfo =
this._mimeSvc.getFromTypeAndExtension(type, null);
handlerInfoWrapper = new HandlerInfoWrapper(type, wrappedHandlerInfo);
handlerInfoWrapper.handledOnlyByPlugin = true;
this._handledTypes[type] = handlerInfoWrapper;
}
else
handlerInfoWrapper = this._handledTypes[type];
handlerInfoWrapper.plugin = plugin;
handlerInfoWrapper.handledOnlyByPlugin = true;
}
}
},
@ -887,17 +910,17 @@ var gApplicationsPane = {
_loadApplicationHandlers: function() {
var wrappedHandlerInfos = this._handlerSvc.enumerate();
while (wrappedHandlerInfos.hasMoreElements()) {
let wrappedHandlerInfo = wrappedHandlerInfos.getNext().
QueryInterface(Ci.nsIHandlerInfo);
let wrappedHandlerInfo =
wrappedHandlerInfos.getNext().QueryInterface(Ci.nsIHandlerInfo);
let type = wrappedHandlerInfo.type;
let handlerInfoWrapper;
if (typeof this._handledTypes[type] == "undefined") {
let handlerInfoWrapper;
if (type in this._handledTypes)
handlerInfoWrapper = this._handledTypes[type];
else {
handlerInfoWrapper = new HandlerInfoWrapper(type, wrappedHandlerInfo);
this._handledTypes[type] = handlerInfoWrapper;
}
else
handlerInfoWrapper = this._handledTypes[type];
handlerInfoWrapper.handledOnlyByPlugin = false;
}
@ -907,35 +930,12 @@ var gApplicationsPane = {
//**************************************************************************//
// View Construction
rebuildView: function() {
// Clear the list of entries.
while (this._list.childNodes.length > 1)
this._list.removeChild(this._list.lastChild);
var visibleTypes = this._getVisibleTypes();
if (this._sortColumn)
this._sortTypes(visibleTypes);
for each (let visibleType in visibleTypes) {
let item = document.createElement("richlistitem");
item.setAttribute("type", visibleType.type);
item.setAttribute("typeDescription", visibleType.description);
if (visibleType.smallIcon)
item.setAttribute("typeIcon", visibleType.smallIcon);
item.setAttribute("actionDescription",
this._describePreferredAction(visibleType));
item.setAttribute("actionIcon",
this._getIconURLForPreferredAction(visibleType));
this._list.appendChild(item);
}
this._selectLastSelectedType();
},
_getVisibleTypes: function() {
var visibleTypes = [];
_rebuildVisibleTypes: function() {
// Reset the list of visible types and the visible type description counts.
this._visibleTypes = [];
this._visibleTypeDescriptionCount = {};
// Get the preferences that help determine what types to show.
var showPlugins = this._prefSvc.getBoolPref(PREF_SHOW_PLUGINS_IN_LIST);
var hideTypesWithoutExtensions =
this._prefSvc.getBoolPref(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS);
@ -958,23 +958,68 @@ var gApplicationsPane = {
if (handlerInfo.handledOnlyByPlugin && !showPlugins)
continue;
// If the user is filtering the list, then only show matching types.
if (this._filter.value && !this._matchesFilter(handlerInfo))
continue;
// We couldn't find any reason to exclude the type, so include it.
visibleTypes.push(handlerInfo);
this._visibleTypes.push(handlerInfo);
if (handlerInfo.description in this._visibleTypeDescriptionCount)
this._visibleTypeDescriptionCount[handlerInfo.description]++;
else
this._visibleTypeDescriptionCount[handlerInfo.description] = 1;
}
},
_rebuildView: function() {
// Clear the list of entries.
while (this._list.childNodes.length > 1)
this._list.removeChild(this._list.lastChild);
var visibleTypes = this._visibleTypes;
// If the user is filtering the list, then only show matching types.
if (this._filter.value)
visibleTypes = visibleTypes.filter(this._matchesFilter, this);
for each (let visibleType in visibleTypes) {
let item = document.createElement("richlistitem");
item.setAttribute("type", visibleType.type);
item.setAttribute("typeDescription", this._describeType(visibleType));
if (visibleType.smallIcon)
item.setAttribute("typeIcon", visibleType.smallIcon);
item.setAttribute("actionDescription",
this._describePreferredAction(visibleType));
item.setAttribute("actionIcon",
this._getIconURLForPreferredAction(visibleType));
this._list.appendChild(item);
}
return visibleTypes;
this._selectLastSelectedType();
},
_matchesFilter: function(aType) {
var filterValue = this._filter.value.toLowerCase();
return aType.description.toLowerCase().indexOf(filterValue) != -1 ||
return this._describeType(aType).toLowerCase().indexOf(filterValue) != -1 ||
this._describePreferredAction(aType).toLowerCase().indexOf(filterValue) != -1;
},
/**
* Describe, in a human-readable fashion, the type represented by the given
* handler info object. Normally this is just the description provided by
* the info object, but if more than one object presents the same description,
* then we annotate the duplicate descriptions with the type itself to help
* users distinguish between those types.
*
* @param aHandlerInfo {nsIHandlerInfo} the type being described
* @returns {string} a description of the type
*/
_describeType: function(aHandlerInfo) {
if (this._visibleTypeDescriptionCount[aHandlerInfo.description] > 1)
return this._prefsBundle.getFormattedString("typeDescriptionWithType",
[aHandlerInfo.description,
aHandlerInfo.type]);
return aHandlerInfo.description;
},
/**
* Describe, in a human-readable fashion, the preferred action to take on
* the type represented by the given handler info object.
@ -985,6 +1030,7 @@ var gApplicationsPane = {
*
* @param aHandlerInfo {nsIHandlerInfo} the type whose preferred action
* is being described
* @returns {string} a description of the action
*/
_describePreferredAction: function(aHandlerInfo) {
// alwaysAskBeforeHandling overrides the preferred action, so if that flag
@ -1248,23 +1294,24 @@ var gApplicationsPane = {
else
column.setAttribute("sortDirection", "ascending");
this.rebuildView();
this._sortVisibleTypes();
this._rebuildView();
},
/**
* Given an array of HandlerInfoWrapper objects, sort them according to
* the current sort order. Used by rebuildView to sort the set of visible
* types before building the list from them.
* Sort the list of visible types by the current sort column/direction.
*/
_sortTypes: function(aTypes) {
_sortVisibleTypes: function() {
if (!this._sortColumn)
return;
var t = this;
function sortByType(a, b) {
return a.description.toLowerCase().localeCompare(b.description.toLowerCase());
return t._describeType(a).toLowerCase().
localeCompare(t._describeType(b).toLowerCase());
}
var t = this;
function sortByAction(a, b) {
return t._describePreferredAction(a).toLowerCase().
localeCompare(t._describePreferredAction(b).toLowerCase());
@ -1272,15 +1319,15 @@ var gApplicationsPane = {
switch (this._sortColumn.getAttribute("value")) {
case "type":
aTypes.sort(sortByType);
this._visibleTypes.sort(sortByType);
break;
case "action":
aTypes.sort(sortByAction);
this._visibleTypes.sort(sortByAction);
break;
}
if (this._sortColumn.getAttribute("sortDirection") == "descending")
aTypes.reverse();
this._visibleTypes.reverse();
},
/**
@ -1292,7 +1339,7 @@ var gApplicationsPane = {
return;
}
this.rebuildView();
this._rebuildView();
document.getElementById("clearFilter").disabled = false;
},
@ -1313,7 +1360,7 @@ var gApplicationsPane = {
clearFilter: function() {
this._filter.value = "";
this.rebuildView();
this._rebuildView();
this._filter.focus();
document.getElementById("clearFilter").disabled = true;

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

@ -61,6 +61,11 @@ pluginName=%S (in %S)
previewInApp=Preview in %S
liveBookmarksInApp=Live Bookmarks in %S
# LOCALIZATION NOTE (typeDescriptionWithType):
# %1$S = type description (for example "Portable Document Format")
# %2$S = type (for example "application/pdf")
typeDescriptionWithType=%S (%S)
#### Cookie Viewer