Bug 941321 - try-finally all of Australis' begin/endBatchUpdate calls, r=mconley

--HG--
extra : rebase_source : 06102ada89853f201baacbca37dc9ced1243acca
This commit is contained in:
Gijs Kruitbosch 2013-11-28 20:04:51 +01:00
Родитель 225944ff63
Коммит 6a64c70da7
4 изменённых файлов: 227 добавлений и 200 удалений

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

@ -220,8 +220,11 @@ const PanelUI = {
CustomizableUI.registerMenuPanel(this.contents);
} else {
this.beginBatchUpdate();
CustomizableUI.registerMenuPanel(this.contents);
this.endBatchUpdate();
try {
CustomizableUI.registerMenuPanel(this.contents);
} finally {
this.endBatchUpdate();
}
}
this.panel.hidden = false;
}.bind(this)).then(null, Cu.reportError);

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

@ -193,29 +193,32 @@
// Get a list of items only in the new list
let newIds = [id for (id of newVal) if (oldIds.indexOf(id) == -1)];
CustomizableUI.beginBatchUpdate();
for (let newId of newIds) {
oldIds = CustomizableUI.getWidgetIdsInArea(this.id);
let nextId = newId;
let pos;
do {
// Get the next item
nextId = newVal[newVal.indexOf(nextId) + 1];
// Figure out where it is in the old list
pos = oldIds.indexOf(nextId);
// If it's not in the old list, repeat:
} while (pos == -1 && nextId);
if (pos == -1) {
pos = null; // We didn't find anything, insert at the end
try {
for (let newId of newIds) {
oldIds = CustomizableUI.getWidgetIdsInArea(this.id);
let nextId = newId;
let pos;
do {
// Get the next item
nextId = newVal[newVal.indexOf(nextId) + 1];
// Figure out where it is in the old list
pos = oldIds.indexOf(nextId);
// If it's not in the old list, repeat:
} while (pos == -1 && nextId);
if (pos == -1) {
pos = null; // We didn't find anything, insert at the end
}
CustomizableUI.addWidgetToArea(newId, this.id, pos);
}
CustomizableUI.addWidgetToArea(newId, this.id, pos);
}
let currentIds = this.currentSet.split(',');
let removedIds = [id for (id of currentIds) if (newIds.indexOf(id) == -1 && newVal.indexOf(id) == -1)];
for (let removedId of removedIds) {
CustomizableUI.removeWidgetFromArea(removedId);
let currentIds = this.currentSet.split(',');
let removedIds = [id for (id of currentIds) if (newIds.indexOf(id) == -1 && newVal.indexOf(id) == -1)];
for (let removedId of removedIds) {
CustomizableUI.removeWidgetFromArea(removedId);
}
} finally {
CustomizableUI.endBatchUpdate();
}
CustomizableUI.endBatchUpdate();
]]></setter>
</property>

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

