Bug 498130 - Reduce places-views overhead (RELAND)

This commit is contained in:
Dietrich Ayala 2009-10-01 09:53:26 -07:00
parent 1594b20ae9
commit 8f8c161f85
38 changed files with 1541 additions and 1620 deletions

View File

@ -1196,21 +1196,22 @@ var PlacesStarButton = {
this._batching = false;
},
onItemAdded: function PSB_onItemAdded(aItemId, aFolder, aIndex) {
onItemAdded: function PSB_onItemAdded(aItemId, aFolder, aIndex, aItemType) {
if (!this._batching && !this._starred)
this.updateState();
},
onBeforeItemRemoved: function PSB_onBeforeItemRemoved(aItemId) {
},
onBeforeItemRemoved: function() {},
onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex) {
onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex,
aItemType) {
if (!this._batching)
this.updateState();
},
onItemChanged: function PSB_onItemChanged(aItemId, aProperty,
aIsAnnotationProperty, aValue) {
aIsAnnotationProperty, aNewValue,
aLastModified, aItemType) {
if (!this._batching && aProperty == "uri")
this.updateState();
},

View File

@ -151,12 +151,9 @@ PlacesController.prototype = {
return this._canInsert(true) && this._isClipboardDataPasteable();
case "cmd_selectAll":
if (this._view.selType != "single") {
var result = this._view.getResult();
if (result) {
var container = asContainer(result.root);
if (container.containerOpen && container.childCount > 0)
var rootNode = this._view.getResultNode();
if (rootNode.containerOpen && rootNode.childCount > 0)
return true;
}
}
return false;
case "placesCmd_open":
@ -171,7 +168,7 @@ PlacesController.prototype = {
return this._canInsert();
case "placesCmd_new:separator":
return this._canInsert() &&
!asQuery(this._view.getResult().root).queryOptions.excludeItems &&
!asQuery(this._view.getResultNode()).queryOptions.excludeItems &&
this._view.getResult().sortingMode ==
Ci.nsINavHistoryQueryOptions.SORT_BY_NONE;
case "placesCmd_show:info":
@ -449,7 +446,7 @@ PlacesController.prototype = {
*/
_buildSelectionMetadata: function PC__buildSelectionMetadata() {
var metadata = [];
var root = this._view.getResult().root;
var root = this._view.getResultNode();
var nodes = this._view.getSelectionNodes();
if (nodes.length == 0)
nodes.push(root); // See the second note above
@ -1011,7 +1008,6 @@ PlacesController.prototype = {
var nodes = this._view.getSelectionNodes();
var URIs = [];
var bhist = PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory);
var resultView = this._view.getResultView();
var root = this._view.getResultNode();
for (var i = 0; i < nodes.length; ++i) {
@ -1087,7 +1083,7 @@ PlacesController.prototype = {
NS_ASSERT(aTxnName !== undefined, "Must supply Transaction Name");
var root = this._view.getResult().root;
var root = this._view.getResultNode();
if (PlacesUtils.nodeIsFolder(root))
this._removeRowsFromBookmarks(aTxnName);

View File

@ -1065,7 +1065,8 @@ var gEditItemOverlay = {
// nsINavBookmarkObserver
onItemChanged: function EIO_onItemChanged(aItemId, aProperty,
aIsAnnotationProperty, aValue) {
aIsAnnotationProperty, aValue,
aLastModified, aItemType) {
if (this._itemId != aItemId) {
if (aProperty == "title") {
// If the title of a folder which is listed within the folders
@ -1145,7 +1146,7 @@ var gEditItemOverlay = {
},
onItemMoved: function EIO_onItemMoved(aItemId, aOldParent, aOldIndex,
aNewParent, aNewIndex) {
aNewParent, aNewIndex, aItemType) {
if (aItemId != this._itemId ||
aNewParent == this._getFolderIdFromMenuList())
return;
@ -1157,7 +1158,7 @@ var gEditItemOverlay = {
this._folderMenuList.selectedItem = folderItem;
},
onItemAdded: function EIO_onItemAdded(aItemId, aFolder, aIndex) {
onItemAdded: function EIO_onItemAdded(aItemId, aFolder, aIndex, aItemType) {
this._lastNewItem = aItemId;
},

View File

@ -78,8 +78,6 @@
<!-- This is the view that manage the popup -->
<field name="_rootView">PlacesUIUtils.getViewForNode(this);</field>
<field name="_built">false</field>
<method name="onDragOver">
<parameter name="aEvent"/>
<parameter name="aFlavour"/>
@ -536,9 +534,9 @@
extends="chrome://browser/content/places/menu.xml#places-popup-base">
<implementation>
<destructor><![CDATA[
this._resultNode = null;
if (this._result) {
this._result.root.containerOpen = false;
this._resultNode.containerOpen = false;
this._resultNode = null;
this._result.viewer = null;
this._result = null;
}
@ -574,12 +572,13 @@
var resultNode = popup._resultNode;
if (!resultNode.containerOpen)
resultNode.containerOpen = true;
if (!popup._built)
if (!popup.parentNode._built)
this._rebuild(popup);
]]></body>
</method>
<field name="_result">null</field>
<field name="_resultNode">null</field>
<!-- nsIPlacesView -->
<method name="getResult">
@ -599,20 +598,12 @@
<method name="removeItem">
<parameter name="child"/>
<body><![CDATA[
if (PlacesUtils.nodeIsContainer(child.node)) {
for (var i=0; i < this._containerNodesMap.length; i++) {
if (this._containerNodesMap[i].resultNode == child.node) {
this._containerNodesMap.splice(i, 1);
break;
}
}
}
// if document.popupNode pointed to this child, null it out,
// otherwise controller's command-updating may rely on the removed
// item still being "selected".
if (document.popupNode == child)
document.popupNode = null;
child.parentNode.removeChild(child);
if (this._endMarker != -1)
@ -625,8 +616,7 @@
<parameter name="aParentPopup"/>
<parameter name="aBefore"/>
<body><![CDATA[
var element =
PlacesUIUtils.createMenuItemForNode(aChild, this._containerNodesMap);
var element = PlacesUIUtils.createMenuItemForNode(aChild);
if (aBefore)
aParentPopup.insertBefore(element, aBefore);
@ -689,7 +679,7 @@
if (aPopup._startMarker == -1 && aPopup._endMarker == -1)
this._showEmptyMenuItem(aPopup);
}
aPopup._built = true;
aPopup.parentNode._built = true;
]]></body>
</method>
@ -697,18 +687,6 @@
<field name="_viewer"><![CDATA[({
_self: this,
_getPopupForContainer:
function PMV__getPopupForContainer(aNode) {
if (this._self._resultNode == aNode)
return this._self;
for (var i=0; i < this._self._containerNodesMap.length; i++) {
if (this._self._containerNodesMap[i].resultNode == aNode)
return this._self._containerNodesMap[i].domNode;
}
throw("Container view not found");
},
get result() {
return this._self._result;
},
@ -721,130 +699,168 @@
// we should do nothing.
if (this._self._result != val) {
if (this._self._result)
this._self._result.root.containerOpen = false;
this._built = false;
this._self._containerNodesMap = [];
this._self._resultNode = val.root;
this._self._resultNode.containerOpen = false;
this._self.parentNode._built = false;
this._self._result = val;
if (val) {
this._self._resultNode = val.root;
this._self._resultNode._DOMElement = this._self.parentNode;
}
else
this._self._resultNode = null;
}
return val;
},
itemInserted: function PMV_itemInserted(aParentNode, aNode, aIndex) {
var popup = this._getPopupForContainer(aParentNode);
if (!popup._built)
nodeInserted: function PMV_nodeInserted(aParentNode, aNode, aIndex) {
let parentElt = aParentNode._DOMElement;
NS_ASSERT(parentElt, "parent node must have _DOMElement set");
if (!parentElt._built)
return;
var index = popup._startMarker + 1 + aIndex;
var before = popup.childNodes[index] || null;
// parentElt is the <menu> element for the container,
// we need the <menupopup>
let popup = parentElt.firstChild;
let index = popup._startMarker + 1 + aIndex;
let before = popup.childNodes[index] || null;
this._self.insertNewItem(aNode, popup, before);
if (popup._emptyMenuItem)
popup._emptyMenuItem.hidden = true;
},
itemRemoved: function PMV_itemRemoved(aParentNode, aNode, aIndex) {
var popup = this._getPopupForContainer(aParentNode);
if (!popup._built)
nodeRemoved: function PMV_nodeRemoved(aParentNode, aNode, aIndex) {
let parentElt = aParentNode._DOMElement;
NS_ASSERT(parentElt, "parent node must have _DOMElement set");
if (!parentElt._built)
return;
var children = popup.childNodes;
for (var i = popup._startMarker + 1; i < children.length; i++) {
if (children[i].node == aNode) {
this._self.removeItem(children[i]);
if (!popup.hasChildNodes() ||
(popup.childNodes.length == 1 &&
popup.firstChild == popup._emptyMenuItem)) {
this._self._showEmptyMenuItem(popup);
}
return;
}
}
// parentElt is the <menu> element for the container,
// we need the <menupopup>
let popup = parentElt.firstChild;
let nodeElt = aNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
popup.removeChild(nodeElt);
// Figure out if we need to show the "<Empty>" menu-item.
// TODO Bug 517701: This doesn't seem to handle the case of an empty
// root (parentElt == this._self.parentNode).
if (!popup.hasChildNodes() ||
(popup.childNodes.length == 1 &&
popup.firstChild == popup._emptyMenuItem))
this._self._showEmptyMenuItem(popup);
if (popup._endMarker != -1)
popup._endMarker--;
},
itemMoved:
function PMV_itemMoved(aItem, aOldParent, aOldIndex, aNewParent,
aNewIndex) {
// This cannot actually happen yet (see IDL)
if (aNewParent != aOldParent)
nodeMoved:
function PMV_nodeMoved(aNode,
aOldParent, aOldIndex,
aNewParent, aNewIndex) {
// Note: the current implementation of moveItem does not actually
// use this notification when the item in question is moved from one
// folder to another. Instead, it calls nodeRemoved and nodeInserted
// for the two folders. Thus, we can assume aOldParent == aNewParent.
let nodeElt = aNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
// If our root node is a folder, it might be moved. There's nothing
// we need to do in that case.
if (nodeElt == this._self.parentNode)
return;
var popup = this._getPopupForContainer(aNewParent);
var index = popup._startMarker + 1 + aNewIndex;
var children = popup.childNodes;
for (var i = popup._startMarker + 1; i < children.length; i++) {
var menuItem = children[i];
if (menuItem.node == aItem) {
popup.removeChild(menuItem);
popup.insertBefore(menuItem, children[index]);
return;
}
}
// Move the node.
let popup = nodeElt.parentNode;
popup.removeChild(nodeElt);
popup.insertBefore(nodeElt, popup.childNodes[aNewIndex]);
},
itemChanged: function PMV_itemChanged(aNode) {
// this check can be removed once we fix bug #382397
var parentNode = aNode.parent;
if (!parentNode)
nodeTitleChanged: function PMV__nodeTitleChanged(aNode, aNewTitle) {
let nodeElt = aNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
// There's no UI representation for the root node, thus there's
// nothing to be done when the title changes.
if (nodeElt == this._self.parentNode)
return;
if (PlacesUtils.nodeIsSeparator(aNode)) {
// nothing to do when a separator changes
return;
}
nodeElt.label = aNewTitle || PlacesUIUtils.getBestTitle(aNode);
},
var popup = this._getPopupForContainer(parentNode);
if (!popup._built)
nodeURIChanged: function PMV_nodeURIChanged(aNode, aURIString) {
let nodeElt = aNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
nodeElt.setAttribute("scheme",
PlacesUIUtils.guessUrlSchemeForUI(aURIString));
},
nodeIconChanged: function PMV_nodeIconChanged(aNode) {
let nodeElt = aNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
// There's no UI representation for the root node, thus there's
// nothing to be done when the icon changes.
if (nodeElt == this._self.parentNode)
return;
var children = popup.childNodes;
var menuitem;
for (var i = popup._startMarker + 1; i < children.length; i++) {
if (children[i].node == aNode) {
menuitem = children[i];
break;
}
}
var iconURI = aNode.icon;
if (iconURI) {
var spec = iconURI.spec;
if (menuitem.getAttribute("image") != spec)
menuitem.setAttribute("image", spec);
var icon = aNode.icon;
if (icon) {
if (nodeElt.getAttribute("image") != icon)
nodeElt.setAttribute("image", icon);
}
else
menuitem.removeAttribute("image");
nodeElt.removeAttribute("image");
},
var title = PlacesUIUtils.getBestTitle(aNode);
if (menuitem.getAttribute("label") != title)
menuitem.setAttribute("label", title);
nodeAnnotationChanged:
function PMV_nodeAnnotationChanged(aNode, aAnno) {
// Ensure the changed annotation is a livemark one.
if (/^livemark\//.test(aAnno) &&
PlacesUtils.nodeIsLivemarkContainer(aNode)) {
let nodeElt = aNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
if (PlacesUtils.nodeIsLivemarkContainer(aNode)) {
if (!menuitem.hasAttribute("livemark"))
menuitem.setAttribute("livemark", "true");
// If this is a livemark container check if the status menuitem has
// to be added or removed.
PlacesUIUtils.ensureLivemarkStatusMenuItem(menuitem.firstChild);
}
else if (PlacesUtils.nodeIsURI(aNode)) {
menuitem.setAttribute("scheme", PlacesUIUtils.guessUrlSchemeForUI(aNode.uri));
if (!nodeElt.hasAttribute("livemark"))
nodeElt.setAttribute("livemark", "true");
// Add or remove the livemark status menuitem.
PlacesUIUtils.ensureLivemarkStatusMenuItem(nodeElt.firstChild);
}
},
itemReplaced:
function PMV_itemReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
var popup = this._getPopupForContainer(aParentNode);
if (!popup._built)
nodeHistoryDetailsChanged: function() { },
nodeTagsChanged: function() { },
nodeDateAddedChanged: function() { },
nodeLastModifiedChanged: function() { },
nodeKeywordChanged: function() { },
nodeReplaced:
function PMV_nodeReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
let parentElt = aParentNode._DOMElement;
NS_ASSERT(parentElt, "parent node must have _DOMElement set");
if (!parentElt._built)
return;
var children = popup.childNodes;
for (var i = popup._startMarker + 1; i < children.length; i++) {
if (children[i].node == aOldNode) {
var next = children[i].nextSibling;
this._self.removeItem(children[i]);
this._self.insertNewItem(aNewNode, popup, next);
return;
}
}
// parentElt is the <menu> element for the container,
// we need the <menupopup>.
let popup = parentElt.firstChild;
let nodeElt = aOldNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
// No worries: If nodeElt is the last item (i.e. no nextSibling),
// insertNewItem will insert the new element as the last item.
let next = nodeElt.nextSibling;
this._self.removeItem(nodeElt);
this._self.insertNewItem(aNewNode, popup, next);
},
containerOpened: function PMV_containerOpened(aNode) {
@ -854,45 +870,19 @@
containerClosed: function PMV_containerClosed(aNode) {
this.invalidateContainer(aNode);
},
invalidateContainer: function PMV_invalidateContainer(aContainer) {
if (!this._self._built)
// Do nothing if the entire view is already marked un-built.
if (!this._self.parentNode._built)
return;
function isChildOf(node, container) {
var parent = node.parent;
while (parent) {
if (parent == container)
return true;
parent = parent.parent;
}
return false;
}
let containerNodeElt = aContainer._DOMElement;
NS_ASSERT(containerNodeElt, "node must have _DOMElement set");
containerNodeElt._built = false;
var popupToRebuild = null;
for (var i=0; i < this._self._containerNodesMap.length; i++) {
var node = this._self._containerNodesMap[i].resultNode;
if (node == aContainer)
popupToRebuild = this._self._containerNodesMap[i].domNode;
if (isChildOf(node, aContainer)) {
this._self._containerNodesMap.splice(i,1);
i--;
}
}
if (!popupToRebuild)
popupToRebuild = this._self;
popupToRebuild._built = false;
// if the menupopup is open we should live-update it
if (popupToRebuild.parentNode.open)
this._self._rebuild(popupToRebuild);
},
invalidateAll: function PMV_invalidateAll() {
this._self._containerNodesMap.splice(0);
this._self._built = false;
// If the menupopup is open we should live-update it.
if (containerNodeElt.open)
this._self._rebuild(containerNodeElt.firstChild);
},
sortingChanged: function PMV_sortingChanged(aSortingMode) {
@ -914,6 +904,7 @@
PlacesUtils.history.executeQueries(queries.value,
queries.value.length,
options.value);
result.viewer = this._viewer;
return val;
]]></setter>

View File

@ -24,6 +24,7 @@
# Ben Goodger <beng@google.com>
# Myk Melez <myk@mozilla.org>
# Marco Bonardo <mak77@bonardo.net>
# Asaf Romano <mano@mozilla.com>
#
# 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
@ -37,7 +38,7 @@
# 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 *****
# ***** END LICENSE BLOCK *****
<!DOCTYPE bindings [
@ -99,6 +100,8 @@
window.removeEventListener("resize", this, false);
if (this._result) {
this._resultNode.containerOpen = false;
this._resultNode = null;
this._result.viewer = null;
this._result = null;
}
@ -110,17 +113,48 @@
<method name="_init">
<body><![CDATA[
this._controller = new PlacesController(this);
this.controllers.appendController(this._controller);
// XBL bug is in the middle...
// When toolbar customization is opened, this binding is attached
// again, as a result of adding the item under the wrapper. However,
// the binding isn't detached from the "original" hbox element due
// to bug 83635.
//
// Then, when the customization dialog is closed, the binding is
// attached the third time, as a result of adding our element back to
// the toolbar.
//
// So, We'll just continue using the original binding, which was
// never removed, and avoid using the new bindings. This means that
// this workaround will work just until bug 83635 is fixed.
//
// However, when the binding is "reconstructed", we do need to add
// back the event listeners and the places controller.
//
// Note: we could avoid part of this mess by moving the "Bookmark
// Toolbar Items" placeholder out of this binding.
this._scrollbox.addEventListener("overflow", this, false);
this._scrollbox.addEventListener("underflow", this, false);
window.addEventListener("resize", this, false);
// We also need to avoid initializing _result and _resultNode and
// _controller as XBL fields. Otherwise, they'll be unset when the
// "extra" bindings are applied.
if (this.hasAttribute("place")) {
// Do the initial build.
this.place = this.place;
}
this._scrollbox.addEventListener("overflow", this, false);
this._scrollbox.addEventListener("underflow", this, false);
window.addEventListener("resize", this, false);
if (this._result === undefined) {
this._result = null;
this._resultNode = null;
if (this.hasAttribute("place")) {
// Do the initial build.
this.place = this.place;
}
}
// Attach the places controller.
if (!this._controller)
this._controller = new PlacesController(this);
this.controllers.appendController(this._controller);
]]></body>
</method>
@ -142,9 +176,6 @@
<field name="_openedMenuButton">null</field>
<field name="_allowPopupShowing">true</field>
<field name="_result">null</field>
<field name="_resultNode">null</field>
<field name="_isRTL">
document.defaultView.getComputedStyle(this.parentNode, "")
.direction == "rtl"
@ -160,7 +191,7 @@
<!-- nsIPlacesView -->
<method name="getResultNode">
<body><![CDATA[
return this._result.root;
return this._resultNode;
]]></body>
</method>
@ -175,10 +206,9 @@
while (this.hasChildNodes())
this.removeChild(this.firstChild);
var rootNode = this._result.root;
var cc = rootNode.childCount;
let cc = this._resultNode.childCount;
for (let i = 0; i < cc; ++i)
this.insertNewItem(rootNode.getChild(i), null);
this.insertNewItem(this._resultNode.getChild(i), null);
if (this._chevronPopup.hasAttribute("type")) {
// Chevron has already been initialized, but since we are forcing
@ -186,9 +216,6 @@
// Otherwise, it will be initialized when the toolbar overflows.
this._chevronPopup.place = this.place;
}
while (chevronPopup.hasChildNodes())
this._chevronPopup.removeChild(this._chevronPopup.lastChild);
]]></body>
</method>
@ -204,12 +231,9 @@
button = document.createElement("toolbarbutton");
button.className = "bookmark-item";
button.setAttribute("label", aChild.title);
var iconURI = aChild.icon;
var iconURISpec = "";
if (iconURI) {
iconURISpec = iconURI.spec;
button.setAttribute("image", iconURISpec);
}
var icon = aChild.icon;
if (icon)
button.setAttribute("image", icon);
if (PlacesUtils.containerTypes.indexOf(type) != -1) {
button.setAttribute("type", "menu");
@ -226,21 +250,17 @@
var popup = document.createElement("menupopup");
popup.setAttribute("placespopup", "true");
button.appendChild(popup);
popup._result = this._result;
popup._resultNode = asContainer(aChild);
#ifndef XP_MACOSX
popup.setAttribute("context", "placesContext");
#endif
this._containerNodesMap.push({ resultNode: aChild,
domNode: popup });
}
else if (PlacesUtils.nodeIsURI(aChild)) {
else if (PlacesUtils.nodeIsURI(aChild))
button.setAttribute("scheme", PlacesUIUtils.guessUrlSchemeForUI(aChild.uri));
}
}
button.node = aChild;
button.node.viewIndex = 0;
aChild._DOMElement = button;
if (aBefore)
this.insertBefore(button, aBefore);
else
@ -251,20 +271,12 @@
<method name="removeItem">
<parameter name="child"/>
<body><![CDATA[
if (PlacesUtils.nodeIsContainer(child.node)) {
for (let i = 0; i < this._containerNodesMap.length; i++) {
if (this._containerNodesMap[i].resultNode == child.node) {
this._containerNodesMap.splice(i, 1);
break;
}
}
}
// if document.popupNode pointed to this child, null it out,
// otherwise controller's command-updating may rely on the removed
// item still being "selected".
if (document.popupNode == child)
document.popupNode = null;
child.parentNode.removeChild(child);
]]></body>
</method>
@ -378,13 +390,13 @@
<getter><![CDATA[
return this.getAttribute("place");
]]></getter>
<setter><![CDATA[
<setter><![CDATA[
this.setAttribute("place", val);
var history = PlacesUtils.history;
var queries = { }, options = { };
history.queryStringToQueries(val, queries, { }, options);
if (!queries.value.length)
if (!queries.value.length)
queries.value = [history.getNewQuery()];
try {
var result =
@ -394,7 +406,7 @@
}
catch(ex) {
// Invalid query, or had no results.
// This is valid, eg: user deletes their bookmarks toolbar folder.
// This is valid, eg: user deletes his bookmarks toolbar folder.
}
return val;
]]></setter>
@ -402,7 +414,7 @@
<!-- nsIPlacesView -->
<property name="hasSelection">
<getter><![CDATA[
<getter><![CDATA[
return this.selectedNode != null;
]]></getter>
</property>
@ -453,9 +465,9 @@
<!-- nsIPlacesView -->
<property name="insertionPoint">
<getter><![CDATA[
// By default, the insertion point is at the top level, at the end.
// By default, the insertion point is at the top level, at the end.
var index = PlacesUtils.bookmarks.DEFAULT_INDEX;
var container = this._result.root;
var container = this._resultNode;
var orientation = Ci.nsITreeView.DROP_BEFORE;
var isTag = false;
@ -486,7 +498,7 @@
<!-- nsIPlacesView -->
<method name="selectAll">
<body><![CDATA[
<body><![CDATA[
// Nothing
]]></body>
</method>
@ -501,18 +513,6 @@
<field name="_viewer"><![CDATA[({
_self: this,
_getPopupForContainer:
function PMV__getPopupForContainer(aNode) {
if (this._self._resultNode == aNode)
return this._self;
for (let i = 0; i < this._self._containerNodesMap.length; i++) {
if (this._self._containerNodesMap[i].resultNode == aNode)
return this._self._containerNodesMap[i].domNode;
}
throw("Container view not found");
},
get result() {
return this._self._result;
},
@ -525,242 +525,235 @@
// we should do nothing.
if (this._self._result != val) {
if (this._self._result)
this._self._result.root.containerOpen = false;
this._self._containerNodesMap = [];
this._self._resultNode.containerOpen = false;
this._self._result = val;
if (val) // this calls _rebuild through invalidateContainer
val.root.containerOpen = true;
if (val) {
this._self._resultNode = val.root;
this._self._resultNode._DOMElement = this._self;
// This calls _rebuild through invalidateContainer.
this._self._resultNode.containerOpen = true;
}
else
this._self._resultNode = null;
}
return val;
},
itemInserted: function TV_V_itemInserted(aParentNode, aNode, aIndex) {
// don't insert new items into the toolbar
// if the parent is not the root
if (aParentNode == this._self.getResultNode()) {
var children = this._self.childNodes;
nodeInserted: function TV_V_nodeInserted(aParentNode, aNode, aIndex) {
let parentElt = aParentNode._DOMElement;
NS_ASSERT(parentElt, "parent node must have _DOMElement set");
if (parentElt == this._self) {
// Node is on the toolbar.
let children = this._self.childNodes;
this._self.insertNewItem(aNode,
aIndex < children.length ? children[aIndex] : null);
this._self.updateChevron();
}
else {
var popup = this._getPopupForContainer(aParentNode);
if (!popup._built)
return;
var before = popup.childNodes[aIndex] || null;
else if (parentElt._built) {
// Node is within a built menu.
let popup = parentElt.firstChild;
let before = popup.childNodes[aIndex] || null;
this._self.insertNewItemToPopup(aNode, popup, before);
if (popup._emptyMenuItem)
popup._emptyMenuItem.hidden = true;
}
},
itemRemoved: function TV_V_itemRemoved(aParentNode, aNode, aIndex) {
if (aParentNode == this._self.getResultNode()) {
var children = this._self.childNodes;
for (let i = 0; i < children.length; i++) {
if (children[i].node == aNode) {
this._self.removeItem(children[i]);
this._self.updateChevron();
return;
}
}
}
else {
var popup = this._getPopupForContainer(aParentNode);
if (!popup._built)
return;
nodeRemoved: function TV_V_nodeRemoved(aParentNode, aNode, aIndex) {
let parentElt = aParentNode._DOMElement;
let nodeElt = aNode._DOMElement;
var children = popup.childNodes;
for (let i = popup._startMarker + 1; i < children.length; i++) {
if (children[i].node == aNode) {
this._self.removeItem(children[i]);
if (!popup.hasChildNodes() ||
(popup.childNodes.length == 1 &&
popup.firstChild == popup._emptyMenuItem)) {
this._self._showEmptyMenuItem(popup);
}
if (popup._endMarker != -1)
popup._endMarker--;
return;
}
}
NS_ASSERT(parentElt, "parent node must have _DOMElement set");
NS_ASSERT(nodeElt, "node must have _DOMElement set");
if (parentElt == this._self) {
// Node is on the toolbar.
this._self.removeChild(nodeElt);
this._self.updateChevron();
}
else if (parentElt._built) {
// Node is within a built menu.
var popup = parentElt.firstChild;
popup.removeChild(nodeElt);
if (!popup.hasChildNodes() ||
(popup.childNodes.length == 1 &&
popup.firstChild == popup._emptyMenuItem))
this._self._showEmptyMenuItem(popup);
if (popup._endMarker != -1)
popup._endMarker--;
}
},
itemMoved:
function TV_V_itemMoved(aItem, aOldParent, aOldIndex, aNewParent,
aNewIndex) {
// This cannot actually happen yet (see IDL)
if (aNewParent != aOldParent)
nodeMoved:
function TV_V_nodeMoved(aNode,
aOldParent, aOldIndex,
aNewParent, aNewIndex) {
// Note: the current implementation of moveItem does not actually
// use this notification when the item in question is moved from one
// folder to another. Instead, it calls nodeRemoved and nodeInserted
// for the two folders. Thus, we can assume aOldParent == aNewParent.
let nodeElt = aNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
// If our root node is a folder, it might be moved. There's nothing
// we need to do in that case.
if (nodeElt == this._self)
return;
if (aNewParent == this._self.getResultNode()) {
var children = this._self.childNodes;
for (let i = 0; i < children.length; i++) {
var button = children[i];
if (button.node == aItem) {
this._self.removeChild(button);
this._self.insertBefore(button, children[aNewIndex]);
// If the chevron popup is open, keep it in sync.
if (this._self._chevron.open) {
var chevronPopup = this._self._chevronPopup;
var menuitem = chevronPopup.childNodes[i];
chevronPopup.removeChild(menuitem);
chevronPopup.insertBefore(menuitem,
chevronPopup.childNodes[aNewIndex]);
}
this._self.updateChevron();
return;
}
let parentElt = aNewParent._DOMElement;
NS_ASSERT(parentElt, "parent node must have _DOMElement set");
if (parentElt == this._self) {
// Container is on the toolbar.
// Move the node.
this._self.removeChild(nodeElt);
this._self.insertBefore(nodeElt, this._self.childNodes[aNewIndex]);
// If the chevron popup is open, keep it in sync.
if (this._self._chevron.open) {
let chevronPopup = this._self._chevronPopup;
let menuitem = chevronPopup.childNodes[aOldIndex];
chevronPopup.removeChild(menuitem);
chevronPopup.insertBefore(menuitem,
chevronPopup.childNodes[aNewIndex]);
}
this._self.updateChevron();
}
else {
var popup = this._getPopupForContainer(aNewParent);
var children = popup.childNodes;
for (let i = popup._startMarker + 1; i < children.length; i++) {
var menuItem = children[i];
if (menuItem.node == aItem) {
popup.removeChild(menuItem);
popup.insertBefore(menuItem, children[aNewIndex]);
return;
}
}
else if (parentElt._built) {
// Container is within a built menu.
// parentElt is the <menu> element for the container,
// we need the <menupopup>.
var popup = parentElt.firstChild;
// Move the node.
popup.removeChild(nodeElt);
popup.insertBefore(nodeElt, popup.childNodes[aNewIndex]);
}
},
itemChanged: function TV_V_itemChanged(aNode) {
// this check can be removed once we fix bug #382397
var parentNode = aNode.parent;
if (!parentNode)
nodeTitleChanged: function TV_V_nodeTitleChanged(aNode, aNewTitle) {
let nodeElt = aNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
// There's no UI representation for the root node, thus there's
// nothing to be done when the title changes.
if (nodeElt == this._self)
return;
if (PlacesUtils.nodeIsSeparator(aNode)) {
// nothing to do when a separator changes
return;
}
var element;
var onToolbar = false;
if (parentNode == this._self.getResultNode()) {
onToolbar = true;
var children = this._self.childNodes;
for (let i = 0; i < children.length; i++) {
if (children[i].node == aNode) {
element = children[i];
break;
}
}
// Don't replace title on toolbarbuttons
var title = aNode.title;
if (nodeElt.parentNode == this._self) {
// Node is on the toolbar
nodeElt.label = aNewTitle;
this._self.updateChevron();
}
else {
var popup = this._getPopupForContainer(parentNode);
if (!popup._built)
return;
var children = popup.childNodes;
for (let i = popup._startMarker + 1; i < children.length; i++) {
if (children[i].node == aNode) {
element = children[i];
break;
}
}
var title = PlacesUIUtils.getBestTitle(aNode);
// Node is within a built menu.
nodeElt.label = aNewTitle || PlacesUIUtils.getBestTitle(aNode);
}
},
var iconURI = aNode.icon;
if (iconURI) {
var spec = iconURI.spec;
if (element.getAttribute("image") != spec)
element.setAttribute("image", spec);
nodeURIChanged: function TV_V_nodeURIChanged(aNode, aURIString) {
let nodeElt = aNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
nodeElt.setAttribute("scheme",
PlacesUIUtils.guessUrlSchemeForUI(aURIString));
},
nodeIconChanged: function TV_V_nodeIconChanged(aNode) {
let nodeElt = aNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
// There's no UI representation for the root node, thus there's
// nothing to be done when the icon changes.
if (nodeElt == this._self)
return;
let icon = aNode.icon;
if (icon) {
if (nodeElt.getAttribute("image") != icon)
nodeElt.setAttribute("image", icon);
}
else
element.removeAttribute("image");
nodeElt.removeAttribute("image");
},
if (element.getAttribute("label") != title) {
element.setAttribute("label", title);
if (onToolbar)
this._self.updateChevron();
}
nodeAnnotationChanged:
function TV_V_nodeAnnotationChanged(aNode, aAnno) {
// Ensure the changed annotation is a livemark one.
if (/^livemark\//.test(aAnno) &&
PlacesUtils.nodeIsLivemarkContainer(aNode)) {
let nodeElt = aNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
if (PlacesUtils.nodeIsLivemarkContainer(aNode)) {
if (!element.hasAttribute("livemark"))
element.setAttribute("livemark", "true");
// If this is a livemark container check if the status menuitem has
// to be added or removed.
PlacesUIUtils.ensureLivemarkStatusMenuItem(element.firstChild);
}
else if (PlacesUtils.nodeIsURI(aNode)) {
element.setAttribute("scheme", PlacesUIUtils.guessUrlSchemeForUI(aNode.uri));
if (!nodeElt.hasAttribute("livemark"))
nodeElt.setAttribute("livemark", "true");
// Add or remove the livemark status menuitem.
PlacesUIUtils.ensureLivemarkStatusMenuItem(nodeElt.firstChild);
}
},
itemReplaced:
function TV_V_itemReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
if (aParentNode == this._self.getResultNode()) {
var children = this._self.childNodes;
for (let i = 0; i < children.length; i++) {
if (children[i].node == aOldNode) {
var next = children[i].nextSibling;
this._self.removeItem(children[i]);
this._self.insertNewItem(aNewNode, next);
this._self.updateChevron();
return;
}
}
nodeHistoryDetailsChanged: function() { },
nodeTagsChanged: function() { },
nodeDateAddedChanged: function() { },
nodeLastModifiedChanged: function() { },
nodeKeywordChanged: function() { },
nodeReplaced:
function TV_V_nodeReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
let nodeElt = aOldNode._DOMElement;
NS_ASSERT(nodeElt, "node must have _DOMElement set");
// No worries: If nodeElt is the last item (i.e. no nextSibling),
// insertNewItem/insertNewItemToPopup will insert the new element as
// the last item.
let next = nodeElt.nextSibling;
let parentElt = aParentNode._DOMElement;
NS_ASSERT(parentElt, "parent node must have _DOMElement set");
if (parentElt == this._self) {
// Node is on the toolbar.
this._self.removeItem(nodeElt);
this._self.insertNewItem(aNewNode, next);
this._self.updateChevron();
}
else if (parentElt._built) {
// Node is within a built menu.
let popup = parentElt.firstChild;
popup.removeItem(nodeElt);
this._self.insertNewItemToPopup(aNewNode, popup, next);
}
},
containerOpened: function TV_V_containerOpened(aNode) {
this.invalidateContainer(aNode);
containerOpened: function TV_V_containerOpened(aContainer) {
this.invalidateContainer(aContainer);
},
containerClosed: function TV_V_containerClosed(aNode) {
this.invalidateContainer(aNode);
containerClosed: function TV_V_containerClosed(aContainer) {
this.invalidateContainer(aContainer);
},
invalidateContainer: function TV_V_invalidateContainer(aContainer) {
if (aContainer == this._self.getResultNode()) {
this._self._containerNodesMap.splice(0);
let containerNodeElt = aContainer._DOMElement;
NS_ASSERT(containerNodeElt, "node must have _DOMElement set");
if (containerNodeElt == this._self) {
// Container is the toolbar itself.
this._self._rebuild();
return;
}
function isChildOf(node, container) {
var parent = node.parent;
while (parent) {
if (parent == container)
return true;
parent = parent.parent;
}
return false;
else if (containerNodeElt._built) {
// Container is a built menu.
containerNodeElt._built = false;
// If the menupopup is open we should live-update it.
if (containerNodeElt.open)
this._self._rebuildPopup(containerNodeElt.firstChild);
}
var popupToRebuild = null;
for (let i = 0; i < this._self._containerNodesMap.length; i++) {
var node = this._self._containerNodesMap[i].resultNode;
if (node == aContainer)
popupToRebuild = this._self._containerNodesMap[i].domNode;
if (isChildOf(node, aContainer)) {
this._self._containerNodesMap.splice(i,1);
i--;
}
}
if (popupToRebuild) {
popupToRebuild._built = false;
// if the menupopup is open we should live-update it
if (popupToRebuild.parentNode.open)
this._self._rebuildPopup(popupToRebuild);
}
},
invalidateAll: function TV_V_invalidateAll() {
this._self._containerNodesMap.splice(0);
this._self._rebuild();
},
sortingChanged: function TV_V_sortingChanged(aSortingMode) {
@ -808,8 +801,7 @@
<parameter name="aParentPopup"/>
<parameter name="aBefore"/>
<body><![CDATA[
var element =
PlacesUIUtils.createMenuItemForNode(aChild, this._containerNodesMap);
var element = PlacesUIUtils.createMenuItemForNode(aChild);
if (aBefore)
aParentPopup.insertBefore(element, aBefore);
@ -833,7 +825,7 @@
<method name="_containerPopupShowing">
<parameter name="aPopup"/>
<body><![CDATA[
if (!aPopup._built)
if (!aPopup.parentNode._built)
this._rebuildPopup(aPopup);
]]></body>
</method>
@ -868,7 +860,7 @@
if (aPopup._startMarker == -1 && aPopup._endMarker == -1)
this._showEmptyMenuItem(aPopup);
}
aPopup._built = true;
aPopup.parentNode._built = true;
]]></body>
</method>
@ -914,7 +906,7 @@
// - beforeIndex: child index to drop before, for the drop indicator.
// - folderNode: the folder to drop into, if applicable.
var result = this.getResult();
if (!PlacesUtils.nodeIsFolder(result.root))
if (!PlacesUtils.nodeIsFolder(this._resultNode))
return null;
var dropPoint = { ip: null, beforeIndex: null, folderNode: null };
@ -932,7 +924,7 @@
: (aEvent.clientX < nodeRect.left + threshold)) {
// Drop before this folder.
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
nodeIndex, Ci.nsITreeView.DROP_BEFORE);
dropPoint.beforeIndex = nodeIndex;
}
@ -951,7 +943,7 @@
let beforeIndex =
(nodeIndex == this.childNodes.length - 1) ? -1 : nodeIndex + 1;
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
beforeIndex, Ci.nsITreeView.DROP_BEFORE);
dropPoint.beforeIndex = beforeIndex;
}
@ -964,7 +956,7 @@
: (aEvent.clientX < nodeRect.left + threshold)) {
// Drop before this bookmark.
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
nodeIndex, Ci.nsITreeView.DROP_BEFORE);
dropPoint.beforeIndex = nodeIndex;
}
@ -973,7 +965,7 @@
let beforeIndex =
nodeIndex == this.childNodes.length - 1 ? -1 : nodeIndex + 1;
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
beforeIndex, Ci.nsITreeView.DROP_BEFORE);
dropPoint.beforeIndex = beforeIndex;
}
@ -983,7 +975,7 @@
// We are most likely dragging on the empty area of the
// toolbar, we should drop after the last node.
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
-1, Ci.nsITreeView.DROP_BEFORE);
dropPoint.beforeIndex = -1;
}
@ -1216,7 +1208,7 @@
this._draggedNode = null;
]]></handler>
<handler event="popupshowing" phase="capturing"><![CDATA[
<handler event="popupshowing" phase="capturing"><![CDATA[
if (!this._allowPopupShowing) {
this._allowPopupShowing = true;
event.preventDefault();

View File

@ -136,7 +136,7 @@
callback = new Function("aContainer", onOpenFlatContainer);
}
var treeView = new PlacesTreeView(this.showRoot, this.flatList, callback);
var treeView = new PlacesTreeView(this.flatList, callback);
result.viewer = treeView;
this.view = treeView;
if (!this._controller) {
@ -147,21 +147,6 @@
]]></body>
</method>
<property name="showRoot">
<getter><![CDATA[
return this.getAttribute("showRoot") == "true";
]]></getter>
<setter><![CDATA[
if (this.showRoot != val) {
this.setAttribute("showRoot", val);
// reload with the last place set
if (this.place)
this.place = this.place;
}
return val;
]]></setter>
</property>
<property name="flatList">
<getter><![CDATA[
return this.getAttribute("flatList") == "true";
@ -259,7 +244,7 @@
<method name="selectNode">
<parameter name="node"/>
<body><![CDATA[
var view = this.getResultView();
var view = this.view;
var parent = node.parent;
if (parent && !parent.containerOpen) {
@ -308,17 +293,6 @@
]]></body>
</method>
<method name="getResultView">
<body><![CDATA[
try {
return this.view.QueryInterface(Ci.nsINavHistoryResultTreeViewer);
}
catch (e) {
}
return null;
]]></body>
</method>
<!-- nsIPlacesView -->
<property name="place">
<getter><![CDATA[
@ -355,7 +329,7 @@
var selection = this.view.selection;
var rc = selection.getRangeCount();
var nodes = [];
var resultview = this.getResultView();
var resultview = this.view;
for (var i = 0; i < rc; ++i) {
var min = { }, max = { };
selection.getRangeAt(i, min, max);
@ -396,7 +370,7 @@
var selection = this.view.selection;
var rc = selection.getRangeCount();
var nodes = [];
var resultview = this.getResultView();
var resultview = this.view;
// This list is kept independently of the range selected (i.e. OUTSIDE
// the for loop) since the row index of a container is unique for the
// entire view, and we could have some really wacky selection and we
@ -437,7 +411,7 @@
var min = { }, max = { };
selection.getRangeAt(0, min, max);
return this.getResultView().nodeForTreeIndex(min.value);
return this.view.nodeForTreeIndex(min.value);
]]></getter>
</property>
@ -478,7 +452,7 @@
// then use getIndexOfNode to find your absolute index in
// the parent container instead.
//
var resultView = this.getResultView();
var resultView = this.view;
var selection = resultView.selection;
var rc = selection.getRangeCount();
var min = { }, max = { };
@ -509,7 +483,7 @@
<parameter name="orientation"/>
<body><![CDATA[
var result = this.getResult();
var resultview = this.getResultView();
var resultview = this.view;
var container = result.root;
var dropNearItemId = -1;
NS_ASSERT(container, "null container");
@ -673,7 +647,7 @@
// For all the nodes we've found, highlight the corresponding
// index in the tree.
var resultview = this.getResultView();
var resultview = this.view;
var selection = this.view.selection;
selection.selectEventsSuppressed = true;
selection.clearSelection();
@ -729,7 +703,7 @@
this.treeBoxObject.getCellAt(aEvent.clientX, aEvent.clientY,
row, col, child);
var node = row.value != -1 ?
this.getResultView().nodeForTreeIndex(row.value) :
this.view.nodeForTreeIndex(row.value) :
this.getResultNode();
// cache the dropTarget for the view
PlacesControllerDragHelper.currentDropTarget = node;

File diff suppressed because it is too large Load Diff

View File

@ -1002,17 +1002,12 @@ var PlacesUIUtils = {
* Helper for the toolbar and menu views
*/
createMenuItemForNode:
function PUU_createMenuItemForNode(aNode, aContainersMap) {
function PUU_createMenuItemForNode(aNode) {
var element;
var type = aNode.type;
if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR)
element = document.createElement("menuseparator");
else {
var iconURI = aNode.icon;
var iconURISpec = "";
if (iconURI)
iconURISpec = iconURI.spec;
if (PlacesUtils.uriTypes.indexOf(type) != -1) {
element = document.createElement("menuitem");
element.className = "menuitem-iconic bookmark-item";
@ -1051,8 +1046,6 @@ var PlacesUIUtils = {
popup.setAttribute("context", "placesContext");
#endif
element.appendChild(popup);
if (aContainersMap)
aContainersMap.push({ resultNode: aNode, domNode: popup });
element.className = "menu-iconic bookmark-item";
}
else
@ -1060,11 +1053,12 @@ var PlacesUIUtils = {
element.setAttribute("label", this.getBestTitle(aNode));
if (iconURISpec)
element.setAttribute("image", iconURISpec);
var icon = aNode.icon;
if (icon)
element.setAttribute("image", icon);
}
element.node = aNode;
element.node.viewIndex = 0;
element.node._DOMElement = element;
return element;
},

View File

@ -575,7 +575,7 @@ placesCreateLivemarkTransactions.prototype = {
if (PlacesUtils.annotations.itemHasAnnotation(this._id, GUID_ANNO))
this._GUID = PlacesUtils.bookmarks.getItemGUID(this._id);
PlacesUtils.bookmarks.removeFolder(this._id);
PlacesUtils.bookmarks.removeItem(this._id);
}
};

View File

@ -188,7 +188,8 @@ var bookmarksObserver = {
},
// nsINavBookmarkObserver
onItemAdded: function PSB_onItemAdded(aItemId, aFolderId, aIndex) {
onItemAdded: function PSB_onItemAdded(aItemId, aFolderId, aIndex,
aItemType) {
var views = getViewsForFolder(aFolderId);
ok(views.length > 0, "Found affected views: " + views);
@ -202,7 +203,8 @@ var bookmarksObserver = {
}
},
onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex) {
onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex,
aItemType) {
var views = getViewsForFolder(aFolderId);
ok(views.length > 0, "Found affected views: " + views);
// Check that item has been removed.
@ -216,7 +218,8 @@ var bookmarksObserver = {
onItemMoved: function(aItemId,
aOldFolderId, aOldIndex,
aNewFolderId, aNewIndex) {
aNewFolderId, aNewIndex,
aItemType) {
var views = getViewsForFolder(aNewFolderId);
ok(views.length > 0, "Found affected views: " + views);
@ -234,8 +237,7 @@ var bookmarksObserver = {
onEndUpdateBatch: function PSB_onEndUpdateBatch() {},
onBeforeItemRemoved: function PSB_onBeforeItemRemoved(aItemId) {},
onItemVisited: function() {},
onItemChanged: function PSB_onItemChanged(aItemId, aProperty,
aIsAnnotationProperty, aValue) {}
onItemChanged: function PSB_onItemChanged() {}
};
/**
@ -291,7 +293,7 @@ function getNodeForToolbarItem(aItemId) {
if (PlacesUtils.nodeIsFolder(child.node)) {
var popup = child.lastChild;
popup.showPopup(popup);
foundNode = findNode(popup);
var foundNode = findNode(popup);
popup.hidePopup();
if (foundNode[0] != null)
return foundNode;
@ -334,7 +336,7 @@ function getNodeForMenuItem(aItemId) {
// XXX Why is this needed on Linux and Mac?
popup.showPopup(popup);
child.open = true;
foundNode = findNode(popup);
var foundNode = findNode(popup);
popup.hidePopup();
child.open = false;
if (foundNode[0] != null)

View File

@ -91,30 +91,33 @@ var observer = {
onEndUpdateBatch: function() {
this._endUpdateBatch = true;
},
onItemAdded: function(id, folder, index) {
onItemAdded: function(id, folder, index, itemType) {
this._itemAddedId = id;
this._itemAddedParent = folder;
this._itemAddedIndex = index;
this._itemAddedType = itemType;
},
onBeforeItemRemoved: function(id) {
},
onItemRemoved: function(id, folder, index) {
onItemRemoved: function(id, folder, index, itemType) {
this._itemRemovedId = id;
this._itemRemovedFolder = folder;
this._itemRemovedIndex = index;
},
onItemChanged: function(id, property, isAnnotationProperty, value) {
onItemChanged: function(id, property, isAnnotationProperty, newValue,
lastModified, itemType) {
this._itemChangedId = id;
this._itemChangedProperty = property;
this._itemChanged_isAnnotationProperty = isAnnotationProperty;
this._itemChangedValue = value;
this._itemChangedValue = newValue;
},
onItemVisited: function(id, visitID, time) {
this._itemVisitedId = id;
this._itemVisitedVistId = visitID;
this._itemVisitedTime = time;
},
onItemMoved: function(id, oldParent, oldIndex, newParent, newIndex) {
onItemMoved: function(id, oldParent, oldIndex, newParent, newIndex,
itemType) {
this._itemMovedId = id
this._itemMovedOldParent = oldParent;
this._itemMovedOldIndex = oldIndex;
@ -150,18 +153,20 @@ function run_test() {
var txn1 = ptSvc.createFolder("Testing folder", root, bmStartIndex, annos);
ptSvc.doTransaction(txn1);
// the check check that calling undoTransaction on an "empty batch" doesn't undo
// the previous transaction
// This checks that calling undoTransaction on an "empty batch" doesn't
// undo the previous transaction (getItemTitle will fail)
ptSvc.beginBatch();
ptSvc.endBatch();
ptSvc.undoTransaction();
var folderId = bmsvc.getChildFolder(root, "Testing folder");
do_check_eq(TEST_DESCRIPTION,
annosvc.getItemAnnotation(folderId, DESCRIPTION_ANNO));
var folderId = observer._itemAddedId;
do_check_eq(bmsvc.getItemTitle(folderId), "Testing folder");
do_check_eq(observer._itemAddedIndex, bmStartIndex);
do_check_eq(observer._itemAddedParent, root);
do_check_eq(observer._itemAddedId, folderId);
do_check_eq(TEST_DESCRIPTION,
annosvc.getItemAnnotation(folderId, DESCRIPTION_ANNO));
txn1.undoTransaction();
do_check_eq(observer._itemRemovedId, folderId);
do_check_eq(observer._itemRemovedFolder, root);
@ -201,7 +206,9 @@ function run_test() {
// Create item to a folder
var txn2a = ptSvc.createFolder("Folder", root, bmStartIndex);
ptSvc.doTransaction(txn2a);
var fldrId = bmsvc.getChildFolder(root, "Folder");
var fldrId = observer._itemAddedId;
do_check_eq(bmsvc.getItemTitle(fldrId), "Folder");
var txn2b = ptSvc.createItem(uri("http://www.example2.com"), fldrId, bmStartIndex, "Testing1b");
ptSvc.doTransaction(txn2b);
var b2 = (bmsvc.getBookmarkIdsForURI(uri("http://www.example2.com"), {}))[0];
@ -287,7 +294,9 @@ function run_test() {
// Test Removing a Folder
ptSvc.doTransaction(ptSvc.createFolder("Folder2", root, -1));
var fldrId2 = bmsvc.getChildFolder(root, "Folder2");
var fldrId2 = observer._itemAddedId;
do_check_eq(bmsvc.getItemTitle(fldrId2), "Folder2");
var txn4 = ptSvc.removeItem(fldrId2);
txn4.doTransaction();
do_check_eq(observer._itemRemovedId, fldrId2);
@ -549,7 +558,8 @@ function run_test() {
// sortFolderByName
ptSvc.doTransaction(ptSvc.createFolder("Sorting folder", root, bmStartIndex, [], null));
var srtFldId = bmsvc.getChildFolder(root, "Sorting folder");
var srtFldId = observer._itemAddedId;
do_check_eq(bmsvc.getItemTitle(srtFldId), "Sorting folder");
ptSvc.doTransaction(ptSvc.createItem(uri("http://www.sortingtest.com"), srtFldId, -1, "c"));
ptSvc.doTransaction(ptSvc.createItem(uri("http://www.sortingtest.com"), srtFldId, -1, "b"));
ptSvc.doTransaction(ptSvc.createItem(uri("http://www.sortingtest.com"), srtFldId, -1, "a"));

View File

@ -547,7 +547,7 @@ BookmarkFolder.prototype = {
},
remove : function bmf_remove() {
Utilities.bookmarks.removeFolder(this._id);
Utilities.bookmarks.removeItem(this._id);
},
// observer

View File

@ -57,7 +57,7 @@ interface nsINavHistoryBatchCallback;
* Observer for bookmark changes.
*/
[scriptable, uuid(a3544e1e-36a8-404a-9b30-918abf8e005e)]
[scriptable, uuid(1f7e9032-b2c0-4561-b35b-94ba3f8344e2)]
interface nsINavBookmarkObserver : nsISupports
{
/**
@ -80,13 +80,16 @@ interface nsINavBookmarkObserver : nsISupports
*
* @param aItemId
* The id of the bookmark that was added.
* @param aFolder
* The folder that the item was added to.
* @param aParentId
* The id of the folder to which the item was added.
* @param aIndex
* The item's index in the folder.
* @param aItemType
* The type of the item that was added (one of the TYPE_* constants
* defined above).
*/
void onItemAdded(in long long aItemId, in long long aFolder,
in long aIndex);
void onItemAdded(in long long aItemId, in long long aParentId,
in long aIndex, in unsigned short aItemType);
/**
* Notify this observer that an item is about to be removed. Called before
@ -94,8 +97,11 @@ interface nsINavBookmarkObserver : nsISupports
*
* @param aItemId
* The id of the bookmark to be removed.
* @param aItemType
* The type of the item to be removed (one of the TYPE_* constants
* defined above).
*/
void onBeforeItemRemoved(in long long aItemId);
void onBeforeItemRemoved(in long long aItemId, in unsigned short aItemType);
/**
* Notify this observer that an item was removed. Called after the actual
@ -103,14 +109,17 @@ interface nsINavBookmarkObserver : nsISupports
* no additional notifications will be sent.
*
* @param aItemId
* The id of the bookmark that was removed.
* @param aFolder
* The folder that the item was removed from.
* The id of the item that was removed.
* @param aParentId
* The id of the folder from which the item was removed.
* @param aIndex
* The bookmark's index in the folder.
* @param aItemType
* The type of the item that was removed (one of the TYPE_* constants
* defined above).
*/
void onItemRemoved(in long long aItemId, in long long aFolder,
in long aIndex);
void onItemRemoved(in long long aItemId, in long long aParentId,
in long aIndex, in unsigned short aItemType);
/**
* Notify this observer that an item's information has changed. This
@ -121,8 +130,19 @@ interface nsINavBookmarkObserver : nsISupports
* @param aProperty
* The property which changed.
* @param aIsAnnotationProperty
* Is aProperty the name of an item annotation
*
* Whether or not aProperty the name of an item annotation.
* @param aProperty
* The property which has been changed (see list below).
* @param aNewValue
* For certain properties, this is set to the new value of the
* property (see list below).
* @param aLastModified
* If the item's lastModified field has changed, this parameter is
* set to the new value, otherwise it's set to 0.
* @param aItemType
* The type of the item that has been changed(one of the TYPE_* constants
* defined above).
*
* property = "cleartime": (history was deleted, there is no last visit date):
* value = empty string.
* property = "title": value = new title.
@ -134,9 +154,10 @@ interface nsINavBookmarkObserver : nsISupports
* property = "lastModified": value = PRTime when the item was last modified
* aIsAnnotationProperty = true: value = empty string.
*/
void onItemChanged(in long long aBookmarkId, in ACString aProperty,
void onItemChanged(in long long aItemId, in ACString aProperty,
in boolean aIsAnnotationProperty,
in AUTF8String aValue);
in AUTF8String aNewValue, in PRTime aLastModified,
in unsigned short aItemType);
/**
* Notify that the item was visited. Normally in bookmarks we use the last
@ -156,18 +177,22 @@ interface nsINavBookmarkObserver : nsISupports
* Notify this observer that an item has been moved.
* @param aItemId
* The id of the item that was moved.
* @param aOldParent
* @param aOldParentId
* The id of the old parent.
* @param aOldIndex
* The old index inside aOldParent.
* @param aNewParent
* The old index inside the old parent.
* @param aNewParentId
* The id of the new parent.
* @param aNewIndex
* The foindex inside aNewParent.
* The index inside the new parent.
* @param aItemType
* The type of the item that was moved (one of the TYPE_* constants
* defined above).
*/
void onItemMoved(in long long aItemId,
in long long aOldParent, in long aOldIndex,
in long long aNewParent, in long aNewIndex);
in long long aOldParentId, in long aOldIndex,
in long long aNewParentId, in long aNewIndex,
in unsigned short aItemType);
};
/**
@ -219,7 +244,7 @@ interface nsINavBookmarksService : nsISupports
/**
* Inserts a child bookmark into the given folder.
*
* @param aParentFolder
* @param aParentId
* The id of the parent folder
* @param aURI
* The URI to insert
@ -229,7 +254,7 @@ interface nsINavBookmarksService : nsISupports
* The title for the new bookmark
* @return The ID of the newly-created bookmark.
*/
long long insertBookmark(in long long aParentFolder, in nsIURI aURI,
long long insertBookmark(in long long aParentId, in nsIURI aURI,
in long aIndex, in AUTF8String aTitle);
/**
@ -270,22 +295,10 @@ interface nsINavBookmarksService : nsISupports
long long createDynamicContainer(in long long aParentFolder, in AUTF8String aName,
in AString aContractId, in long aIndex);
/**
* Removes a folder from the bookmarks tree.
*
* NOTE: This API is deprecated. The correct method to use is removeItem.
* This will be removed in the next release after Firefox 3.0. The
* removal is in bug 428558.
*
* @param aFolder
* The id of the folder to remove.
*/
void removeFolder(in long long aFolder);
/**
* Gets an undo-able transaction for removing a folder from the bookmarks
* tree.
* @param folder
* @param aItemId
* The id of the folder to remove.
* @return An object implementing nsITransaction that can be used to undo
* or redo the action.
@ -298,21 +311,21 @@ interface nsINavBookmarksService : nsISupports
* specific IDs (potentially dangerous if abused by other code!) in the
* public API.
*/
nsITransaction getRemoveFolderTransaction(in long long aFolder);
nsITransaction getRemoveFolderTransaction(in long long aItemId);
/**
* Convenience function for container services. Removes
* all children of the given folder.
* @param aFolder
* @param aItemId
* The id of the folder to remove children from.
*/
void removeFolderChildren(in long long aFolder);
void removeFolderChildren(in long long aItemId);
/**
* Moves an item to a different container, preserving its contents.
* @param aItemId
* The id of the item to move
* @param aNewParent
* @param aNewParentId
* The id of the new parent
* @param aIndex
* The index under aNewParent, or DEFAULT_INDEX to append
@ -321,48 +334,29 @@ interface nsINavBookmarksService : nsISupports
* removal of the original item. If you want to move from index X to
* index Y > X you must use moveItem(id, folder, Y + 1)
*/
void moveItem(in long long aItemId, in long long aNewParent, in long aIndex);
/**
* Returns the ID of a child folder with the given name. This does not
* recurse, you have to give it an immediate sibling of the given folder.
* If the given subfolder doesn't exist, it will return 0.
* @param aFolder
* Parent folder whose children we will search
* @param aSubFolder
* Name of the folder to search for in folder
*/
long long getChildFolder(in long long aFolder, in AString aSubFolder);
void moveItem(in long long aItemId, in long long aNewParentId, in long aIndex);
/**
* Inserts a bookmark separator into the given folder at the given index.
* The separator can be removed using removeChildAt().
* @param aFolder
* Parent folder of the separator
* @param aParentId
* The id of the parent folder
* @param aIndex
* The separator's index under folder, or DEFAULT_INDEX to append
* @return The ID of the new separator.
*/
long long insertSeparator(in long long aFolder, in long aIndex);
/**
* Removes any type of child (item, folder, or separator) at the given index.
* @param aFolder
* The folder to remove a child from
* @param aIndex
* The index of the child to remove
*/
void removeChildAt(in long long aFolder, in long aIndex);
long long insertSeparator(in long long aParentId, in long aIndex);
/**
* Get the itemId given the containing folder and the index.
* @param aFolder
* The direct parent folder of the item
* @param aParentId
* The id of the diret parent folder of the item
* @param aIndex
* The index of the item within aFolder, DEFAULT_INDEX for the last item
* The index of the item within the parent folder.
* Pass DEFAULT_INDEX for the last item.
* @return The ID of the found item, -1 if the item does not exists.
*/
long long getIdForItemAt(in long long aFolder, in long aIndex);
long long getIdForItemAt(in long long aParentId, in long aIndex);
/**
* Get a globally unique identifier for an item, meant to be used in
@ -479,10 +473,10 @@ interface nsINavBookmarksService : nsISupports
* or reorder children in this folder. The default for all folders is false.
* Note: This does not restrict API calls, only UI actions.
*
* @param aFolder
* @param aItemId
* the item-id of the folder.
*/
boolean getFolderReadonly(in long long aFolder);
boolean getFolderReadonly(in long long aItemId);
/**
* Sets or unsets the readonly flag from a folder.

View File

@ -21,6 +21,9 @@
*
* Contributor(s):
* Brett Wilson <brett@gmail.com>
* Dietrich Ayala <dietrich@mozilla.com>
* Marco Bonardo <mak77@bonardo.net>
* Asaf Romano <mano@mozilla.com>
*
* 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
@ -55,9 +58,8 @@ interface nsINavHistoryQueryOptions;
interface nsINavHistoryResult;
interface nsINavHistoryBatchCallback;
interface nsITreeColumn;
interface nsIWritablePropertyBag;
[scriptable, uuid(47cf89e3-4777-46bf-9677-21793870ce62)]
[scriptable, uuid(464ae28f-3a9c-4483-afb2-bb0fb0ddb893)]
interface nsINavHistoryResultNode : nsISupports
{
/**
@ -133,7 +135,7 @@ interface nsINavHistoryResultNode : nsISupports
* default favicon. If the favicon originally lived in chrome, this will
* be the original chrome URI of the icon.
*/
readonly attribute nsIURI icon;
readonly attribute AUTF8String icon;
/**
* This is the number of levels between this node and the top of the
@ -143,25 +145,6 @@ interface nsINavHistoryResultNode : nsISupports
*/
readonly attribute long indentLevel;
/**
* Value with undefined meaning for use by the view. Its initial value will
* be -1. The result implementation treats nodes with this property set to
* -1 as invisible!
*
* View-implementations may use this value to track the node index in the
* view, e.g. the tree view uses this value to indicate the row in the
* tree that this node is at. Other views may choose not to use this, but
* should inititalize this value to anything but -1 for visible nodes.
*/
attribute long viewIndex;
/**
* You can use this to associate temporary information with the result node.
* This property bag is associated with the result node and is not persisted
* in any way.
*/
readonly attribute nsIWritablePropertyBag propertyBag;
/**
* When this item is in a bookmark folder (parent is of type folder), this is
* the index into that folder of this node. These indices start at 0 and
@ -441,8 +424,8 @@ interface nsINavHistoryResultViewer : nsISupports
* The item previously at index (if any) and everything below it will have
* been shifted down by one. The item may be a container or a leaf.
*/
void itemInserted(in nsINavHistoryContainerResultNode aParent,
in nsINavHistoryResultNode aItem,
void nodeInserted(in nsINavHistoryContainerResultNode aParent,
in nsINavHistoryResultNode aNode,
in unsigned long aNewIndex);
/**
@ -451,7 +434,7 @@ interface nsINavHistoryResultViewer : nsISupports
* has been removed from its parent list, but before anything else (including
* NULLing out the item's parent) has happened.
*/
void itemRemoved(in nsINavHistoryContainerResultNode aParent,
void nodeRemoved(in nsINavHistoryContainerResultNode aParent,
in nsINavHistoryResultNode aItem,
in unsigned long aOldIndex);
@ -464,53 +447,158 @@ interface nsINavHistoryResultViewer : nsISupports
* a new node is created for the item, and the itemRemoved/itemAdded methods
* are used.
*/
void itemMoved(in nsINavHistoryResultNode aItem,
void nodeMoved(in nsINavHistoryResultNode aNode,
in nsINavHistoryContainerResultNode aOldParent,
in unsigned long aOldIndex,
in nsINavHistoryContainerResultNode aNewParent,
in unsigned long aNewIndex);
/**
* Called when an item has been changed and should be repainted. This only
* refers to the specific item. If it is a container, getting this message
* does not imply anything happened to the children. You'll get separate
* messages for those. Also, this may be called for container nodes at times
* when the result thinks it's possible that a twisty mey need to bw redrawn.
* Called right after aNode's title has changed.
*
* @param aNode
* a result node
* @param aNewTitle
* the new title
*/
void itemChanged(in nsINavHistoryResultNode item);
void nodeTitleChanged(in nsINavHistoryResultNode aNode,
in AUTF8String aNewTitle);
/**
* Called right after aNode's uri property has changed.
*
* @param aNode
* a result node
* @param aNewURI
* the new uri
*/
void nodeURIChanged(in nsINavHistoryResultNode aNode,
in AUTF8String aNewURI);
/**
* Called right after aNode's icon property has changed.
*
* @param aNode
* a result node
*
* @note: The new icon is accessible through aNode.icon.
*/
void nodeIconChanged(in nsINavHistoryResultNode aNode);
/**
* Called right after aNode's time property or accessCount property, or both,
* have changed.
*
* @param aNode
* a uri result node
* @param aNewVisitDate
* the new visit date
* @param aNewAccessCount
* the new access-count
*/
void nodeHistoryDetailsChanged(in nsINavHistoryResultNode aNode,
in PRTime aNewVisitDate,
in unsigned long aNewAccessCount);
/**
* Called when the tags set on the uri represented by aNode have changed.
*
* @param aNode
* a uri result node
*
* @note: The new tags list is accessible through aNode.tags.
*/
void nodeTagsChanged(in nsINavHistoryResultNode aNode);
/**
* Called right after the aNode's keyword property has changed.
*
* @param aNode
* a uri result node
* @param aNewKeyword
* the new keyword
*/
void nodeKeywordChanged(in nsINavHistoryResultNode aNode,
in AUTF8String aNewKeyword);
/**
* Called right after an annotation of aNode's has changed (set, altered, or
* unset).
*
* @param aNode
* a result node
* @param aAnnoName
* the name of the annotation that changed
*/
void nodeAnnotationChanged(in nsINavHistoryResultNode aNode,
in AUTF8String aAnnoName);
/**
* Called right after aNode's dateAdded property has changed.
*
* @param aNode
* a result node
* @param aNewValue
* the new value of the dateAdded property
*/
void nodeDateAddedChanged(in nsINavHistoryResultNode aNode,
in PRTime aNewValue);
/**
* Called right after aNode's dateModified property has changed.
*
* @param aNode
* a result node
* @param aNewValue
* the new value of the dateModified property
*/
void nodeLastModifiedChanged(in nsINavHistoryResultNode aNode,
in PRTime aNewValue);
/**
* Called when an item is being replaced with another item at the exact
* same position.
*
* @param aParentNode
* the parent node of the node which is being replaced
* @param aOldNode
* the node which is being replaced
* @param aNewNode
* the new node
* @param aParentNode
* the index in aParentNode, at which a node is being replaced
*/
void itemReplaced(in nsINavHistoryContainerResultNode parent,
in nsINavHistoryResultNode oldItem,
in nsINavHistoryResultNode newItem,
in unsigned long index);
void nodeReplaced(in nsINavHistoryContainerResultNode aParentNode,
in nsINavHistoryResultNode aOldNode,
in nsINavHistoryResultNode aNewNode,
in unsigned long aIndex);
/**
* Called after a container node went from closed to opened.
*
* @param aContainerNode
* the container node which was opened
*/
void containerOpened(in nsINavHistoryContainerResultNode item);
void containerOpened(in nsINavHistoryContainerResultNode aContainerNode);
/**
* Called after a container node went from opened to closed. This will be
* called for the topmost container that is closing, and implies that any
* child containers have closed as well.
*
* @param aContainerNode
* the container node which was closed
*/
void containerClosed(in nsINavHistoryContainerResultNode item);
void containerClosed(in nsINavHistoryContainerResultNode aContainerNode);
/**
* Called when something significant has happened within the container. The
* contents of the container should be re-built.
*
* @param aContainerNode
* the container node to invalidate
*/
void invalidateContainer(in nsINavHistoryContainerResultNode item);
/**
* Called when something significant is changing that requires everything
* to be recomputed. For example, changing sorting can affect every row.
*/
void invalidateAll();
void invalidateContainer(in nsINavHistoryContainerResultNode aContainerNode);
/**
* This is called to indicate to the UI that the sort has changed to the
@ -536,6 +624,8 @@ interface nsINavHistoryResultViewer : nsISupports
/**
* TODO: Bug 517719.
*
* A predefined view adaptor for interfacing results with an nsITree. This
* object will remove itself from its associated result when the tree has been
* detached. This prevents circular references. Users should be aware of this,
@ -904,7 +994,7 @@ interface nsINavHistoryQuery : nsISupports
/**
* This object represents the global options for executing a query.
*/
[scriptable, uuid(b3d5de06-f8ef-4433-84c2-b8b237403b2a)]
[scriptable, uuid(c6831388-fd4c-46a8-85f3-952917b66d72)]
interface nsINavHistoryQueryOptions : nsISupports
{
/**
@ -1104,12 +1194,6 @@ interface nsINavHistoryQueryOptions : nsISupports
*/
attribute unsigned short redirectsMode;
/**
* Separate/group history items based on session information. Only
* matters when sorting by date.
*/
attribute boolean showSessions;
/**
* This is the maximum number of results that you want. The query is exeucted,
* the results are sorted, and then the top 'maxResults' results are taken

View File

@ -478,7 +478,7 @@ LivemarkService.prototype = {
onItemMoved: function() { },
onBeforeItemRemoved: function() { },
onItemRemoved: function(aItemId, aParentId, aIndex) {
onItemRemoved: function(aItemId, aParentId, aIndex, aItemType) {
// we don't need to remove annotations since itemAnnotations
// are already removed with the bookmark
try {

View File

@ -1186,7 +1186,7 @@ nsNavBookmarks::InsertBookmark(PRInt64 aFolder,
AddBookmarkToHash(childID, 0);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemAdded(*aNewBookmarkId, aFolder, index))
OnItemAdded(*aNewBookmarkId, aFolder, index, TYPE_BOOKMARK))
// If the bookmark has been added to a tag container, notify all
// bookmark-folder result nodes which contain a bookmark for the new
@ -1204,8 +1204,12 @@ nsNavBookmarks::InsertBookmark(PRInt64 aFolder,
if (bookmarks.Length()) {
for (PRUint32 i = 0; i < bookmarks.Length(); i++) {
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(bookmarks[i], NS_LITERAL_CSTRING("tags"),
PR_FALSE, EmptyCString()))
OnItemChanged(bookmarks[i],
NS_LITERAL_CSTRING("tags"),
PR_FALSE,
EmptyCString(),
0,
TYPE_BOOKMARK))
}
}
}
@ -1252,7 +1256,7 @@ nsNavBookmarks::RemoveItem(PRInt64 aItemId)
}
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnBeforeItemRemoved(aItemId))
OnBeforeItemRemoved(aItemId, itemType))
mozStorageTransaction transaction(mDBConn, PR_FALSE);
@ -1291,7 +1295,7 @@ nsNavBookmarks::RemoveItem(PRInt64 aItemId)
}
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemRemoved(aItemId, folderId, childIndex))
OnItemRemoved(aItemId, folderId, childIndex, itemType))
if (itemType == TYPE_BOOKMARK) {
// If the removed bookmark was a child of a tag container, notify all
@ -1312,8 +1316,12 @@ nsNavBookmarks::RemoveItem(PRInt64 aItemId)
if (bookmarks.Length()) {
for (PRUint32 i = 0; i < bookmarks.Length(); i++) {
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(bookmarks[i], NS_LITERAL_CSTRING("tags"),
PR_FALSE, EmptyCString()))
OnItemChanged(bookmarks[i],
NS_LITERAL_CSTRING("tags"),
PR_FALSE,
EmptyCString(),
0,
TYPE_BOOKMARK))
}
}
}
@ -1422,7 +1430,7 @@ nsNavBookmarks::CreateContainerWithID(PRInt64 aItemId, PRInt64 aParent,
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemAdded(*aNewFolder, aParent, index))
OnItemAdded(*aNewFolder, aParent, index, containerType))
*aIndex = index;
return NS_OK;
@ -1466,7 +1474,7 @@ nsNavBookmarks::InsertSeparator(PRInt64 aParent, PRInt32 aIndex,
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemAdded(*aNewItemId, aParent, index))
OnItemAdded(*aNewItemId, aParent, index, TYPE_SEPARATOR))
return NS_OK;
}
@ -1531,52 +1539,6 @@ nsNavBookmarks::GetIdForItemAt(PRInt64 aFolder, PRInt32 aIndex, PRInt64* aItemId
return NS_OK;
}
NS_IMETHODIMP
nsNavBookmarks::RemoveChildAt(PRInt64 aParent, PRInt32 aIndex)
{
NS_ENSURE_ARG_MIN(aParent, 1);
mozStorageTransaction transaction(mDBConn, PR_FALSE);
nsresult rv;
PRInt64 id;
PRInt32 type;
{
mozStorageStatementScoper scope(mDBGetChildAt);
rv = mDBGetChildAt->BindInt64Parameter(0, aParent);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBGetChildAt->BindInt32Parameter(1, aIndex);
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasMore;
rv = mDBGetChildAt->ExecuteStep(&hasMore);
NS_ENSURE_SUCCESS(rv, rv);
if (!hasMore) {
// Child doesn't exist
return NS_ERROR_INVALID_ARG;
}
id = mDBGetChildAt->AsInt64(0);
type = mDBGetChildAt->AsInt32(2);
}
if (type == TYPE_BOOKMARK || type == TYPE_SEPARATOR) {
// Commit this transaction so that we don't notify observers mid-tranaction
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
return RemoveItem(id);
}
else if (type == TYPE_FOLDER) {
// Commit this transaction so that we don't notify observers mid-tranaction
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
return RemoveFolder(id);
}
return NS_ERROR_INVALID_ARG;
}
nsresult
nsNavBookmarks::GetParentAndIndexOfFolder(PRInt64 aFolder, PRInt64* aParent,
PRInt32* aIndex)
@ -1602,13 +1564,13 @@ nsNavBookmarks::GetParentAndIndexOfFolder(PRInt64 aFolder, PRInt64* aParent,
return NS_OK;
}
NS_IMETHODIMP
NS_HIDDEN_(nsresult)
nsNavBookmarks::RemoveFolder(PRInt64 aFolderId)
{
NS_ENSURE_TRUE(aFolderId != mRoot, NS_ERROR_INVALID_ARG);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnBeforeItemRemoved(aFolderId))
OnBeforeItemRemoved(aFolderId, TYPE_FOLDER))
mozStorageTransaction transaction(mDBConn, PR_FALSE);
@ -1682,7 +1644,7 @@ nsNavBookmarks::RemoveFolder(PRInt64 aFolderId)
}
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemRemoved(aFolderId, parent, index))
OnItemRemoved(aFolderId, parent, index, TYPE_FOLDER))
return NS_OK;
}
@ -1803,7 +1765,7 @@ nsNavBookmarks::RemoveFolderChildren(PRInt64 aFolderId)
// Notify observers that we are about to remove this child.
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnBeforeItemRemoved(child.itemId))
OnBeforeItemRemoved(child.itemId, child.itemType))
if (child.itemType == TYPE_FOLDER) {
foldersToRemove.AppendLiteral(",");
@ -1878,7 +1840,8 @@ nsNavBookmarks::RemoveFolderChildren(PRInt64 aFolderId)
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemRemoved(child.itemId,
child.parentId,
child.index));
child.index,
child.itemType));
if (child.itemType == TYPE_BOOKMARK) {
// If the removed bookmark was a child of a tag container, notify all
@ -1897,8 +1860,12 @@ nsNavBookmarks::RemoveFolderChildren(PRInt64 aFolderId)
if (bookmarks.Length()) {
for (PRUint32 i = 0; i < bookmarks.Length(); i++) {
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(bookmarks[i], NS_LITERAL_CSTRING("tags"),
PR_FALSE, EmptyCString()))
OnItemChanged(bookmarks[i],
NS_LITERAL_CSTRING("tags"),
PR_FALSE,
EmptyCString(),
0,
TYPE_BOOKMARK))
}
}
}
@ -2059,7 +2026,7 @@ nsNavBookmarks::MoveItem(PRInt64 aItemId, PRInt64 aNewParent, PRInt32 aIndex)
// notify bookmark observers
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemMoved(aItemId, oldParent, oldIndex, aNewParent,
newIndex))
newIndex, itemType))
// notify dynamic container provider if there is one
if (!folderType.IsEmpty()) {
@ -2073,41 +2040,6 @@ nsNavBookmarks::MoveItem(PRInt64 aItemId, PRInt64 aNewParent, PRInt32 aIndex)
return NS_OK;
}
NS_IMETHODIMP
nsNavBookmarks::GetChildFolder(PRInt64 aFolder, const nsAString& aSubFolder,
PRInt64* _result)
{
// note: we allow empty folder names
nsresult rv;
if (aFolder == 0)
return NS_ERROR_INVALID_ARG;
// If this gets used a lot, we'll want a precompiled statement
nsCAutoString getChildFolderQuery =
NS_LITERAL_CSTRING("SELECT id "
"FROM moz_bookmarks "
"WHERE parent = ?1 AND type = ") +
nsPrintfCString("%d", TYPE_FOLDER) +
NS_LITERAL_CSTRING(" AND title = ?2");
nsCOMPtr<mozIStorageStatement> statement;
rv = mDBConn->CreateStatement(getChildFolderQuery, getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
statement->BindInt64Parameter(0, aFolder);
statement->BindStringParameter(1, aSubFolder);
PRBool hasResult = PR_FALSE;
rv = statement->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, rv);
if (! hasResult) {
// item not found
*_result = 0;
return NS_OK;
}
return statement->GetInt64(0, _result);
}
nsresult
nsNavBookmarks::SetItemDateInternal(mozIStorageStatement* aStatement, PRInt64 aItemId, PRTime aValue)
{
@ -2129,14 +2061,21 @@ nsNavBookmarks::SetItemDateInternal(mozIStorageStatement* aStatement, PRInt64 aI
NS_IMETHODIMP
nsNavBookmarks::SetItemDateAdded(PRInt64 aItemId, PRTime aDateAdded)
{
NS_ENSURE_ARG_MIN(aItemId, 1);
nsresult rv = SetItemDateInternal(mDBSetItemDateAdded, aItemId, aDateAdded);
// GetItemType also ensures that aItemId points to a valid item.
PRUint16 itemType;
nsresult rv = GetItemType(aItemId, &itemType);
NS_ENSURE_SUCCESS(rv, rv);
rv = SetItemDateInternal(mDBSetItemDateAdded, aItemId, aDateAdded);
NS_ENSURE_SUCCESS(rv, rv);
// Note: mDBSetItemDateAdded also sets lastModified to aDateAdded.
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(aItemId, NS_LITERAL_CSTRING("dateAdded"),
PR_FALSE, nsPrintfCString(16, "%lld", aDateAdded)));
PR_FALSE,
nsPrintfCString(16, "%lld", aDateAdded),
aDateAdded,
itemType));
return NS_OK;
}
@ -2163,14 +2102,21 @@ nsNavBookmarks::GetItemDateAdded(PRInt64 aItemId, PRTime *aDateAdded)
NS_IMETHODIMP
nsNavBookmarks::SetItemLastModified(PRInt64 aItemId, PRTime aLastModified)
{
NS_ENSURE_ARG_MIN(aItemId, 1);
// GetItemType also ensures that aItemId points to a valid item.
PRUint16 itemType;
nsresult rv = GetItemType(aItemId, &itemType);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = SetItemDateInternal(mDBSetItemLastModified, aItemId, aLastModified);
rv = SetItemDateInternal(mDBSetItemLastModified, aItemId, aLastModified);
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(aItemId, NS_LITERAL_CSTRING("lastModified"),
PR_FALSE, nsPrintfCString(16, "%lld", aLastModified)));
OnItemChanged(aItemId,
NS_LITERAL_CSTRING("lastModified"),
PR_FALSE,
nsPrintfCString(16, "%lld", aLastModified),
aLastModified,
itemType));
return NS_OK;
}
@ -2279,10 +2225,13 @@ nsNavBookmarks::GetItemIdForGUID(const nsAString &aGUID, PRInt64 *aItemId)
NS_IMETHODIMP
nsNavBookmarks::SetItemTitle(PRInt64 aItemId, const nsACString &aTitle)
{
NS_ENSURE_ARG_MIN(aItemId, 1);
// GetItemType also ensures that aItemId points to a valid item.
PRUint16 itemType;
nsresult rv = GetItemType(aItemId, &itemType);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageStatement> statement;
nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_bookmarks SET title = ?1, lastModified = ?2 WHERE id = ?3"),
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
@ -2302,8 +2251,12 @@ nsNavBookmarks::SetItemTitle(PRInt64 aItemId, const nsACString &aTitle)
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(aItemId, NS_LITERAL_CSTRING("title"),
PR_FALSE, aTitle));
OnItemChanged(aItemId,
NS_LITERAL_CSTRING("title"),
PR_FALSE,
aTitle,
lastModified,
itemType));
return NS_OK;
}
@ -2699,7 +2652,8 @@ nsNavBookmarks::ChangeBookmarkURI(PRInt64 aBookmarkId, nsIURI *aNewURI)
// Pass the new URI to OnItemChanged.
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(aBookmarkId, NS_LITERAL_CSTRING("uri"), PR_FALSE, spec))
OnItemChanged(aBookmarkId, NS_LITERAL_CSTRING("uri"), PR_FALSE, spec,
lastModified, TYPE_BOOKMARK))
return NS_OK;
}
@ -2813,6 +2767,7 @@ nsNavBookmarks::SetItemIndex(PRInt64 aItemId, PRInt32 aNewIndex)
nsresult rv;
PRInt32 oldIndex = 0;
PRInt64 parent = 0;
PRUint16 itemType;
{
mozStorageStatementScoper scopeGet(mDBGetItemProperties);
@ -2826,6 +2781,7 @@ nsNavBookmarks::SetItemIndex(PRInt64 aItemId, PRInt32 aNewIndex)
return NS_OK;
oldIndex = mDBGetItemProperties->AsInt32(kGetItemPropertiesIndex_Position);
itemType = (PRUint16)mDBGetItemProperties->AsInt32(kGetItemPropertiesIndex_Type);
parent = mDBGetItemProperties->AsInt64(kGetItemPropertiesIndex_Parent);
}
@ -2844,14 +2800,9 @@ nsNavBookmarks::SetItemIndex(PRInt64 aItemId, PRInt32 aNewIndex)
rv = mDBSetItemIndex->Execute();
NS_ENSURE_SUCCESS(rv, rv);
// XXX (bug 484096) this is really inefficient and we should look into using
// onItemChanged here!
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnBeforeItemRemoved(aItemId))
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemRemoved(aItemId, parent, oldIndex))
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemAdded(aItemId, parent, aNewIndex))
OnItemMoved(aItemId, parent, oldIndex, parent,
aNewIndex, itemType))
return NS_OK;
}
@ -2939,7 +2890,8 @@ nsNavBookmarks::SetKeywordForBookmark(PRInt64 aBookmarkId, const nsAString& aKey
// Pass the new keyword to OnItemChanged.
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(aBookmarkId, NS_LITERAL_CSTRING("keyword"),
PR_FALSE, NS_ConvertUTF16toUTF8(aKeyword)))
PR_FALSE, NS_ConvertUTF16toUTF8(aKeyword),
lastModified, TYPE_BOOKMARK))
return NS_OK;
}
@ -3142,8 +3094,12 @@ nsNavBookmarks::OnDeleteURI(nsIURI *aURI)
if (bookmarks.Length()) {
for (PRUint32 i = 0; i < bookmarks.Length(); i ++)
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(bookmarks[i], NS_LITERAL_CSTRING("cleartime"),
PR_FALSE, EmptyCString()))
OnItemChanged(bookmarks[i],
NS_LITERAL_CSTRING("cleartime"),
PR_FALSE,
EmptyCString(),
0,
TYPE_BOOKMARK))
}
}
return NS_OK;
@ -3191,8 +3147,12 @@ nsNavBookmarks::OnPageChanged(nsIURI *aURI, PRUint32 aWhat,
NS_ENSURE_STATE(queries[0]->Folders().Length() == 1);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(queries[0]->Folders()[0], NS_LITERAL_CSTRING("favicon"),
PR_FALSE, NS_ConvertUTF16toUTF8(aValue)));
OnItemChanged(queries[0]->Folders()[0],
NS_LITERAL_CSTRING("favicon"),
PR_FALSE,
NS_ConvertUTF16toUTF8(aValue),
0,
TYPE_BOOKMARK));
}
else {
// query for all bookmarks for that URI, notify for each
@ -3203,8 +3163,12 @@ nsNavBookmarks::OnPageChanged(nsIURI *aURI, PRUint32 aWhat,
if (bookmarks.Length()) {
for (PRUint32 i = 0; i < bookmarks.Length(); i ++)
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(bookmarks[i], NS_LITERAL_CSTRING("favicon"),
PR_FALSE, NS_ConvertUTF16toUTF8(aValue)));
OnItemChanged(bookmarks[i],
NS_LITERAL_CSTRING("favicon"),
PR_FALSE,
NS_ConvertUTF16toUTF8(aValue),
0,
TYPE_BOOKMARK));
}
}
}
@ -3230,11 +3194,19 @@ nsNavBookmarks::OnPageAnnotationSet(nsIURI* aPage, const nsACString& aName)
NS_IMETHODIMP
nsNavBookmarks::OnItemAnnotationSet(PRInt64 aItemId, const nsACString& aName)
{
nsresult rv = SetItemDateInternal(mDBSetItemLastModified, aItemId, PR_Now());
// GetItemType also ensures that aItemId points to a valid item.
PRUint16 itemType;
nsresult rv = GetItemType(aItemId, &itemType);
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(aItemId, aName, PR_TRUE, EmptyCString()));
PRTime lastModified = PR_Now();
rv = SetItemDateInternal(mDBSetItemLastModified, aItemId, lastModified);
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavBookmarkObserver,
OnItemChanged(aItemId, aName, PR_TRUE, EmptyCString(),
lastModified, itemType));
return NS_OK;
}
@ -3249,11 +3221,19 @@ nsNavBookmarks::OnPageAnnotationRemoved(nsIURI* aPage, const nsACString& aName)
NS_IMETHODIMP
nsNavBookmarks::OnItemAnnotationRemoved(PRInt64 aItemId, const nsACString& aName)
{
nsresult rv = SetItemDateInternal(mDBSetItemLastModified, aItemId, PR_Now());
// GetItemType also ensures that aItemId points to a valid item.
PRUint16 itemType;
nsresult rv = GetItemType(aItemId, &itemType);
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(aItemId, aName, PR_TRUE, EmptyCString()));
PRTime lastModified = PR_Now();
rv = SetItemDateInternal(mDBSetItemLastModified, aItemId, lastModified);
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavBookmarkObserver,
OnItemChanged(aItemId, aName, PR_TRUE, EmptyCString(),
lastModified, itemType));
return NS_OK;
}

View File

@ -135,6 +135,8 @@ private:
PRInt32 aStartIndex, PRInt32 aEndIndex,
PRInt32 aDelta);
NS_HIDDEN_(nsresult) RemoveFolder(PRInt64 aFolderId);
/**
* Calculates number of children for the given folder.
*

View File

@ -170,7 +170,6 @@ static void SetOptionsKeyUint32(const nsCString& aValue,
#define QUERYKEY_FORCE_ORIGINAL_TITLE "originalTitle"
#define QUERYKEY_INCLUDE_HIDDEN "includeHidden"
#define QUERYKEY_REDIRECTS_MODE "redirectsMode"
#define QUERYKEY_SHOW_SESSIONS "showSessions"
#define QUERYKEY_MAX_RESULTS "maxResults"
#define QUERYKEY_QUERY_TYPE "queryType"
#define QUERYKEY_TAG "tag"
@ -602,12 +601,6 @@ nsNavHistory::QueriesToQueryString(nsINavHistoryQuery **aQueries,
AppendInt16(queryString, options->RedirectsMode());
}
// show sessions
if (options->ShowSessions()) {
AppendAmpersandIfNonempty(queryString);
queryString += NS_LITERAL_CSTRING(QUERYKEY_SHOW_SESSIONS "=1");
}
// max results
if (options->MaxResults()) {
AppendAmpersandIfNonempty(queryString);
@ -869,10 +862,6 @@ nsNavHistory::TokensToQueries(const nsTArray<QueryKeyValuePair>& aTokens,
} else if (kvp.key.EqualsLiteral(QUERYKEY_REDIRECTS_MODE)) {
SetOptionsKeyUint16(kvp.value, aOptions,
&nsINavHistoryQueryOptions::SetRedirectsMode);
// show sessions
} else if (kvp.key.EqualsLiteral(QUERYKEY_SHOW_SESSIONS)) {
SetOptionsKeyBool(kvp.value, aOptions,
&nsINavHistoryQueryOptions::SetShowSessions);
// max results
} else if (kvp.key.EqualsLiteral(QUERYKEY_MAX_RESULTS)) {
SetOptionsKeyUint32(kvp.value, aOptions,
@ -1498,20 +1487,6 @@ nsNavHistoryQueryOptions::SetRedirectsMode(PRUint16 aRedirectsMode)
return NS_OK;
}
// showSessions
NS_IMETHODIMP
nsNavHistoryQueryOptions::GetShowSessions(PRBool* aShowSessions)
{
*aShowSessions = mShowSessions;
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryOptions::SetShowSessions(PRBool aShowSessions)
{
mShowSessions = aShowSessions;
return NS_OK;
}
// maxResults
NS_IMETHODIMP
nsNavHistoryQueryOptions::GetMaxResults(PRUint32* aMaxResults)
@ -1567,7 +1542,6 @@ nsNavHistoryQueryOptions::Clone(nsNavHistoryQueryOptions **aResult)
result->mResultType = mResultType;
result->mExcludeItems = mExcludeItems;
result->mExcludeQueries = mExcludeQueries;
result->mShowSessions = mShowSessions;
result->mExpandQueries = mExpandQueries;
result->mMaxResults = mMaxResults;
result->mQueryType = mQueryType;

View File

@ -55,10 +55,11 @@
#include "prprf.h"
#include "nsIDynamicContainer.h"
#include "nsHashPropertyBag.h"
#include "nsIWritablePropertyBag.h"
#include "mozStorageHelper.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIClassInfo.h"
#include "nsIProgrammingLanguage.h"
#include "nsIXPCScriptable.h"
// What we want is: NS_INTERFACE_MAP_ENTRY(self) for static IID accessors,
// but some of our classes (like nsNavHistoryResult) have an ambiguous base
@ -86,10 +87,115 @@ inline PRInt32 CompareIntegers(PRUint32 a, PRUint32 b)
return a - b;
}
namespace mozilla {
namespace places {
// Class-info and the scriptable helper are implemented in order to
// allow the JS frontend code to set expando properties on result nodes.
class ResultNodeClassInfo : public nsIClassInfo
, public nsIXPCScriptable
{
NS_DECL_ISUPPORTS
NS_DECL_NSIXPCSCRIPTABLE
// TODO: Bug 517718.
NS_IMETHODIMP
GetInterfaces(PRUint32 *_count, nsIID ***_array)
{
*_count = 0;
*_array = nsnull;
return NS_OK;
}
NS_IMETHODIMP
GetHelperForLanguage(PRUint32 aLanguage, nsISupports **_helper)
{
if (aLanguage == nsIProgrammingLanguage::JAVASCRIPT) {
*_helper = static_cast<nsIXPCScriptable *>(this);
NS_ADDREF(*_helper);
}
else
*_helper = nsnull;
return NS_OK;
}
NS_IMETHODIMP
GetContractID(char **_contractID)
{
*_contractID = nsnull;
return NS_OK;
}
NS_IMETHODIMP
GetClassDescription(char **_desc)
{
*_desc = nsnull;
return NS_OK;
}
NS_IMETHODIMP
GetClassID(nsCID **_id)
{
*_id = nsnull;
return NS_OK;
}
NS_IMETHODIMP
GetImplementationLanguage(PRUint32 *_language)
{
*_language = nsIProgrammingLanguage::CPLUSPLUS;
return NS_OK;
}
NS_IMETHODIMP
GetFlags(PRUint32 *_flags)
{
*_flags = 0;
return NS_OK;
}
NS_IMETHODIMP
GetClassIDNoAlloc(nsCID *_cid)
{
return NS_ERROR_NOT_AVAILABLE;
}
};
/**
* As a static implementation of classinfo, we violate XPCOM rules andjust
* pretend to use the refcount mechanism. See classinfo documentation at
* https://developer.mozilla.org/en/Using_nsIClassInfo
*/
NS_IMETHODIMP_(nsrefcnt) ResultNodeClassInfo::AddRef()
{
return 2;
}
NS_IMETHODIMP_(nsrefcnt) ResultNodeClassInfo::Release()
{
return 1;
}
NS_IMPL_QUERY_INTERFACE2(ResultNodeClassInfo, nsIClassInfo, nsIXPCScriptable)
#define XPC_MAP_CLASSNAME ResultNodeClassInfo
#define XPC_MAP_QUOTED_CLASSNAME "ResultNodeClassInfo"
#define XPC_MAP_FLAGS nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY | \
nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY | \
nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY
// xpc_map_end contains implementation for nsIXPCScriptable, that used the
// constant define above
#include "xpc_map_end.h"
static ResultNodeClassInfo sResultNodeClassInfo;
} // namespace places
} // namespace mozilla
using namespace mozilla::places;
// nsNavHistoryResultNode ******************************************************
NS_IMPL_CYCLE_COLLECTION_CLASS(nsNavHistoryResultNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsNavHistoryResultNode)
@ -102,6 +208,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNavHistoryResultNode)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsINavHistoryResultNode)
if (aIID.Equals(NS_GET_IID(nsIClassInfo)))
foundInterface = static_cast<nsIClassInfo *>(&mozilla::places::sResultNodeClassInfo);
else
NS_INTERFACE_MAP_ENTRY(nsINavHistoryResultNode)
NS_INTERFACE_MAP_END
@ -121,22 +230,23 @@ nsNavHistoryResultNode::nsNavHistoryResultNode(
mItemId(-1),
mDateAdded(0),
mLastModified(0),
mIndentLevel(-1),
mViewIndex(-1)
mIndentLevel(-1)
{
mTags.SetIsVoid(PR_TRUE);
}
NS_IMETHODIMP
nsNavHistoryResultNode::GetIcon(nsIURI** aURI)
nsNavHistoryResultNode::GetIcon(nsACString& aIcon)
{
if (mFaviconURI.IsEmpty()) {
*aURI = nsnull;
aIcon.Truncate();
return NS_OK;
}
nsFaviconService* faviconService = nsFaviconService::GetFaviconService();
NS_ENSURE_TRUE(faviconService, NS_ERROR_OUT_OF_MEMORY);
return faviconService->GetFaviconLinkForIconString(mFaviconURI, aURI);
faviconService->GetFaviconSpecForIconString(mFaviconURI, aIcon);
return NS_OK;
}
NS_IMETHODIMP
@ -212,15 +322,6 @@ nsNavHistoryResultNode::GetTags(nsAString& aTags) {
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryResultNode::GetPropertyBag(nsIWritablePropertyBag** aBag)
{
nsNavHistoryResult* result = GetResult();
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
return result->PropertyBagFor(this, aBag);
}
// nsNavHistoryResultNode::OnRemoving
//
// This will zero out some values in case somebody still holds a reference
@ -229,7 +330,6 @@ void
nsNavHistoryResultNode::OnRemoving()
{
mParent = nsnull;
mViewIndex = -1;
}
@ -401,30 +501,30 @@ nsNavHistoryContainerResultNode::OnRemoving()
// nsNavHistoryContainerResultNode::AreChildrenVisible
//
// Folders can't always depend on their mViewIndex value to determine if
// their children are visible because they can be root nodes. Root nodes
// are visible if a tree is attached to the result.
PRBool
nsNavHistoryContainerResultNode::AreChildrenVisible()
{
// can't see children when we're invisible
if (! mExpanded)
return PR_FALSE;
// easy case, the node itself is visible
if (mViewIndex >= 0)
return PR_TRUE;
nsNavHistoryResult* result = GetResult();
if (! result) {
if (!result) {
NS_NOTREACHED("Invalid result");
return PR_FALSE;
}
if (result->mRootNode == this && result->mView)
return PR_TRUE;
return PR_FALSE;
// can't see children when we're invisible
if (!mExpanded)
return PR_FALSE;
// Now check if any ancestor is closed.
nsNavHistoryContainerResultNode* ancestor = mParent;
while (ancestor) {
if (!ancestor->mExpanded)
return PR_FALSE;
ancestor = ancestor->mParent;
}
return PR_TRUE;
}
@ -603,6 +703,11 @@ void
nsNavHistoryContainerResultNode::ReverseUpdateStats(PRInt32 aAccessCountChange)
{
if (mParent) {
nsNavHistoryResult* result = GetResult();
PRBool shouldUpdateView = result && result->GetView() &&
mParent->mParent &&
mParent->mParent->AreChildrenVisible();
mParent->mAccessCount += aAccessCountChange;
PRBool timeChanged = PR_FALSE;
if (mTime > mParent->mTime) {
@ -610,26 +715,27 @@ nsNavHistoryContainerResultNode::ReverseUpdateStats(PRInt32 aAccessCountChange)
mParent->mTime = mTime;
}
if (shouldUpdateView) {
result->GetView()->NodeHistoryDetailsChanged(
static_cast<nsINavHistoryContainerResultNode*>(mParent),
mParent->mTime,
mParent->mAccessCount);
}
// check sorting, the stats may have caused this node to move if the
// sorting depended on something we are changing.
PRUint16 sortMode = mParent->GetSortType();
PRBool resorted = PR_FALSE;
if (((sortMode == nsINavHistoryQueryOptions::SORT_BY_VISITCOUNT_ASCENDING ||
sortMode == nsINavHistoryQueryOptions::SORT_BY_VISITCOUNT_DESCENDING) &&
aAccessCountChange != 0) ||
((sortMode == nsINavHistoryQueryOptions::SORT_BY_DATE_ASCENDING ||
sortMode == nsINavHistoryQueryOptions::SORT_BY_DATE_DESCENDING) &&
timeChanged)) {
PRBool sortingByVisitCount =
sortMode == nsINavHistoryQueryOptions::SORT_BY_VISITCOUNT_ASCENDING ||
sortMode == nsINavHistoryQueryOptions::SORT_BY_VISITCOUNT_DESCENDING;
PRBool sortingByTime =
sortMode == nsINavHistoryQueryOptions::SORT_BY_DATE_ASCENDING ||
sortMode == nsINavHistoryQueryOptions::SORT_BY_DATE_DESCENDING;
if ((sortingByVisitCount && aAccessCountChange != 0) ||
(sortingByTime && timeChanged)) {
PRUint32 ourIndex = mParent->FindChild(this);
resorted = EnsureItemPosition(ourIndex);
}
if (!resorted) {
// repaint visible rows
nsNavHistoryResult* result = GetResult();
if (result && result->GetView() && mParent->AreChildrenVisible()) {
result->GetView()->ItemChanged(static_cast<nsINavHistoryContainerResultNode*>(mParent));
}
EnsureItemPosition(ourIndex);
}
mParent->ReverseUpdateStats(aAccessCountChange);
@ -1238,29 +1344,6 @@ nsNavHistoryContainerResultNode::FindChildURI(const nsACString& aSpec,
return nsnull;
}
// nsNavHistoryContainerResultNode::FindChildFolder
//
// Searches this folder for the given subfolder. Returns null if not found.
// DOES NOT ADDREF.
nsNavHistoryFolderResultNode*
nsNavHistoryContainerResultNode::FindChildFolder(PRInt64 aFolderId,
PRUint32* aNodeIndex)
{
for (PRInt32 i = 0; i < mChildren.Count(); i ++) {
if (mChildren[i]->IsFolder()) {
nsNavHistoryFolderResultNode* folder = mChildren[i]->GetAsFolder();
if (folder->mItemId == aFolderId) {
*aNodeIndex = i;
return folder;
}
}
}
return nsnull;
}
// nsNavHistoryContainerResultNode::FindChildContainerByName
//
// Searches this container for a subfolder with the given name. This is used
@ -1303,7 +1386,6 @@ nsNavHistoryContainerResultNode::InsertChildAt(nsNavHistoryResultNode* aNode,
nsNavHistoryResult* result = GetResult();
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
aNode->mViewIndex = -1;
aNode->mParent = this;
aNode->mIndentLevel = mIndentLevel + 1;
if (! aIsTemporary && aNode->IsContainer()) {
@ -1322,8 +1404,9 @@ nsNavHistoryContainerResultNode::InsertChildAt(nsNavHistoryResultNode* aNode,
if (mTime < aNode->mTime)
mTime = aNode->mTime;
if (result->GetView() && (!mParent || mParent->AreChildrenVisible()))
result->GetView()->ItemChanged(
static_cast<nsINavHistoryContainerResultNode*>(this));
result->GetView()->NodeHistoryDetailsChanged(
static_cast<nsINavHistoryContainerResultNode*>(this), mTime,
mAccessCount);
ReverseUpdateStats(aNode->mAccessCount);
}
@ -1331,7 +1414,7 @@ nsNavHistoryContainerResultNode::InsertChildAt(nsNavHistoryResultNode* aNode,
// like when there is a bookmark folder being updated because its parent is
// visible.
if (result->GetView() && AreChildrenVisible())
result->GetView()->ItemInserted(this, aNode, aIndex);
result->GetView()->NodeInserted(this, aNode, aIndex);
return NS_OK;
}
@ -1412,7 +1495,7 @@ nsNavHistoryContainerResultNode::EnsureItemPosition(PRUint32 aIndex) {
NS_ENSURE_TRUE(result, PR_TRUE);
if (result->GetView() && AreChildrenVisible())
result->GetView()->ItemMoved(node, this, aIndex, this, newIndex);
result->GetView()->NodeMoved(node, this, aIndex, this, newIndex);
return PR_TRUE;
}
@ -1527,7 +1610,7 @@ nsNavHistoryContainerResultNode::ReplaceChildURIAt(PRUint32 aIndex,
nsNavHistoryResult* result = GetResult();
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
if (result->GetView() && AreChildrenVisible())
result->GetView()->ItemReplaced(this, oldItem, aNode, aIndex);
result->GetView()->NodeReplaced(this, oldItem, aNode, aIndex);
mChildren[aIndex]->OnRemoving();
return NS_OK;
@ -1568,7 +1651,7 @@ nsNavHistoryContainerResultNode::RemoveChildAt(PRInt32 aIndex,
// remove from our list and notify the tree
mChildren.RemoveObjectAt(aIndex);
if (result->GetView() && AreChildrenVisible())
result->GetView()->ItemRemoved(this, oldNode, aIndex);
result->GetView()->NodeRemoved(this, oldNode, aIndex);
if (! aIsTemporary) {
ReverseUpdateStats(mAccessCount - oldAccessCount);
@ -1622,7 +1705,7 @@ nsNavHistoryContainerResultNode::RecursiveFindURIs(PRBool aOnlyOne,
void
nsNavHistoryContainerResultNode::UpdateURIs(PRBool aRecursive, PRBool aOnlyOne,
PRBool aUpdateSort, const nsCString& aSpec,
void (*aCallback)(nsNavHistoryResultNode*,void*), void* aClosure)
void (*aCallback)(nsNavHistoryResultNode*,void*, nsNavHistoryResult*), void* aClosure)
{
nsNavHistoryResult* result = GetResult();
if (! result) {
@ -1663,11 +1746,12 @@ nsNavHistoryContainerResultNode::UpdateURIs(PRBool aRecursive, PRBool aOnlyOne,
NS_NOTREACHED("All URI nodes being updated must have parents");
continue;
}
PRBool childrenVisible = result->GetView() != nsnull && parent->AreChildrenVisible();
PRUint32 oldAccessCount = node->mAccessCount;
PRTime oldTime = node->mTime;
aCallback(node, aClosure);
aCallback(node, aClosure, result);
PRBool childrenVisible = result->GetView() != nsnull && parent->AreChildrenVisible();
if (oldAccessCount != node->mAccessCount || oldTime != node->mTime) {
// need to update/redraw the parent
@ -1675,18 +1759,18 @@ nsNavHistoryContainerResultNode::UpdateURIs(PRBool aRecursive, PRBool aOnlyOne,
if (node->mTime > parent->mTime)
parent->mTime = node->mTime;
if (childrenVisible)
result->GetView()->ItemChanged(
static_cast<nsINavHistoryContainerResultNode*>(parent));
result->GetView()->NodeHistoryDetailsChanged(
static_cast<nsINavHistoryContainerResultNode*>(parent),
parent->mTime,
parent->mAccessCount);
parent->ReverseUpdateStats(node->mAccessCount - oldAccessCount);
}
if (aUpdateSort) {
PRInt32 childIndex = parent->FindChild(node);
if ((childIndex < 0 || !parent->EnsureItemPosition(childIndex) && childrenVisible)) {
result->GetView()->ItemChanged(node);
}
} else if (childrenVisible) {
result->GetView()->ItemChanged(node);
NS_ASSERTION(childIndex >= 0, "Could not find child we just got a reference to");
if (childIndex >= 0)
parent->EnsureItemPosition(childIndex);
}
}
}
@ -1700,10 +1784,16 @@ nsNavHistoryContainerResultNode::UpdateURIs(PRBool aRecursive, PRBool aOnlyOne,
// their own callbacks registered.
static void setTitleCallback(
nsNavHistoryResultNode* aNode, void* aClosure)
nsNavHistoryResultNode* aNode, void* aClosure,
nsNavHistoryResult* aResult)
{
const nsACString* newTitle = reinterpret_cast<nsACString*>(aClosure);
aNode->mTitle = *newTitle;
if (aResult && aResult->GetView() &&
(!aNode->mParent || aNode->mParent->AreChildrenVisible())) {
aResult->GetView()->NodeTitleChanged(aNode, *newTitle);
}
}
nsresult
nsNavHistoryContainerResultNode::ChangeTitles(nsIURI* aURI,
@ -2871,10 +2961,16 @@ nsNavHistoryQueryResultNode::OnClearHistory()
//
static void setFaviconCallback(
nsNavHistoryResultNode* aNode, void* aClosure)
nsNavHistoryResultNode* aNode, void* aClosure,
nsNavHistoryResult* aResult)
{
const nsCString* newFavicon = static_cast<nsCString*>(aClosure);
aNode->mFaviconURI = *newFavicon;
if (aResult && aResult->GetView() &&
(!aNode->mParent || aNode->mParent->AreChildrenVisible())) {
aResult->GetView()->NodeIconChanged(aNode);
}
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnPageChanged(nsIURI *aURI, PRUint32 aWhat,
@ -2917,19 +3013,6 @@ nsNavHistoryQueryResultNode::OnPageExpired(nsIURI* aURI, PRTime aVisitTime,
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnItemAdded(PRInt64 aItemId,
PRInt64 aFolder,
PRInt32 aIndex)
{
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
PRUint16 itemType;
nsresult rv = bookmarks->GetItemType(aItemId, &itemType);
NS_ENSURE_SUCCESS(rv, rv);
return OnItemAdded(aItemId, aFolder, aIndex, itemType);
}
// nsNavHistoryQueryResultNode bookmark observers
//
// These are the bookmark observer functions for query nodes. They listen
@ -2942,41 +3025,57 @@ nsNavHistoryQueryResultNode::OnItemAdded(PRInt64 aItemId,
PRInt32 aIndex,
PRUint16 aItemType)
{
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
if (aItemType == nsINavBookmarksService::TYPE_BOOKMARK &&
mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
return Refresh();
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnBeforeItemRemoved(PRInt64 aItemId)
nsNavHistoryQueryResultNode::OnBeforeItemRemoved(PRInt64 aItemId,
PRUint16 aItemType)
{
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnItemRemoved(PRInt64 aItemId, PRInt64 aFolder,
PRInt32 aIndex)
PRInt32 aIndex, PRUint16 aItemType)
{
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
return Refresh();
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnItemChanged(PRInt64 aItemId,
const nsACString& aProperty,
PRBool aIsAnnotationProperty,
const nsACString& aValue)
const nsACString& aNewValue,
PRTime aLastModified,
PRUint16 aItemType)
{
// History observers should not get OnItemChanged
// but should get the corresponding history notifications instead.
// For bookmark queries, "all bookmark" observers should get OnItemChanged.
// For example, when a title of a bookmark changes, we want that to refresh.
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS) {
// Make sure it's not a folder or a separator.
if (aItemType != nsINavBookmarksService::TYPE_BOOKMARK)
return NS_OK;
(void)Refresh();
else
}
else {
NS_WARNING("history observers should not get OnItemChanged, but should get the corresponding history notifications instead");
}
return nsNavHistoryResultNode::OnItemChanged(aItemId, aProperty,
aIsAnnotationProperty,
aValue);
aNewValue,
aLastModified,
aItemType);
}
NS_IMETHODIMP
@ -2991,12 +3090,20 @@ nsNavHistoryQueryResultNode::OnItemVisited(PRInt64 aItemId,
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnItemMoved(PRInt64 aFolder, PRInt64 aOldParent,
PRInt32 aOldIndex, PRInt64 aNewParent,
PRInt32 aNewIndex)
nsNavHistoryQueryResultNode::OnItemMoved(PRInt64 aFolder,
PRInt64 aOldParent, PRInt32 aOldIndex,
PRInt64 aNewParent, PRInt32 aNewIndex,
PRUint16 aItemType)
{
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
// 1. The query cannot be affected by the item's position
// 2. For the time being, we cannot optimize this not to update
// queries which are not restricted to some folders, due to way
// sub-queries are updated (see Refresh)
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS &&
aItemType != nsINavBookmarksService::TYPE_SEPARATOR &&
aOldParent != aNewParent) {
return Refresh();
}
return NS_OK;
}
@ -3459,21 +3566,6 @@ nsNavHistoryFolderResultNode::OnEndUpdateBatch()
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryFolderResultNode::OnItemAdded(PRInt64 aItemId,
PRInt64 aFolder,
PRInt32 aIndex)
{
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
PRUint16 itemType;
nsresult rv = bookmarks->GetItemType(aItemId, &itemType);
NS_ENSURE_SUCCESS(rv, rv);
return OnItemAdded(aItemId, aFolder, aIndex, itemType);
}
// nsNavHistoryFolderResultNode::OnItemAdded (nsINavBookmarkObserver)
NS_IMETHODIMP
@ -3569,7 +3661,8 @@ nsNavHistoryFolderResultNode::OnItemAdded(PRInt64 aItemId,
// nsNavHistoryFolderResultNode::OnBeforeItemRemoved (nsINavBookmarkObserver)
NS_IMETHODIMP
nsNavHistoryFolderResultNode::OnBeforeItemRemoved(PRInt64 aItemId)
nsNavHistoryFolderResultNode::OnBeforeItemRemoved(PRInt64 aItemId,
PRUint16 aItemType)
{
return NS_OK;
}
@ -3580,7 +3673,8 @@ nsNavHistoryFolderResultNode::OnBeforeItemRemoved(PRInt64 aItemId)
NS_IMETHODIMP
nsNavHistoryFolderResultNode::OnItemRemoved(PRInt64 aItemId,
PRInt64 aParentFolder,
PRInt32 aIndex)
PRInt32 aIndex,
PRUint16 aItemType)
{
// We only care about notifications when a child changes. When the deleted
// item is us, our parent should also be registered and will remove us from
@ -3630,61 +3724,70 @@ NS_IMETHODIMP
nsNavHistoryResultNode::OnItemChanged(PRInt64 aItemId,
const nsACString& aProperty,
PRBool aIsAnnotationProperty,
const nsACString& aValue)
const nsACString& aNewValue,
PRTime aLastModified,
PRUint16 aItemType)
{
if (aItemId != mItemId)
return NS_OK;
if (aProperty.EqualsLiteral("title")) {
// XXX: what should we do if the new title is void?
mTitle = aValue;
}
else if (aProperty.EqualsLiteral("uri")) {
mURI = aValue;
// clear the tags string as well
mTags.SetIsVoid(PR_TRUE);
}
else if (aProperty.EqualsLiteral("favicon")) {
mFaviconURI = aValue;
}
else if (aProperty.EqualsLiteral("cleartime")) {
mTime = 0;
}
else if (aProperty.EqualsLiteral("tags")) {
mTags.SetIsVoid(PR_TRUE);
}
else if (!aProperty.EqualsLiteral("keyword") &&
!aProperty.EqualsLiteral("dateAdded") &&
!aProperty.EqualsLiteral("lastModified") && !aIsAnnotationProperty) {
NS_NOTREACHED("Unknown bookmark property changing.");
}
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bookmarks, NS_ERROR_UNEXPECTED);
PRTime lastModified;
nsresult rv = bookmarks->GetItemLastModified(aItemId, &lastModified);
if (NS_SUCCEEDED(rv)) {
mLastModified = lastModified;
}
else {
mLastModified = 0;
}
PRTime dateAdded;
rv = bookmarks->GetItemDateAdded(aItemId, &dateAdded);
if (NS_SUCCEEDED(rv)) {
mDateAdded = dateAdded;
}
else {
mDateAdded = 0;
}
mLastModified = aLastModified;
nsNavHistoryResult* result = GetResult();
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
if (result->GetView() && (!mParent || mParent->AreChildrenVisible())) {
result->GetView()->ItemChanged(this);
PRBool shouldUpdateView =
result->GetView() && (!mParent || mParent->AreChildrenVisible());
if (aIsAnnotationProperty) {
if (shouldUpdateView)
result->GetView()->NodeAnnotationChanged(this, aProperty);
}
else if (aProperty.EqualsLiteral("title")) {
// XXX: what should we do if the new title is void?
mTitle = aNewValue;
if (shouldUpdateView)
result->GetView()->NodeTitleChanged(this, mTitle);
}
else if (aProperty.EqualsLiteral("uri")) {
// clear the tags string as well
mTags.SetIsVoid(PR_TRUE);
mURI = aNewValue;
if (shouldUpdateView)
result->GetView()->NodeURIChanged(this, mURI);
}
else if (aProperty.EqualsLiteral("favicon")) {
mFaviconURI = aNewValue;
if (shouldUpdateView)
result->GetView()->NodeIconChanged(this);
}
else if (aProperty.EqualsLiteral("cleartime")) {
mTime = 0;
if (shouldUpdateView)
result->GetView()->NodeHistoryDetailsChanged(this, 0, mAccessCount);
}
else if (aProperty.EqualsLiteral("tags")) {
mTags.SetIsVoid(PR_TRUE);
if (shouldUpdateView)
result->GetView()->NodeTagsChanged(this);
}
else if (aProperty.EqualsLiteral("dateAdded")) {
// aNewValue has the date as a string, but we can use aLastModified,
// because it's set to the same value when dateAdded is changed.
mDateAdded = aLastModified;
if (shouldUpdateView)
result->GetView()->NodeDateAddedChanged(this, mDateAdded);
}
else if (aProperty.EqualsLiteral("lastModified")) {
if (shouldUpdateView)
result->GetView()->NodeLastModifiedChanged(this, aLastModified);
}
else if (aProperty.EqualsLiteral("keyword")) {
if (shouldUpdateView)
result->GetView()->NodeKeywordChanged(this, aNewValue);
}
else {
NS_NOTREACHED("Unknown bookmark property changing.");
}
if (!mParent)
@ -3703,7 +3806,9 @@ NS_IMETHODIMP
nsNavHistoryFolderResultNode::OnItemChanged(PRInt64 aItemId,
const nsACString& aProperty,
PRBool aIsAnnotationProperty,
const nsACString& aValue) {
const nsACString& aNewValue,
PRTime aLastModified,
PRUint16 aItemType) {
// The query-item's title is used for simple-query nodes
if (mQueryItemId != -1) {
PRBool isTitleChange = aProperty.EqualsLiteral("title");
@ -3715,7 +3820,9 @@ nsNavHistoryFolderResultNode::OnItemChanged(PRInt64 aItemId,
return nsNavHistoryResultNode::OnItemChanged(aItemId, aProperty,
aIsAnnotationProperty,
aValue);
aNewValue,
aLastModified,
aItemType);
}
// nsNavHistoryFolderResultNode::OnItemVisited (nsINavBookmarkObserver)
@ -3731,12 +3838,12 @@ nsNavHistoryFolderResultNode::OnItemVisited(PRInt64 aItemId,
mOptions->ExcludeItems();
if (excludeItems)
return NS_OK; // don't update items when we aren't displaying them
if (! StartIncrementalUpdate())
if (!StartIncrementalUpdate())
return NS_OK;
PRUint32 nodeIndex;
nsNavHistoryResultNode* node = FindChildById(aItemId, &nodeIndex);
if (! node)
if (!node)
return NS_ERROR_FAILURE;
nsNavHistoryResult* result = GetResult();
@ -3753,6 +3860,11 @@ nsNavHistoryFolderResultNode::OnItemVisited(PRInt64 aItemId,
mTime = aTime;
ReverseUpdateStats(mAccessCount - oldAccessCount);
if (result->GetView() && AreChildrenVisible()) {
// Sorting has not changed, just redraw the row if it's visible.
result->GetView()->NodeHistoryDetailsChanged(node, mTime, mAccessCount);
}
// update sorting if necessary
PRUint32 sortType = GetSortType();
if (sortType == nsINavHistoryQueryOptions::SORT_BY_VISITCOUNT_ASCENDING ||
@ -3764,10 +3876,8 @@ nsNavHistoryFolderResultNode::OnItemVisited(PRInt64 aItemId,
if (childIndex >= 0) {
EnsureItemPosition(childIndex);
}
} else if (result->GetView() && AreChildrenVisible()) {
// no sorting changed, just redraw the row if visible
result->GetView()->ItemChanged(node);
}
return NS_OK;
}
@ -3776,7 +3886,7 @@ nsNavHistoryFolderResultNode::OnItemVisited(PRInt64 aItemId,
NS_IMETHODIMP
nsNavHistoryFolderResultNode::OnItemMoved(PRInt64 aItemId, PRInt64 aOldParent,
PRInt32 aOldIndex, PRInt64 aNewParent,
PRInt32 aNewIndex)
PRInt32 aNewIndex, PRUint16 aItemType)
{
NS_ASSERTION(aOldParent == mItemId || aNewParent == mItemId,
"Got a bookmark message that doesn't belong to us");
@ -3807,9 +3917,9 @@ nsNavHistoryFolderResultNode::OnItemMoved(PRInt64 aItemId, PRInt64 aOldParent,
} else {
// moving between two different folders, just do a remove and an add
if (aOldParent == mItemId)
OnItemRemoved(aItemId, aOldParent, aOldIndex);
OnItemRemoved(aItemId, aOldParent, aOldIndex, aItemType);
if (aNewParent == mItemId)
OnItemAdded(aItemId, aNewParent, aNewIndex);
OnItemAdded(aItemId, aNewParent, aNewIndex, aItemType);
}
return NS_OK;
}
@ -3863,24 +3973,10 @@ TraverseBookmarkFolderObservers(nsTrimInt64HashKey::KeyType aKey,
return PL_DHASH_NEXT;
}
static PLDHashOperator
TraversePropertyBags(nsISupportsHashKey::KeyType aKey,
nsCOMPtr<nsIWritablePropertyBag> &aData,
void *aClosure)
{
nsCycleCollectionTraversalCallback* cb =
static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mPropertyBags key");
cb->NoteXPCOMChild(aKey);
return PL_DHASH_NEXT;
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsNavHistoryResult)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mRootNode, nsINavHistoryContainerResultNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mView)
tmp->mBookmarkFolderObservers.Enumerate(&TraverseBookmarkFolderObservers, &cb);
tmp->mPropertyBags.Enumerate(&TraversePropertyBags, &cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mAllBookmarksObservers, nsNavHistoryQueryResultNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(mHistoryObservers, nsNavHistoryQueryResultNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -3963,7 +4059,6 @@ nsNavHistoryResult::Init(nsINavHistoryQuery** aQueries,
rv = aOptions->GetSortingAnnotation(mSortingAnnotation);
NS_ENSURE_SUCCESS(rv, rv);
mPropertyBags.Init();
if (! mBookmarkFolderObservers.Init(128))
return NS_ERROR_OUT_OF_MEMORY;
@ -4005,38 +4100,6 @@ nsNavHistoryResult::NewHistoryResult(nsINavHistoryQuery** aQueries,
}
// nsNavHistoryResult::PropertyBagFor
//
// Given a pointer to a result node, this will give you the property bag
// corresponding to it. Each node exposes a property bag to be used to
// store temporary data. It is designed primarily for those implementing
// container sources for storing data they need.
//
// Since we expect very few result nodes will ever have their property bags
// used, and since we can have a LOT of result nodes, we store the property
// bags separately in a hash table in the parent result.
//
// This function is called by a node when somebody wants the property bag.
// It will create a property bag if necessary and store it for later
// retrieval.
nsresult
nsNavHistoryResult::PropertyBagFor(nsISupports* aObject,
nsIWritablePropertyBag** aBag)
{
*aBag = nsnull;
if (mPropertyBags.Get(aObject, aBag) && *aBag)
return NS_OK;
nsresult rv = NS_NewHashPropertyBag(aBag);
NS_ENSURE_SUCCESS(rv, rv);
if (! mPropertyBags.Put(aObject, *aBag)) {
NS_RELEASE(*aBag);
*aBag = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
// nsNavHistoryResult::AddHistoryObserver
@ -4193,7 +4256,7 @@ nsNavHistoryResult::SetSortingMode(PRUint16 aSortingMode)
if (mView) {
mView->SortingChanged(aSortingMode);
mView->InvalidateAll();
mView->InvalidateContainer(mRootNode);
}
return NS_OK;
}
@ -4305,21 +4368,15 @@ nsNavHistoryResult::OnEndUpdateBatch()
NS_IMETHODIMP
nsNavHistoryResult::OnItemAdded(PRInt64 aItemId,
PRInt64 aFolder,
PRInt32 aIndex)
PRInt64 aParentId,
PRInt32 aIndex,
PRUint16 aItemType)
{
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
PRUint16 itemType;
nsresult rv = bookmarks->GetItemType(aItemId, &itemType);
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(aFolder,
OnItemAdded(aItemId, aFolder, aIndex, itemType));
ENUMERATE_HISTORY_OBSERVERS(OnItemAdded(aItemId, aFolder, aIndex, itemType));
ENUMERATE_ALL_BOOKMARKS_OBSERVERS(OnItemAdded(aItemId, aFolder, aIndex,
itemType));
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(aParentId,
OnItemAdded(aItemId, aParentId, aIndex, aItemType));
ENUMERATE_HISTORY_OBSERVERS(OnItemAdded(aItemId, aParentId, aIndex, aItemType));
ENUMERATE_ALL_BOOKMARKS_OBSERVERS(OnItemAdded(aItemId, aParentId, aIndex,
aItemType));
return NS_OK;
}
@ -4327,7 +4384,7 @@ nsNavHistoryResult::OnItemAdded(PRInt64 aItemId,
// nsNavHistoryResult::OnBeforeItemRemoved (nsINavBookmarkObserver)
NS_IMETHODIMP
nsNavHistoryResult::OnBeforeItemRemoved(PRInt64 aItemId)
nsNavHistoryResult::OnBeforeItemRemoved(PRInt64 aItemId, PRUint16 aItemType)
{
// Nobody actually does anything with this method, so we do not need to notify
return NS_OK;
@ -4338,14 +4395,15 @@ nsNavHistoryResult::OnBeforeItemRemoved(PRInt64 aItemId)
NS_IMETHODIMP
nsNavHistoryResult::OnItemRemoved(PRInt64 aItemId,
PRInt64 aFolder, PRInt32 aIndex)
PRInt64 aParentId, PRInt32 aIndex,
PRUint16 aItemType)
{
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(aFolder,
OnItemRemoved(aItemId, aFolder, aIndex));
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(aParentId,
OnItemRemoved(aItemId, aParentId, aIndex, aItemType));
ENUMERATE_ALL_BOOKMARKS_OBSERVERS(
OnItemRemoved(aItemId, aFolder, aIndex));
OnItemRemoved(aItemId, aParentId, aIndex, aItemType));
ENUMERATE_HISTORY_OBSERVERS(
OnItemRemoved(aItemId, aFolder, aIndex));
OnItemRemoved(aItemId, aParentId, aIndex, aItemType));
return NS_OK;
}
@ -4356,10 +4414,13 @@ NS_IMETHODIMP
nsNavHistoryResult::OnItemChanged(PRInt64 aItemId,
const nsACString &aProperty,
PRBool aIsAnnotationProperty,
const nsACString &aValue)
const nsACString &aNewValue,
PRTime aLastModified,
PRUint16 aItemType)
{
ENUMERATE_ALL_BOOKMARKS_OBSERVERS(
OnItemChanged(aItemId, aProperty, aIsAnnotationProperty, aValue));
OnItemChanged(aItemId, aProperty, aIsAnnotationProperty, aNewValue,
aLastModified, aItemType));
// Note: folder-nodes set their own bookmark observer only once they're
// opened, meaning we cannot optimize this code path for changes done to
@ -4389,7 +4450,8 @@ nsNavHistoryResult::OnItemChanged(PRInt64 aItemId,
if (node &&
(!excludeItems || !(node->IsURI() || node->IsSeparator())) &&
folder->StartIncrementalUpdate()) {
node->OnItemChanged(aItemId, aProperty, aIsAnnotationProperty, aValue);
node->OnItemChanged(aItemId, aProperty, aIsAnnotationProperty,
aNewValue, aLastModified, aItemType);
}
}
}
@ -4434,20 +4496,24 @@ nsNavHistoryResult::OnItemVisited(PRInt64 aItemId, PRInt64 aVisitId,
NS_IMETHODIMP
nsNavHistoryResult::OnItemMoved(PRInt64 aItemId,
PRInt64 aOldParent, PRInt32 aOldIndex,
PRInt64 aNewParent, PRInt32 aNewIndex)
PRInt64 aNewParent, PRInt32 aNewIndex,
PRUint16 aItemType)
{
{ // scope for loop index for VC6's broken for loop scoping
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(aOldParent,
OnItemMoved(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex));
OnItemMoved(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex,
aItemType));
}
if (aNewParent != aOldParent) {
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(aNewParent,
OnItemMoved(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex));
OnItemMoved(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex,
aItemType));
}
ENUMERATE_ALL_BOOKMARKS_OBSERVERS(OnItemMoved(aItemId, aOldParent, aOldIndex,
aNewParent, aNewIndex));
aNewParent, aNewIndex,
aItemType));
ENUMERATE_HISTORY_OBSERVERS(OnItemMoved(aItemId, aOldParent, aOldIndex,
aNewParent, aNewIndex));
aNewParent, aNewIndex, aItemType));
return NS_OK;
}

View File

@ -51,7 +51,6 @@
#include "nsCycleCollectionParticipant.h"
class nsNavHistory;
class nsIWritablePropertyBag;
class nsNavHistoryQuery;
class nsNavHistoryQueryOptions;
@ -107,10 +106,6 @@ private:
NS_IMETHOD OnPageExpired(nsIURI* aURI, PRTime aVisitTime, \
PRBool aWholeEntry);
#define NS_DECL_EXTENDED_BOOKMARK_OBSERVER \
NS_IMETHOD OnItemAdded(PRInt64 aItemId, PRInt64 aFolder, \
PRInt32 aIndex, PRUint16 aItemType);
// nsNavHistoryResult
//
// nsNavHistory creates this object and fills in mChildren (by getting
@ -141,9 +136,6 @@ public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYRESULT_IID)
nsresult PropertyBagFor(nsISupports* aObject,
nsIWritablePropertyBag** aBag);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSINAVHISTORYRESULT
NS_DECL_BOOKMARK_HISTORY_OBSERVER
@ -187,9 +179,6 @@ public:
nsCOMPtr<nsINavHistoryResultViewer> mView;
// property bags for all result nodes, see PropertyBagFor
nsInterfaceHashtable<nsISupportsHashKey, nsIWritablePropertyBag> mPropertyBags;
// node observers
PRBool mIsHistoryObserver;
PRBool mIsBookmarkFolderObserver;
@ -235,10 +224,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResult, NS_NAVHISTORYRESULT_IID)
{ *aTime = mTime; return NS_OK; } \
NS_IMETHOD GetIndentLevel(PRInt32* aIndentLevel) \
{ *aIndentLevel = mIndentLevel; return NS_OK; } \
NS_IMETHOD GetViewIndex(PRInt32* aViewIndex) \
{ *aViewIndex = mViewIndex; return NS_OK; } \
NS_IMETHOD SetViewIndex(PRInt32 aViewIndex) \
{ mViewIndex = aViewIndex; return NS_OK; } \
NS_IMETHOD GetBookmarkIndex(PRInt32* aIndex) \
{ *aIndex = mBookmarkIndex; return NS_OK; } \
NS_IMETHOD GetDateAdded(PRTime* aDateAdded) \
@ -262,16 +247,14 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResult, NS_NAVHISTORYRESULT_IID)
// buffer.)
#define NS_FORWARD_COMMON_RESULTNODE_TO_BASE_NO_GETITEMMID \
NS_IMPLEMENT_SIMPLE_RESULTNODE_NO_GETITEMMID \
NS_IMETHOD GetIcon(nsIURI** aIcon) \
NS_IMETHOD GetIcon(nsACString& aIcon) \
{ return nsNavHistoryResultNode::GetIcon(aIcon); } \
NS_IMETHOD GetParent(nsINavHistoryContainerResultNode** aParent) \
{ return nsNavHistoryResultNode::GetParent(aParent); } \
NS_IMETHOD GetParentResult(nsINavHistoryResult** aResult) \
{ return nsNavHistoryResultNode::GetParentResult(aResult); } \
NS_IMETHOD GetPropertyBag(nsIWritablePropertyBag** aBag) \
{ return nsNavHistoryResultNode::GetPropertyBag(aBag); } \
NS_IMETHOD GetTags(nsAString& aTags) \
{ return nsNavHistoryResultNode::GetTags(aTags); } \
{ return nsNavHistoryResultNode::GetTags(aTags); }
#define NS_FORWARD_COMMON_RESULTNODE_TO_BASE \
NS_FORWARD_COMMON_RESULTNODE_TO_BASE_NO_GETITEMMID \
@ -292,10 +275,9 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS(nsNavHistoryResultNode)
NS_IMPLEMENT_SIMPLE_RESULTNODE
NS_IMETHOD GetIcon(nsIURI** aIcon);
NS_IMETHOD GetIcon(nsACString& aIcon);
NS_IMETHOD GetParent(nsINavHistoryContainerResultNode** aParent);
NS_IMETHOD GetParentResult(nsINavHistoryResult** aResult);
NS_IMETHOD GetPropertyBag(nsIWritablePropertyBag** aBag);
NS_IMETHOD GetType(PRUint32* type)
{ *type = nsNavHistoryResultNode::RESULT_TYPE_URI; return NS_OK; }
NS_IMETHOD GetUri(nsACString& aURI)
@ -309,7 +291,9 @@ public:
NS_IMETHOD OnItemChanged(PRInt64 aItemId,
const nsACString &aProperty,
PRBool aIsAnnotationProperty,
const nsACString &aValue);
const nsACString &aValue,
PRTime aNewLastModified,
PRUint16 aItemType);
public:
@ -408,14 +392,6 @@ public:
// The indent level of this node. The root node will have a value of -1. The
// root's children will have a value of 0, and so on.
PRInt32 mIndentLevel;
// Value used by the view for whatever it wants. For the built-in tree view,
// this is the index into the result's mVisibleElements list of this element.
// This is -1 if it is invalid. For items, >= 0 can be used to determine if
// the node is visible in the list or not. For folders, call IsVisible, since
// they can be the root node which is not itself visible, but its children
// are.
PRInt32 mViewIndex;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResultNode, NS_NAVHISTORYRESULTNODE_IID)
@ -650,8 +626,6 @@ public:
}
nsNavHistoryResultNode* FindChildURI(const nsACString& aSpec,
PRUint32* aNodeIndex);
nsNavHistoryFolderResultNode* FindChildFolder(PRInt64 aFolderId,
PRUint32* aNodeIndex);
nsNavHistoryContainerResultNode* FindChildContainerByName(const nsACString& aTitle,
PRUint32* aNodeIndex);
// returns the index of the given node, -1 if not found
@ -674,7 +648,7 @@ public:
nsCOMArray<nsNavHistoryResultNode>* aMatches);
void UpdateURIs(PRBool aRecursive, PRBool aOnlyOne, PRBool aUpdateSort,
const nsCString& aSpec,
void (*aCallback)(nsNavHistoryResultNode*,void*),
void (*aCallback)(nsNavHistoryResultNode*,void*, nsNavHistoryResult*),
void* aClosure);
nsresult ChangeTitles(nsIURI* aURI, const nsACString& aNewTitle,
PRBool aRecursive, PRBool aOnlyOne);
@ -725,7 +699,6 @@ public:
virtual nsresult OpenContainer();
NS_DECL_BOOKMARK_HISTORY_OBSERVER
NS_DECL_EXTENDED_BOOKMARK_OBSERVER
virtual void OnRemoving();
public:
@ -799,7 +772,6 @@ public:
// the bookmark observers. This is called from the result's actual observer
// and it knows all observers are FolderResultNodes
NS_DECL_NSINAVBOOKMARKOBSERVER
NS_DECL_EXTENDED_BOOKMARK_OBSERVER
virtual void OnRemoving();
public:

View File

@ -218,17 +218,18 @@ nsPlacesDBFlush.prototype = {
this._flushWithQueries([kQuerySyncPlacesId, kQuerySyncHistoryVisitsId]);
},
onItemAdded: function(aItemId, aParentId, aIndex)
onItemAdded: function(aItemId, aParentId, aIndex, aItemType)
{
// Sync only if we added a TYPE_BOOKMARK item. Note, we want to run the
// least amount of queries as possible here for performance reasons.
if (!this._inBatchMode &&
this._bs.getItemType(aItemId) == this._bs.TYPE_BOOKMARK)
if (!this._inBatchMode && aItemType == this._bs.TYPE_BOOKMARK)
this._flushWithQueries([kQuerySyncPlacesId]);
},
onItemChanged: function DBFlush_onItemChanged(aItemId, aProperty,
aIsAnnotationProperty, aValue)
aIsAnnotationProperty,
aNewValue, aLastModified,
aItemType)
{
if (!this._inBatchMode && aProperty == "uri")
this._flushWithQueries([kQuerySyncPlacesId]);

View File

@ -225,7 +225,7 @@ TaggingService.prototype = {
var cc = node.childCount;
node.containerOpen = false;
if (cc == 0)
this._bms.removeFolder(node.itemId);
this._bms.removeItem(node.itemId);
},
// nsITaggingService
@ -397,46 +397,21 @@ TaggingService.prototype = {
this._inBatch = false;
},
onItemAdded: function(aItemId, aFolderId, aIndex) {
onItemAdded: function(aItemId, aFolderId, aIndex, aItemType) {
// Nothing to do if this is not a tag.
if (aFolderId != this._bms.tagsFolder)
if (aFolderId != this._bms.tagsFolder ||
aItemType != this._bms.TYPE_FOLDER)
return;
// If we are correctly called through createTag the itemId will be added
// to _tagFolders just after onItemAdded is called. To avoid an useless
// call to getItemType we enqueue this check, so that when it runs the hash
// has already been updated.
// TODO: once bug 494380 is fixed, this 'workaround' can go away.
var self = this;
var tm = Cc["@mozilla.org/thread-manager;1"].
getService(Ci.nsIThreadManager);
tm.mainThread.dispatch({
run: function() {
try {
if (!self._tagFolders[aItemId] &&
self._bms.getItemType(aItemId) == self._bms.TYPE_FOLDER)
self._tagFolders[aItemId] = self._bms.getItemTitle(aItemId);
}
catch(ex) {
// Could happen that the tag is removed just after it is added, for
// example with transactions. in such a case getting item type
// will fail and there's no reason to register the addition.
}
}
}, Ci.nsIThread.DISPATCH_NORMAL);
this._tagFolders[aItemId] = this._bms.getItemTitle(aItemId);
},
onBeforeItemRemoved: function(aItemId) {
// Remember the bookmark's URI, because it will be gone by the time
// onItemRemoved() is called. getBookmarkURI() will throw if the item is
// not a bookmark, which is fine.
try {
onBeforeItemRemoved: function(aItemId, aItemType) {
if (aItemType == this._bms.TYPE_BOOKMARK)
this._itemsInRemoval[aItemId] = this._bms.getBookmarkURI(aItemId);
}
catch (e) {}
},
onItemRemoved: function(aItemId, aFolderId, aIndex) {
onItemRemoved: function(aItemId, aFolderId, aIndex, aItemType) {
var itemURI = this._itemsInRemoval[aItemId];
delete this._itemsInRemoval[aItemId];
@ -456,14 +431,16 @@ TaggingService.prototype = {
}
},
onItemChanged: function(aItemId, aProperty, aIsAnnotationProperty, aValue) {
onItemChanged: function(aItemId, aProperty, aIsAnnotationProperty, aNewValue,
aLastModified, aItemType) {
if (aProperty == "title" && this._tagFolders[aItemId])
this._tagFolders[aItemId] = this._bms.getItemTitle(aItemId);
},
onItemVisited: function(aItemId, aVisitID, time) {},
onItemMoved: function(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
onItemMoved: function(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex,
aItemType) {
if (this._tagFolders[aItemId] && this._bms.tagFolder == aOldParent &&
this._bms.tagFolder != aNewParent)
delete this._tagFolders[aItemId];

View File

@ -47,22 +47,23 @@ try {
var observer = {
onBeginUpdateBatch: function() {},
onEndUpdateBatch: function() {},
onItemAdded: function(id, folder, index) {
onItemAdded: function(id, folder, index, itemType) {
this._itemAddedId = id;
this._itemAddedParent = folder;
this._itemAddedIndex = index;
},
onBeforeItemRemoved: function(id) {},
onItemRemoved: function(id, folder, index) {},
onBeforeItemRemoved: function() {},
onItemRemoved: function() {},
_itemChangedProperty: null,
onItemChanged: function(id, property, isAnnotationProperty, value) {
onItemChanged: function(id, property, isAnnotationProperty, value,
lastModified, itemType) {
this._itemChangedId = id;
this._itemChangedProperty = property;
this._itemChanged_isAnnotationProperty = isAnnotationProperty;
this._itemChangedValue = value;
},
onItemVisited: function(id, visitID, time) {},
onItemMoved: function(id, oldParent, oldIndex, newParent, newIndex) {},
onItemVisited: function() {},
onItemMoved: function() {},
QueryInterface: function(iid) {
if (iid.equals(Ci.nsINavBookmarkObserver) ||
iid.equals(Ci.nsISupports)) {

View File

@ -66,19 +66,19 @@ var observer = {
onEndUpdateBatch: function() {
this._endUpdateBatch = true;
},
onItemAdded: function(id, folder, index) {
onItemAdded: function(id, folder, index, itemType) {
this._itemAddedId = id;
this._itemAddedParent = folder;
this._itemAddedIndex = index;
},
onBeforeItemRemoved: function(id) {
},
onItemRemoved: function(id, folder, index) {
onBeforeItemRemoved: function(){},
onItemRemoved: function(id, folder, index, itemType) {
this._itemRemovedId = id;
this._itemRemovedFolder = folder;
this._itemRemovedIndex = index;
},
onItemChanged: function(id, property, isAnnotationProperty, value) {
onItemChanged: function(id, property, isAnnotationProperty, value,
lastModified, itemType) {
this._itemChangedId = id;
this._itemChangedProperty = property;
this._itemChanged_isAnnotationProperty = isAnnotationProperty;
@ -89,7 +89,8 @@ var observer = {
this._itemVisitedVistId = visitID;
this._itemVisitedTime = time;
},
onItemMoved: function(id, oldParent, oldIndex, newParent, newIndex) {
onItemMoved: function(id, oldParent, oldIndex, newParent, newIndex,
itemType) {
this._itemMovedId = id
this._itemMovedOldParent = oldParent;
this._itemMovedOldIndex = oldIndex;
@ -340,27 +341,6 @@ function run_test() {
do_check_eq(observer._itemMovedNewParent, testRoot);
do_check_eq(observer._itemMovedNewIndex, 3);
// test insertSeparator and removeChildAt
// XXX - this should also query bookmarks for the folder children
// and then test the node type at our index
try {
bmsvc.insertSeparator(testRoot, 1);
bmsvc.removeChildAt(testRoot, 1);
} catch(ex) {
do_throw("insertSeparator: " + ex);
}
// XXX test getItemType for separators
// add when 379952 is fixed
// removeChildAt w/ folder
bmsvc.createFolder(testRoot, "tmp", 1);
bmsvc.removeChildAt(testRoot, 1);
// removeChildAt w/ bookmark
bmsvc.insertBookmark(root, uri("http://blah.com"), 1, "");
bmsvc.removeChildAt(root, 1);
// test get folder's index
var tmpFolder = bmsvc.createFolder(testRoot, "tmp", 2);
do_check_eq(bmsvc.getItemIndex(tmpFolder), 2);

View File

@ -57,6 +57,8 @@ function Observer(aExpectedId)
Observer.prototype =
{
checked: false,
onItemMovedCalled: false,
onItemRemovedCalled: false,
onBeginUpdateBatch: function() {
},
onEndUpdateBatch: function() {
@ -69,13 +71,14 @@ Observer.prototype =
onItemRemoved: function(id, folder, index) {
do_check_false(this.checked);
do_check_eq(this.removedId, id);
this.checked = true;
this.onItemRemovedCalled = true;
},
onItemChanged: function(id, property, isAnnotationProperty, value) {
},
onItemVisited: function(id, visitID, time) {
},
onItemMoved: function(id, oldParent, oldIndex, newParent, newIndex) {
this.onItemMovedCalled = true;
},
QueryInterface: function(iid) {
if (iid.equals(Ci.nsINavBookmarkObserver) ||
@ -101,7 +104,7 @@ function test_removeItem()
bs.removeItem(id);
// Make sure we were notified!
do_check_true(observer.checked);
do_check_true(observer.onItemRemovedCalled);
bs.removeObserver(observer);
}
@ -116,7 +119,7 @@ function test_removeFolder()
bs.removeItem(id);
// Make sure we were notified!
do_check_true(observer.checked);
do_check_true(observer.onItemRemovedCalled);
bs.removeObserver(observer);
}
@ -133,7 +136,7 @@ function test_removeFolderChildren()
bs.removeFolderChildren(fid);
// Make sure we were notified!
do_check_true(observer.checked);
do_check_true(observer.onItemRemovedCalled);
bs.removeObserver(observer);
}
@ -151,7 +154,7 @@ function test_setItemIndex()
bs.setItemIndex(id, 2);
// Make sure we were notified!
do_check_true(observer.checked);
do_check_true(observer.onItemMovedCalled);
bs.removeObserver(observer);
}

View File

@ -55,13 +55,6 @@ function run_test() {
DEFAULT_INDEX, "");
do_check_eq(PlacesUtils.bookmarks.getItemTitle(bookmarkId), "");
// try to remove the bookmark using removeFolder
try {
PlacesUtils.bookmarks.removeFolder(bookmarkId);
do_throw("no exception when removing a bookmark via removeFolder()!");
} catch(ex) {}
do_check_true(PlacesUtils.bookmarks.isBookmarked(bookmarkURI));
// remove the folder using removeItem
PlacesUtils.bookmarks.removeItem(folderId);
do_check_eq(PlacesUtils.bookmarks.getBookmarkIdsForURI(bookmarkURI, {}).length, 0);

View File

@ -69,24 +69,24 @@ var observer =
// nsINavBookmarkObserver
onBeginUpdateBatch: function(){},
onEndUpdateBatch: function(){},
onItemAdded: function(bookmarkId, folderId, index) {
onItemAdded: function(bookmarkId, folderId, index, itemType) {
if ( status == 0 ) {
runTest1( folderId );
} else {
runTest2( folderId );
if ( status == 2 ) {
bmsvc.removeObserver(this);
bmsvc.removeFolder(gLivemarkId1);
bmsvc.removeFolder(gLivemarkId2);
bmsvc.removeItem(gLivemarkId1);
bmsvc.removeItem(gLivemarkId2);
SimpleTest.finish();
}
}
},
onBeforeItemRemoved: function(bookmarkId){},
onItemRemoved: function(bookmarkId, bookmark, folder, index){},
onItemChanged: function(bookmarkId, property, isAnnotationProperty, value){},
onItemVisited: function(bookmarkId, bookmark, aVisitID, time){},
onItemMoved: function(itemId, oldParent, oldIndex, newParent, newIndex){}
onBeforeItemRemoved: function(){},
onItemRemoved: function() {},
onItemChanged: function() {}
onItemVisited: function() {}
onItemMoved: function() {}
};
bmsvc.addObserver(observer, false);

View File

@ -57,7 +57,7 @@ var observer =
ok(newSiteURI == FEEDSITESPEC,
"livemark site URI changed to " + newSiteURI + " not to value in feed");
annosvc.removeObserver(this);
bmsvc.removeFolder(gLivemarkId);
bmsvc.removeItem(gLivemarkId);
SimpleTest.finish();
}
},

View File

@ -53,12 +53,12 @@ var observer =
setTimeout(runTest, 1000);
bmsvc.removeObserver(this);
},
onItemAdded: function(itemId, folder, index) {},
onBeforeItemRemoved: function(itemId){},
onItemRemoved: function(itemId, folder, index){},
onItemChanged: function(itemId, property, isAnnotationProperty, value){},
onItemVisited: function(itemId, aVisitID, time){},
onItemMoved: function(itemId, oldParent, oldIndex, newParent, newIndex){},
onItemAdded: function(){}.
onBeforeItemRemoved: function(){},
onItemRemoved: function(){},
onItemChanged: function(){},
onItemVisited: function(){},
onItemMoved: function(){},
};
@ -79,7 +79,7 @@ function runTest() {
}
rootNode.containerOpen = false;
bmsvc.removeFolder(gLivemarkId);
bmsvc.removeItem(gLivemarkId);
SimpleTest.finish();
}

View File

@ -59,15 +59,16 @@ var observer =
// nsINavBookmarkObserver
onBeginUpdateBatch: function(){},
onEndUpdateBatch: function(){},
onItemAdded: function(bookmarkId, bookmark, folder, index) {},
onBeforeItemRemoved: function(bookmarkId){},
onItemRemoved: function(bookmarkId, bookmark, folder, index){},
onItemChanged: function(bookmarkId, property, isAnnotationProperty, value){
onItemAdded: function(){},
onBeforeItemRemoved: function(){},
onItemRemoved: function(){},
onItemChanged: function(bookmarkId, property, isAnnotationProperty, value,
lastModified, itemType){
runTest();
bmsvc.removeObserver(this);
},
onItemVisited: function(bookmarkId, bookmark, aVisitID, time){},
onItemMoved: function(itemId, oldParent, oldIndex, newParent, newIndex){}
onItemVisited: function(){},
onItemMoved: function(){}
};
bmsvc.addObserver(observer, false);

View File

@ -51,7 +51,7 @@ var observer =
onBeginUpdateBatch: function(){},
onEndUpdateBatch: function(){
},
onItemAdded: function(itemId, folder, index) {
onItemAdded: function(itemId, folder, index, itemType) {
var title = bmsvc.getItemTitle(itemId);
if (title == "The First Title") {
ok(true, "Item with title loaded");
@ -59,11 +59,11 @@ var observer =
SimpleTest.finish();
}
},
onBeforeItemRemoved: function(itemId){},
onItemRemoved: function(itemId, folder, index){},
onItemChanged: function(itemId, property, isAnnotationProperty, value){},
onItemVisited: function(itemId, aVisitID, time){},
onItemMoved: function(itemId, oldParent, oldIndex, newParent, newIndex){},
onBeforeItemRemoved: function(){},
onItemRemoved: function(){},
onItemChanged: function(){},
onItemVisited: function(){},
onItemMoved: function(){},
};

View File

@ -176,7 +176,6 @@ function run_test() {
// The next two options should be ignored
// can't use this one, breaks test - bug 419779
// options.excludeItems = true;
options.showSessions = true;
// Results
var result = histsvc.executeQuery(query, options);

View File

@ -174,7 +174,6 @@ function run_test() {
// The next two options should be ignored
// can't use this one, breaks test - bug 419779
// options.excludeItems = true;
options.showSessions = true;
// Results
var result = histsvc.executeQuery(query, options);

View File

@ -463,17 +463,6 @@ const queryOptionSwitches = [
}
]
},
// showSessions
{
property: "showSessions",
desc: "nsINavHistoryQueryOptions.showSessions",
matches: simplePropertyMatches,
runs: [
function (aQuery, aQueryOptions) {
aQueryOptions.showSessions = true;
}
]
},
// maxResults
{
property: "maxResults",

View File

@ -55,10 +55,11 @@ const kSyncFinished = "places-sync-finished";
// Used to update observer itemId
var bookmarksObserver = {
onItemAdded: function(aItemId, aNewParent, aNewIndex) {
onItemAdded: function(aItemId, aNewParent, aNewIndex, aItemType) {
observer.itemId = aItemId;
},
onItemChanged: function(aItemId, aProperty, aValue) {
onItemChanged: function(aItemId, aProperty, aNewValue, aLastModified,
aItemType) {
if (aProperty == "uri")
do_check_eq(observer.itemId, aItemId);
}

View File

@ -64,12 +64,12 @@ DummyObserver.prototype = {
// bookmark observer
//onBeginUpdateBatch: function() {},
//onEndUpdateBatch: function() {},
onItemAdded: function(aItemId, aParentId, aIndex) {
onItemAdded: function(aItemId, aParentId, aIndex, aItemType) {
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
os.notifyObservers(null, "dummy-observer-item-added", null);
},
onItemChanged: function (aItemId, aProperty, aIsAnnotationProperty, aValue) {},
onItemChanged: function () {},
onBeforeItemRemoved: function() {},
onItemRemoved: function() {},
onItemVisited: function() {},

View File

@ -51,7 +51,7 @@
var observer = {
onBeginUpdateBatch: function() {},
onEndUpdateBatch: function() {},
onItemAdded: function(id, folder, index) {
onItemAdded: function(id, folder, index, itemType) {
do_check_true(id > 0);
},
onBeforeItemRemoved: function() {},

View File

@ -65,43 +65,52 @@ function add_visit(aURI, aDate) {
}
var viewer = {
insertedItem: null,
itemInserted: function(parent, item, newIndex) {
this.insertedItem = item;
insertedNode: null,
nodeInserted: function(parent, node, newIndex) {
this.insertedNode = node;
},
removedItem: null,
itemRemoved: function(parent, item, oldIndex) {
this.removedItem = item;
removedNode: null,
nodeRemoved: function(parent, node, oldIndex) {
this.removedNode = node;
},
changedItem: null,
itemChanged: function(item) {
this.changedItem = item;
newTitle: "",
nodeChangedByTitle: null,
nodeTitleChanged: function(node, newTitle) {
this.nodeChangedByTitle = node;
this.newTitle = newTitle;
},
replacedItem: null,
itemReplaced: function(parent, oldItem, newItem, index) {
dump("itemReplaced: " + newItem.uri + "\n");
this.replacedItem = item;
newAccessCount: 0,
newTime: 0,
nodeChangedByHistoryDetails: null,
nodeHistoryDetailsChanged: function(node,
updatedVisitDate,
updatedVisitCount) {
this.nodeChangedByHistoryDetails = node
this.newTime = updatedVisitDate;
this.newAccessCount = updatedVisitCount;
},
movedItem: null,
itemMoved: function(item, oldParent, oldIndex, newParent, newIndex) {
this.movedItem = item;
replacedNode: null,
nodeReplaced: function(parent, oldNode, newNode, index) {
this.replacedNode = node;
},
movedNode: null,
nodeMoved: function(node, oldParent, oldIndex, newParent, newIndex) {
this.movedNode = node;
},
openedContainer: null,
containerOpened: function(item) {
this.openedContainer = item;
containerOpened: function(node) {
this.openedContainer = node;
},
closedContainer: null,
containerClosed: function(item) {
this.closedContainer = item;
containerClosed: function(node) {
this.closedContainer = node;
},
invalidatedContainer: null,
invalidateContainer: function(item) {
dump("invalidateContainer()\n");
this.invalidatedContainer = item;
},
allInvalidated: null,
invalidateAll: function() {
this.allInvalidated = true;
invalidateContainer: function(node) {
this.invalidatedContainer = node;
},
sortingMode: null,
sortingChanged: function(sortingMode) {
@ -112,15 +121,15 @@ var viewer = {
addViewObserver: function(observer, ownsWeak) {},
removeViewObserver: function(observer) {},
reset: function() {
this.insertedItem = null;
this.removedItem = null;
this.changedItem = null;
this.replacedItem = null;
this.movedItem = null;
this.insertedNode = null;
this.removedNode = null;
this.nodeChangedByTitle = null;
this.nodeChangedByHistoryDetails = null;
this.replacedNode = null;
this.movedNode = null;
this.openedContainer = null;
this.closedContainer = null;
this.invalidatedContainer = null;
this.allInvalidated = null;
this.sortingMode = null;
}
};
@ -141,38 +150,38 @@ function run_test() {
// nsINavHistoryResultViewer.containerOpened
do_check_neq(viewer.openedContainer, null);
// nsINavHistoryResultViewer.itemInserted
// nsINavHistoryResultViewer.nodeInserted
// add a visit
var testURI = uri("http://mozilla.com");
add_visit(testURI);
do_check_eq(testURI.spec, viewer.insertedItem.uri);
do_check_eq(testURI.spec, viewer.insertedNode.uri);
// nsINavHistoryResultViewer.itemChanged
// adding a visit causes itemChanged for the folder
do_check_eq(root.uri, viewer.changedItem.uri);
// nsINavHistoryResultViewer.nodeHistoryDetailsChanged
// adding a visit causes nodeHistoryDetailsChanged for the folder
do_check_eq(root.uri, viewer.nodeChangedByHistoryDetails.uri);
// nsINavHistoryResultViewer.itemChanged for a leaf node
// nsINavHistoryResultViewer.itemTitleChanged for a leaf node
bhist.addPageWithDetails(testURI, "baz", Date.now() * 1000);
do_check_eq(viewer.changedItem.title, "baz");
do_check_eq(viewer.nodeChangedByTitle.title, "baz");
// nsINavHistoryResultViewer.itemRemoved
// nsINavHistoryResultViewer.nodeRemoved
var removedURI = uri("http://google.com");
add_visit(removedURI);
bhist.removePage(removedURI);
do_check_eq(removedURI.spec, viewer.removedItem.uri);
do_check_eq(removedURI.spec, viewer.removedNode.uri);
// XXX nsINavHistoryResultViewer.itemReplaced
// NHQRN.onVisit()->NHCRN.MergeResults()->NHCRN.ReplaceChildURIAt()->NHRV.ItemReplaced()
// XXX nsINavHistoryResultViewer.nodeReplaced
// NHQRN.onVisit()->NHCRN.MergeResults()->NHCRN.ReplaceChildURIAt()->NHRV.NodeReplaced()
// nsINavHistoryResultViewer.invalidateContainer
bhist.removePagesFromHost("mozilla.com", false);
do_check_eq(root.uri, viewer.invalidatedContainer.uri);
// nsINavHistoryResultViewer.invalidateAll
// nsINavHistoryResultViewer.sortingChanged
viewer.invalidatedContainer = null;
result.sortingMode = options.SORT_BY_TITLE_ASCENDING;
do_check_true(viewer.allInvalidated);
do_check_eq(viewer.sortingMode, options.SORT_BY_TITLE_ASCENDING);
do_check_eq(viewer.invalidatedContainer, result.root);
// nsINavHistoryResultViewer.containerClosed
root.containerOpen = false;
@ -201,38 +210,39 @@ function run_test() {
// nsINavHistoryResultViewer.containerOpened
do_check_neq(viewer.openedContainer, null);
// nsINavHistoryResultViewer.itemInserted
// nsINavHistoryResultViewer.nodeInserted
// add a bookmark
var testBookmark = bmsvc.insertBookmark(bmsvc.bookmarksMenuFolder, testURI, bmsvc.DEFAULT_INDEX, "foo");
do_check_eq("foo", viewer.insertedItem.title);
do_check_eq(testURI.spec, viewer.insertedItem.uri);
do_check_eq("foo", viewer.insertedNode.title);
do_check_eq(testURI.spec, viewer.insertedNode.uri);
// nsINavHistoryResultViewer.itemChanged
// adding a visit causes itemChanged for the folder
do_check_eq(root.uri, viewer.changedItem.uri);
// nsINavHistoryResultViewer.nodeHistoryDetailsChanged
// adding a visit causes nodeHistoryDetailsChanged for the folder
do_check_eq(root.uri, viewer.nodeChangedByHistoryDetails.uri);
// nsINavHistoryResultViewer.itemChanged for a leaf node
// nsINavHistoryResultViewer.nodeTitleChanged for a leaf node
bmsvc.setItemTitle(testBookmark, "baz");
do_check_eq(viewer.changedItem.title, "baz");
do_check_eq(viewer.nodeChangedByTitle.title, "baz");
do_check_eq(viewer.newTitle, "baz");
var testBookmark2 = bmsvc.insertBookmark(bmsvc.bookmarksMenuFolder, uri("http://google.com"), bmsvc.DEFAULT_INDEX, "foo");
bmsvc.moveItem(testBookmark2, bmsvc.bookmarksMenuFolder, 0);
do_check_eq(viewer.movedItem.itemId, testBookmark2);
do_check_eq(viewer.movedNode.itemId, testBookmark2);
// nsINavHistoryResultViewer.itemRemoved
// nsINavHistoryResultViewer.nodeRemoved
bmsvc.removeItem(testBookmark2);
do_check_eq(testBookmark2, viewer.removedItem.itemId);
do_check_eq(testBookmark2, viewer.removedNode.itemId);
// XXX nsINavHistoryResultViewer.itemReplaced
// NHQRN.onVisit()->NHCRN.MergeResults()->NHCRN.ReplaceChildURIAt()->NHRV.ItemReplaced()
// XXX nsINavHistoryResultViewer.nodeReplaced
// NHQRN.onVisit()->NHCRN.MergeResults()->NHCRN.ReplaceChildURIAt()->NHRV.NodeReplaced()
// XXX nsINavHistoryResultViewer.invalidateContainer
// nsINavHistoryResultViewer.invalidateAll
// nsINavHistoryResultViewer.sortingChanged
viewer.invalidatedContainer = null;
result.sortingMode = options.SORT_BY_TITLE_ASCENDING;
do_check_true(viewer.allInvalidated);
do_check_eq(viewer.sortingMode, options.SORT_BY_TITLE_ASCENDING);
do_check_eq(viewer.invalidatedContainer, result.root);
// nsINavHistoryResultViewer.containerClosed
root.containerOpen = false;