@ -279,15 +279,18 @@ let CustomizableUIInternal = {
// Move all the widgets out
this.beginBatchUpdate();
let placements = gPlacements.get(aName);
placements.forEach(this.removeWidgetFromArea, this);
try {
let placements = gPlacements.get(aName);
placements.forEach(this.removeWidgetFromArea, this);
// Delete all remaining traces.
gAreas.delete(aName);
gPlacements.delete(aName);
gFuturePlacements.delete(aName);
gBuildAreas.delete(aName);
this.endBatchUpdate(true);
// Delete all remaining traces.
gAreas.delete(aName);
gPlacements.delete(aName);
gFuturePlacements.delete(aName);
gBuildAreas.delete(aName);
} finally {
this.endBatchUpdate(true);
}
},
registerToolbarNode: function(aToolbar, aExistingChildren) {
@ -303,44 +306,47 @@ let CustomizableUIInternal = {
}
this.beginBatchUpdate();
let placements = gPlacements.get(area);
if (!placements && areaProperties.has("legacy")) {
let legacyState = aToolbar.getAttribute("currentset");
if (legacyState) {
legacyState = legacyState.split(",").filter(s => s);
try {
let placements = gPlacements.get(area);
if (!placements && areaProperties.has("legacy")) {
let legacyState = aToolbar.getAttribute("currentset");
if (legacyState) {
legacyState = legacyState.split(",").filter(s => s);
}
// Manually restore the state here, so the legacy state can be converted.
this.restoreStateForArea(area, legacyState);
placements = gPlacements.get(area);
}
// Manually restore the state here, so the legacy state can be converted.
this.restoreStateForArea(area, legacyState);
placements = gPlacements.get(area);
}
// Check that the current children and the current placements match. If
// not, mark it as dirty:
if (aExistingChildren.length != placements.length ||
aExistingChildren.every((id, i) => id == placements[i])) {
gDirtyAreaCache.add(area);
}
// Check that the current children and the current placements match. If
// not, mark it as dirty:
if (aExistingChildren.length != placements.length ||
aExistingChildren.every((id, i) => id == placements[i])) {
gDirtyAreaCache.add(area);
}
if (areaProperties.has("overflowable")) {
aToolbar.overflowable = new OverflowableToolbar(aToolbar);
}
if (areaProperties.has("overflowable")) {
aToolbar.overflowable = new OverflowableToolbar(aToolbar);
}
this.registerBuildArea(area, aToolbar);
this.registerBuildArea(area, aToolbar);
// We only build the toolbar if it's been marked as "dirty". Dirty means
// one of the following things:
// 1) Items have been added, moved or removed from this toolbar before.
// 2) The number of children of the toolbar does not match the length of
// the placements array for that area.
//
// This notion of being "dirty" is stored in a cache which is persisted
// in the saved state.
if (gDirtyAreaCache.has(area)) {
this.buildArea(area, placements, aToolbar);
// We only build the toolbar if it's been marked as "dirty". Dirty means
// one of the following things:
// 1) Items have been added, moved or removed from this toolbar before.
// 2) The number of children of the toolbar does not match the length of
// the placements array for that area.
//
// This notion of being "dirty" is stored in a cache which is persisted
// in the saved state.
if (gDirtyAreaCache.has(area)) {
this.buildArea(area, placements, aToolbar);
}
aToolbar.setAttribute("currentset", placements.join(","));
} finally {
this.endBatchUpdate();
}
aToolbar.setAttribute("currentset", placements.join(","));
this.endBatchUpdate();
},
buildArea: function(aArea, aPlacements, aAreaNode) {
@ -354,110 +360,112 @@ let CustomizableUIInternal = {
+ " to have a customizationTarget attribute.");
}
this.beginBatchUpdate();
// Restore nav-bar visibility since it may have been hidden
// through a migration path (bug 938980) or an add-on.
if (aArea == CustomizableUI.AREA_NAVBAR) {
aAreaNode.collapsed = false;
}
let currentNode = container.firstChild;
let placementsToRemove = new Set();
for (let id of aPlacements) {
while (currentNode && currentNode.getAttribute("skipintoolbarset") == "true") {
currentNode = currentNode.nextSibling;
}
this.beginBatchUpdate();
if (currentNode && currentNode.id == id) {
currentNode = currentNode.nextSibling;
continue;
}
try {
let currentNode = container.firstChild;
let placementsToRemove = new Set();
for (let id of aPlacements) {
while (currentNode && currentNode.getAttribute("skipintoolbarset") == "true") {
currentNode = currentNode.nextSibling;
}
let [provider, node] = this.getWidgetNode(id, window);
if (!node) {
LOG("Unknown widget: " + id);
continue;
}
// If the placements have items in them which are (now) no longer removable,
// we shouldn't be moving them:
if (node.parentNode != container && !this.isWidgetRemovable(node)) {
placementsToRemove.add(id);
continue;
}
if (inPrivateWindow && provider == CustomizableUI.PROVIDER_API) {
let widget = gPalette.get(id);
if (!widget.showInPrivateBrowsing && inPrivateWindow) {
if (currentNode && currentNode.id == id) {
currentNode = currentNode.nextSibling;
continue;
}
}
this.ensureButtonContextMenu(node, aAreaNode);
if (node.localName == "toolbarbutton" && aArea == CustomizableUI.AREA_PANEL) {
node.setAttribute("tabindex", "0");
if (!node.hasAttribute("type")) {
node.setAttribute("type", "wrap");
let [provider, node] = this.getWidgetNode(id, window);
if (!node) {
LOG("Unknown widget: " + id);
continue;
}
}
this.insertWidgetBefore(node, currentNode, container, aArea);
if (gResetting) {
this.notifyListeners("onWidgetReset", id, aArea);
}
}
// If the placements have items in them which are (now) no longer removable,
// we shouldn't be moving them:
if (node.parentNode != container && !this.isWidgetRemovable(node)) {
placementsToRemove.add(id);
continue;
}
if (currentNode) {
let palette = aAreaNode.toolbox ? aAreaNode.toolbox.palette : null;
let limit = currentNode.previousSibling;
let node = container.lastChild;
while (node && node != limit) {
let previousSibling = node.previousSibling;
// Nodes opt-in to removability. If they're removable, and we haven't
// seen them in the placements array, then we toss them into the palette
// if one exists. If no palette exists, we just remove the node. If the
// node is not removable, we leave it where it is. However, we can only
// safely touch elements that have an ID - both because we depend on
// IDs, and because such elements are not intended to be widgets
// (eg, titlebar-placeholder elements).
if (node.id && node.getAttribute("skipintoolbarset") != "true") {
if (this.isWidgetRemovable(node)) {
if (palette && !this.isSpecialWidget(node.id)) {
palette.appendChild(node);
this.removeLocationAttributes(node);
} else {
container.removeChild(node);
}
} else {
this.setLocationAttributes(currentNode, aArea);
node.setAttribute("removable", false);
LOG("Adding non-removable widget to placements of " + aArea + ": " +
node.id);
gPlacements.get(aArea).push(node.id);
gDirty = true;
if (inPrivateWindow && provider == CustomizableUI.PROVIDER_API) {
let widget = gPalette.get(id);
if (!widget.showInPrivateBrowsing && inPrivateWindow) {
continue;
}
}
node = previousSibling;
this.ensureButtonContextMenu(node, aAreaNode);
if (node.localName == "toolbarbutton" && aArea == CustomizableUI.AREA_PANEL) {
node.setAttribute("tabindex", "0");
if (!node.hasAttribute("type")) {
node.setAttribute("type", "wrap");
}
}
this.insertWidgetBefore(node, currentNode, container, aArea);
if (gResetting) {
this.notifyListeners("onWidgetReset", id, aArea);
}
}
}
// If there are placements in here which aren't removable from their original area,
// we remove them from this area's placement array. They will (have) be(en) added
// to their original area's placements array in the block above this one.
if (placementsToRemove.size) {
let placementAry = gPlacements.get(aArea);
for (let id of placementsToRemove) {
let index = placementAry.indexOf(id);
placementAry.splice(index, 1);
if (currentNode) {
let palette = aAreaNode.toolbox ? aAreaNode.toolbox.palette : null;
let limit = currentNode.previousSibling;
let node = container.lastChild;
while (node && node != limit) {
let previousSibling = node.previousSibling;
// Nodes opt-in to removability. If they're removable, and we haven't
// seen them in the placements array, then we toss them into the palette
// if one exists. If no palette exists, we just remove the node. If the
// node is not removable, we leave it where it is. However, we can only
// safely touch elements that have an ID - both because we depend on
// IDs, and because such elements are not intended to be widgets
// (eg, titlebar-placeholder elements).
if (node.id && node.getAttribute("skipintoolbarset") != "true") {
if (this.isWidgetRemovable(node)) {
if (palette && !this.isSpecialWidget(node.id)) {
palette.appendChild(node);
this.removeLocationAttributes(node);
} else {
container.removeChild(node);
}
} else {
this.setLocationAttributes(currentNode, aArea);
node.setAttribute("removable", false);
LOG("Adding non-removable widget to placements of " + aArea + ": " +
node.id);
gPlacements.get(aArea).push(node.id);
gDirty = true;
}
}
node = previousSibling;
}
}
}
if (gResetting) {
this.notifyListeners("onAreaReset", aArea);
}
// If there are placements in here which aren't removable from their original area,
// we remove them from this area's placement array. They will (have) be(en) added
// to their original area's placements array in the block above this one.
if (placementsToRemove.size) {
let placementAry = gPlacements.get(aArea);
for (let id of placementsToRemove) {
let index = placementAry.indexOf(id);
placementAry.splice(index, 1);
}
}
this.endBatchUpdate();
if (gResetting) {
this.notifyListeners("onAreaReset", aArea);
}
} finally {
this.endBatchUpdate();
}
},
addPanelCloseListeners: function(aPanel) {
@ -1382,51 +1390,54 @@ let CustomizableUIInternal = {
}
this.beginBatchUpdate();
gRestoring = true;
try {
gRestoring = true;
let restored = false;
gPlacements.set(aArea, []);
let restored = false;
gPlacements.set(aArea, []);
if (gSavedState && aArea in gSavedState.placements) {
LOG("Restoring " + aArea + " from saved state");
let placements = gSavedState.placements[aArea];
for (let id of placements)
this.addWidgetToArea(id, aArea);
gDirty = false;
restored = true;
}
if (!restored && aLegacyState) {
LOG("Restoring " + aArea + " from legacy state");
for (let id of aLegacyState)
this.addWidgetToArea(id, aArea);
// Don't override dirty state, to ensure legacy state is saved here and
// therefore only used once.
restored = true;
}
if (!restored) {
LOG("Restoring " + aArea + " from default state");
let defaults = gAreas.get(aArea).get("defaultPlacements");
if (defaults) {
for (let id of defaults)
this.addWidgetToArea(id, aArea, null, true);
if (gSavedState && aArea in gSavedState.placements) {
LOG("Restoring " + aArea + " from saved state");
let placements = gSavedState.placements[aArea];
for (let id of placements)
this.addWidgetToArea(id, aArea);
gDirty = false;
restored = true;
}
gDirty = false;
if (!restored && aLegacyState) {
LOG("Restoring " + aArea + " from legacy state");
for (let id of aLegacyState)
this.addWidgetToArea(id, aArea);
// Don't override dirty state, to ensure legacy state is saved here and
// therefore only used once.
restored = true;
}
if (!restored) {
LOG("Restoring " + aArea + " from default state");
let defaults = gAreas.get(aArea).get("defaultPlacements");
if (defaults) {
for (let id of defaults)
this.addWidgetToArea(id, aArea, null, true);
}
gDirty = false;
}
// Finally, add widgets to the area that were added before the it was able
// to be restored. This can occur when add-ons register widgets for a
// lazily-restored area before it's been restored.
if (gFuturePlacements.has(aArea)) {
for (let id of gFuturePlacements.get(aArea))
this.addWidgetToArea(id, aArea);
}
LOG("Placements for " + aArea + ":\n\t" + gPlacements.get(aArea).join("\n\t"));
gRestoring = false;
} finally {
this.endBatchUpdate();
}
// Finally, add widgets to the area that were added before the it was able
// to be restored. This can occur when add-ons register widgets for a
// lazily-restored area before it's been restored.
if (gFuturePlacements.has(aArea)) {
for (let id of gFuturePlacements.get(aArea))
this.addWidgetToArea(id, aArea);
}
LOG("Placements for " + aArea + ":\n\t" + gPlacements.get(aArea).join("\n\t"));
gRestoring = false;
this.endBatchUpdate();
},
saveState: function() {
@ -1581,17 +1592,19 @@ let CustomizableUIInternal = {
// seen before, then add it to its default area so it can be used.
if (autoAdd && !widget.currentArea && !gSeenWidgets.has(widget.id)) {
this.beginBatchUpdate();
gSeenWidgets.add(widget.id);
try {
gSeenWidgets.add(widget.id);
if (widget.defaultArea) {
if (this.isAreaLazy(widget.defaultArea)) {
gFuturePlacements.get(widget.defaultArea).add(widget.id);
} else {
this.addWidgetToArea(widget.id, widget.defaultArea);
if (widget.defaultArea) {
if (this.isAreaLazy(widget.defaultArea)) {
gFuturePlacements.get(widget.defaultArea).add(widget.id);
} else {
this.addWidgetToArea(widget.id, widget.defaultArea);
}
}
} finally {
this.endBatchUpdate(true);
}
this.endBatchUpdate(true);
}
}

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

@ -93,6 +93,9 @@ CustomizeMode.prototype = {
return;
}
let window = this.window;
let document = this.document;
Task.spawn(function() {
// We shouldn't start customize mode until after browser-delayed-startup has finished:
if (!this.window.gBrowserInit.delayedStartupFinished) {
@ -115,9 +118,6 @@ CustomizeMode.prototype = {
this.dispatchToolboxEvent("beforecustomization");
CustomizableUI.notifyStartCustomizing(this.window);
let window = this.window;
let document = this.document;
// Add a keypress listener to the document so that we can quickly exit
// customization mode when pressing ESC.
document.addEventListener("keypress", this);
@ -159,7 +159,6 @@ CustomizeMode.prototype = {
}
this._showPanelCustomizationPlaceholders();
CustomizableUI.addListener(this);
yield this._wrapToolbarItems();
yield this.populatePalette();
@ -184,11 +183,16 @@ CustomizeMode.prototype = {
for (let toolbar of customizableToolbars)
toolbar.setAttribute("customizing", true);
CustomizableUI.addListener(this);
window.PanelUI.endBatchUpdate();
this._customizing = true;
this._transitioning = false;
this.dispatchToolboxEvent("customizationready");
}.bind(this)).then(null, ERROR);
}.bind(this)).then(null, function(e) {
ERROR(e);
// We should ensure this has been called, and calling it again doesn't hurt:
window.PanelUI.endBatchUpdate();
});
},
exit: function() {
@ -298,7 +302,11 @@ CustomizeMode.prototype = {
this._transitioning = false;
this.dispatchToolboxEvent("aftercustomization");
CustomizableUI.notifyEndCustomizing(this.window);
}.bind(this)).then(null, ERROR);
}.bind(this)).then(null, function(e) {
ERROR(e);
// We should ensure this has been called, and calling it again doesn't hurt:
window.PanelUI.endBatchUpdate();
});
},
/**