Backout bug 498130 due to persistent startup crash on Windows Mobile (bug 519854)

This commit is contained in:
Dietrich Ayala 2009-09-30 17:21:39 -07:00
parent 540fe200cc
commit 890e1e64fa
38 changed files with 1627 additions and 1548 deletions

View File

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

View File

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

View File

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

View File

@ -78,6 +78,8 @@
<!-- 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"/>
@ -534,9 +536,9 @@
extends="chrome://browser/content/places/menu.xml#places-popup-base">
<implementation>
<destructor><![CDATA[
this._resultNode = null;
if (this._result) {
this._resultNode.containerOpen = false;
this._resultNode = null;
this._result.root.containerOpen = false;
this._result.viewer = null;
this._result = null;
}
@ -572,13 +574,12 @@
var resultNode = popup._resultNode;
if (!resultNode.containerOpen)
resultNode.containerOpen = true;
if (!popup.parentNode._built)
if (!popup._built)
this._rebuild(popup);
]]></body>
</method>
<field name="_result">null</field>
<field name="_resultNode">null</field>
<!-- nsIPlacesView -->
<method name="getResult">
@ -598,12 +599,20 @@
<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)
@ -616,7 +625,8 @@
<parameter name="aParentPopup"/>
<parameter name="aBefore"/>
<body><![CDATA[
var element = PlacesUIUtils.createMenuItemForNode(aChild);
var element =
PlacesUIUtils.createMenuItemForNode(aChild, this._containerNodesMap);
if (aBefore)
aParentPopup.insertBefore(element, aBefore);
@ -679,7 +689,7 @@
if (aPopup._startMarker == -1 && aPopup._endMarker == -1)
this._showEmptyMenuItem(aPopup);
}
aPopup.parentNode._built = true;
aPopup._built = true;
]]></body>
</method>
@ -687,6 +697,18 @@
<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;
},
@ -699,168 +721,130 @@
// we should do nothing.
if (this._self._result != val) {
if (this._self._result)
this._self._resultNode.containerOpen = false;
this._self.parentNode._built = false;
this._self._result.root.containerOpen = false;
this._built = false;
this._self._containerNodesMap = [];
this._self._resultNode = val.root;
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;
},
nodeInserted: function PMV_nodeInserted(aParentNode, aNode, aIndex) {
let parentElt = aParentNode._DOMElement;
NS_ASSERT(parentElt, "parent node must have _DOMElement set");
if (!parentElt._built)
itemInserted: function PMV_itemInserted(aParentNode, aNode, aIndex) {
var popup = this._getPopupForContainer(aParentNode);
if (!popup._built)
return;
// 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;
var index = popup._startMarker + 1 + aIndex;
var before = popup.childNodes[index] || null;
this._self.insertNewItem(aNode, popup, before);
if (popup._emptyMenuItem)
popup._emptyMenuItem.hidden = true;
},
nodeRemoved: function PMV_nodeRemoved(aParentNode, aNode, aIndex) {
let parentElt = aParentNode._DOMElement;
NS_ASSERT(parentElt, "parent node must have _DOMElement set");
if (!parentElt._built)
itemRemoved: function PMV_itemRemoved(aParentNode, aNode, aIndex) {
var popup = this._getPopupForContainer(aParentNode);
if (!popup._built)
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--;
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;
}
}
},
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)
itemMoved:
function PMV_itemMoved(aItem, aOldParent, aOldIndex, aNewParent,
aNewIndex) {
// This cannot actually happen yet (see IDL)
if (aNewParent != aOldParent)
return;
// Move the node.
let popup = nodeElt.parentNode;
popup.removeChild(nodeElt);
popup.insertBefore(nodeElt, popup.childNodes[aNewIndex]);
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;
}
}
},
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)
itemChanged: function PMV_itemChanged(aNode) {
// this check can be removed once we fix bug #382397
var parentNode = aNode.parent;
if (!parentNode)
return;
nodeElt.label = aNewTitle || PlacesUIUtils.getBestTitle(aNode);
},
if (PlacesUtils.nodeIsSeparator(aNode)) {
// nothing to do when a separator changes
return;
}
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)
var popup = this._getPopupForContainer(parentNode);
if (!popup._built)
return;
var icon = aNode.icon;
if (icon) {
if (nodeElt.getAttribute("image") != icon)
nodeElt.setAttribute("image", icon);
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);
}
else
nodeElt.removeAttribute("image");
},
menuitem.removeAttribute("image");
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");
var title = PlacesUIUtils.getBestTitle(aNode);
if (menuitem.getAttribute("label") != title)
menuitem.setAttribute("label", title);
if (!nodeElt.hasAttribute("livemark"))
nodeElt.setAttribute("livemark", "true");
// Add or remove the livemark status menuitem.
PlacesUIUtils.ensureLivemarkStatusMenuItem(nodeElt.firstChild);
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));
}
},
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)
itemReplaced:
function PMV_itemReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
var popup = this._getPopupForContainer(aParentNode);
if (!popup._built)
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);
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;
}
}
},
containerOpened: function PMV_containerOpened(aNode) {
@ -870,19 +854,45 @@
containerClosed: function PMV_containerClosed(aNode) {
this.invalidateContainer(aNode);
},
invalidateContainer: function PMV_invalidateContainer(aContainer) {
// Do nothing if the entire view is already marked un-built.
if (!this._self.parentNode._built)
if (!this._self._built)
return;
let containerNodeElt = aContainer._DOMElement;
NS_ASSERT(containerNodeElt, "node must have _DOMElement set");
containerNodeElt._built = false;
function isChildOf(node, container) {
var parent = node.parent;
while (parent) {
if (parent == container)
return true;
parent = parent.parent;
}
return false;
}
// If the menupopup is open we should live-update it.
if (containerNodeElt.open)
this._self._rebuild(containerNodeElt.firstChild);
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;
},
sortingChanged: function PMV_sortingChanged(aSortingMode) {
@ -904,7 +914,6 @@
PlacesUtils.history.executeQueries(queries.value,
queries.value.length,
options.value);
result.viewer = this._viewer;
return val;
]]></setter>

View File

@ -24,7 +24,6 @@
# 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
@ -38,7 +37,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 [
@ -100,8 +99,6 @@
window.removeEventListener("resize", this, false);
if (this._result) {
this._resultNode.containerOpen = false;
this._resultNode = null;
this._result.viewer = null;
this._result = null;
}
@ -113,48 +110,17 @@
<method name="_init">
<body><![CDATA[
// 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._controller = new PlacesController(this);
this.controllers.appendController(this._controller);
// 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.
this._scrollbox.addEventListener("overflow", this, false);
this._scrollbox.addEventListener("underflow", this, false);
window.addEventListener("resize", this, false);
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);
if (this.hasAttribute("place")) {
// Do the initial build.
this.place = this.place;
}
]]></body>
</method>
@ -176,6 +142,9 @@
<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"
@ -191,7 +160,7 @@
<!-- nsIPlacesView -->
<method name="getResultNode">
<body><![CDATA[
return this._resultNode;
return this._result.root;
]]></body>
</method>
@ -206,9 +175,10 @@
while (this.hasChildNodes())
this.removeChild(this.firstChild);
let cc = this._resultNode.childCount;
var rootNode = this._result.root;
var cc = rootNode.childCount;
for (let i = 0; i < cc; ++i)
this.insertNewItem(this._resultNode.getChild(i), null);
this.insertNewItem(rootNode.getChild(i), null);
if (this._chevronPopup.hasAttribute("type")) {
// Chevron has already been initialized, but since we are forcing
@ -216,6 +186,9 @@
// 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>
@ -231,9 +204,12 @@
button = document.createElement("toolbarbutton");
button.className = "bookmark-item";
button.setAttribute("label", aChild.title);
var icon = aChild.icon;
if (icon)
button.setAttribute("image", icon);
var iconURI = aChild.icon;
var iconURISpec = "";
if (iconURI) {
iconURISpec = iconURI.spec;
button.setAttribute("image", iconURISpec);
}
if (PlacesUtils.containerTypes.indexOf(type) != -1) {
button.setAttribute("type", "menu");
@ -250,17 +226,21 @@
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;
aChild._DOMElement = button;
button.node.viewIndex = 0;
if (aBefore)
this.insertBefore(button, aBefore);
else
@ -271,12 +251,20 @@
<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>
@ -390,13 +378,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 =
@ -406,7 +394,7 @@
}
catch(ex) {
// Invalid query, or had no results.
// This is valid, eg: user deletes his bookmarks toolbar folder.
// This is valid, eg: user deletes their bookmarks toolbar folder.
}
return val;
]]></setter>
@ -414,7 +402,7 @@
<!-- nsIPlacesView -->
<property name="hasSelection">
<getter><![CDATA[
<getter><![CDATA[
return this.selectedNode != null;
]]></getter>
</property>
@ -465,9 +453,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._resultNode;
var container = this._result.root;
var orientation = Ci.nsITreeView.DROP_BEFORE;
var isTag = false;
@ -498,7 +486,7 @@
<!-- nsIPlacesView -->
<method name="selectAll">
<body><![CDATA[
<body><![CDATA[
// Nothing
]]></body>
</method>
@ -513,6 +501,18 @@
<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,235 +525,242 @@
// we should do nothing.
if (this._self._result != val) {
if (this._self._result)
this._self._resultNode.containerOpen = false;
this._self._result.root.containerOpen = false;
this._self._containerNodesMap = [];
this._self._result = val;
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;
if (val) // this calls _rebuild through invalidateContainer
val.root.containerOpen = true;
}
return val;
},
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;
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;
this._self.insertNewItem(aNode,
aIndex < children.length ? children[aIndex] : null);
this._self.updateChevron();
}
else if (parentElt._built) {
// Node is within a built menu.
let popup = parentElt.firstChild;
let before = popup.childNodes[aIndex] || null;
else {
var popup = this._getPopupForContainer(aParentNode);
if (!popup._built)
return;
var before = popup.childNodes[aIndex] || null;
this._self.insertNewItemToPopup(aNode, popup, before);
if (popup._emptyMenuItem)
popup._emptyMenuItem.hidden = true;
}
},
nodeRemoved: function TV_V_nodeRemoved(aParentNode, aNode, aIndex) {
let parentElt = aParentNode._DOMElement;
let nodeElt = aNode._DOMElement;
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--;
}
},
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;
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]);
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;
}
}
this._self.updateChevron();
}
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]);
}
},
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 (nodeElt.parentNode == this._self) {
// Node is on the toolbar
nodeElt.label = aNewTitle;
this._self.updateChevron();
}
else {
// Node is within a built menu.
nodeElt.label = aNewTitle || PlacesUIUtils.getBestTitle(aNode);
var popup = this._getPopupForContainer(aParentNode);
if (!popup._built)
return;
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;
}
}
}
},
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)
itemMoved:
function TV_V_itemMoved(aItem, aOldParent, aOldIndex, aNewParent,
aNewIndex) {
// This cannot actually happen yet (see IDL)
if (aNewParent != aOldParent)
return;
let icon = aNode.icon;
if (icon) {
if (nodeElt.getAttribute("image") != icon)
nodeElt.setAttribute("image", icon);
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;
}
}
}
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;
}
}
}
},
itemChanged: function TV_V_itemChanged(aNode) {
// this check can be removed once we fix bug #382397
var parentNode = aNode.parent;
if (!parentNode)
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;
}
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);
}
var iconURI = aNode.icon;
if (iconURI) {
var spec = iconURI.spec;
if (element.getAttribute("image") != spec)
element.setAttribute("image", spec);
}
else
nodeElt.removeAttribute("image");
},
element.removeAttribute("image");
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 (element.getAttribute("label") != title) {
element.setAttribute("label", title);
if (onToolbar)
this._self.updateChevron();
}
if (!nodeElt.hasAttribute("livemark"))
nodeElt.setAttribute("livemark", "true");
// Add or remove the livemark status menuitem.
PlacesUIUtils.ensureLivemarkStatusMenuItem(nodeElt.firstChild);
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));
}
},
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);
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;
}
}
}
},
containerOpened: function TV_V_containerOpened(aContainer) {
this.invalidateContainer(aContainer);
containerOpened: function TV_V_containerOpened(aNode) {
this.invalidateContainer(aNode);
},
containerClosed: function TV_V_containerClosed(aContainer) {
this.invalidateContainer(aContainer);
containerClosed: function TV_V_containerClosed(aNode) {
this.invalidateContainer(aNode);
},
invalidateContainer: function TV_V_invalidateContainer(aContainer) {
let containerNodeElt = aContainer._DOMElement;
NS_ASSERT(containerNodeElt, "node must have _DOMElement set");
if (containerNodeElt == this._self) {
// Container is the toolbar itself.
if (aContainer == this._self.getResultNode()) {
this._self._containerNodesMap.splice(0);
this._self._rebuild();
return;
}
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);
function isChildOf(node, container) {
var parent = node.parent;
while (parent) {
if (parent == container)
return true;
parent = parent.parent;
}
return false;
}
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) {
@ -801,7 +808,8 @@
<parameter name="aParentPopup"/>
<parameter name="aBefore"/>
<body><![CDATA[
var element = PlacesUIUtils.createMenuItemForNode(aChild);
var element =
PlacesUIUtils.createMenuItemForNode(aChild, this._containerNodesMap);
if (aBefore)
aParentPopup.insertBefore(element, aBefore);
@ -825,7 +833,7 @@
<method name="_containerPopupShowing">
<parameter name="aPopup"/>
<body><![CDATA[
if (!aPopup.parentNode._built)
if (!aPopup._built)
this._rebuildPopup(aPopup);
]]></body>
</method>
@ -860,7 +868,7 @@
if (aPopup._startMarker == -1 && aPopup._endMarker == -1)
this._showEmptyMenuItem(aPopup);
}
aPopup.parentNode._built = true;
aPopup._built = true;
]]></body>
</method>
@ -906,7 +914,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(this._resultNode))
if (!PlacesUtils.nodeIsFolder(result.root))
return null;
var dropPoint = { ip: null, beforeIndex: null, folderNode: null };
@ -924,7 +932,7 @@
: (aEvent.clientX < nodeRect.left + threshold)) {
// Drop before this folder.
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
nodeIndex, Ci.nsITreeView.DROP_BEFORE);
dropPoint.beforeIndex = nodeIndex;
}
@ -943,7 +951,7 @@
let beforeIndex =
(nodeIndex == this.childNodes.length - 1) ? -1 : nodeIndex + 1;
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
beforeIndex, Ci.nsITreeView.DROP_BEFORE);
dropPoint.beforeIndex = beforeIndex;
}
@ -956,7 +964,7 @@
: (aEvent.clientX < nodeRect.left + threshold)) {
// Drop before this bookmark.
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
nodeIndex, Ci.nsITreeView.DROP_BEFORE);
dropPoint.beforeIndex = nodeIndex;
}
@ -965,7 +973,7 @@
let beforeIndex =
nodeIndex == this.childNodes.length - 1 ? -1 : nodeIndex + 1;
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
beforeIndex, Ci.nsITreeView.DROP_BEFORE);
dropPoint.beforeIndex = beforeIndex;
}
@ -975,7 +983,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(this._resultNode),
new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
-1, Ci.nsITreeView.DROP_BEFORE);
dropPoint.beforeIndex = -1;
}
@ -1208,7 +1216,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.flatList, callback);
var treeView = new PlacesTreeView(this.showRoot, this.flatList, callback);
result.viewer = treeView;
this.view = treeView;
if (!this._controller) {
@ -147,6 +147,21 @@
]]></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";
@ -244,7 +259,7 @@
<method name="selectNode">
<parameter name="node"/>
<body><![CDATA[
var view = this.view;
var view = this.getResultView();
var parent = node.parent;
if (parent && !parent.containerOpen) {
@ -293,6 +308,17 @@
]]></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[
@ -329,7 +355,7 @@
var selection = this.view.selection;
var rc = selection.getRangeCount();
var nodes = [];
var resultview = this.view;
var resultview = this.getResultView();
for (var i = 0; i < rc; ++i) {
var min = { }, max = { };
selection.getRangeAt(i, min, max);
@ -370,7 +396,7 @@
var selection = this.view.selection;
var rc = selection.getRangeCount();
var nodes = [];
var resultview = this.view;
var resultview = this.getResultView();
// 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
@ -411,7 +437,7 @@
var min = { }, max = { };
selection.getRangeAt(0, min, max);
return this.view.nodeForTreeIndex(min.value);
return this.getResultView().nodeForTreeIndex(min.value);
]]></getter>
</property>
@ -452,7 +478,7 @@
// then use getIndexOfNode to find your absolute index in
// the parent container instead.
//
var resultView = this.view;
var resultView = this.getResultView();
var selection = resultView.selection;
var rc = selection.getRangeCount();
var min = { }, max = { };
@ -483,7 +509,7 @@
<parameter name="orientation"/>
<body><![CDATA[
var result = this.getResult();
var resultview = this.view;
var resultview = this.getResultView();
var container = result.root;
var dropNearItemId = -1;
NS_ASSERT(container, "null container");
@ -647,7 +673,7 @@
// For all the nodes we've found, highlight the corresponding
// index in the tree.
var resultview = this.view;
var resultview = this.getResultView();
var selection = this.view.selection;
selection.selectEventsSuppressed = true;
selection.clearSelection();
@ -703,7 +729,7 @@
this.treeBoxObject.getCellAt(aEvent.clientX, aEvent.clientY,
row, col, child);
var node = row.value != -1 ?
this.view.nodeForTreeIndex(row.value) :
this.getResultView().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,12 +1002,17 @@ var PlacesUIUtils = {
* Helper for the toolbar and menu views
*/
createMenuItemForNode:
function PUU_createMenuItemForNode(aNode) {
function PUU_createMenuItemForNode(aNode, aContainersMap) {
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";
@ -1046,6 +1051,8 @@ 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
@ -1053,12 +1060,11 @@ var PlacesUIUtils = {
element.setAttribute("label", this.getBestTitle(aNode));
var icon = aNode.icon;
if (icon)
element.setAttribute("image", icon);
if (iconURISpec)
element.setAttribute("image", iconURISpec);
}
element.node = aNode;
element.node._DOMElement = element;
element.node.viewIndex = 0;
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.removeItem(this._id);
PlacesUtils.bookmarks.removeFolder(this._id);
}
};

View File

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

View File

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

View File

@ -57,7 +57,7 @@ interface nsINavHistoryBatchCallback;
* Observer for bookmark changes.
*/
[scriptable, uuid(1f7e9032-b2c0-4561-b35b-94ba3f8344e2)]
[scriptable, uuid(a3544e1e-36a8-404a-9b30-918abf8e005e)]
interface nsINavBookmarkObserver : nsISupports
{
/**
@ -80,16 +80,13 @@ interface nsINavBookmarkObserver : nsISupports
*
* @param aItemId
* The id of the bookmark that was added.
* @param aParentId
* The id of the folder to which the item was added.
* @param aFolder
* The folder that the item was added to.
* @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 aParentId,
in long aIndex, in unsigned short aItemType);
void onItemAdded(in long long aItemId, in long long aFolder,
in long aIndex);
/**
* Notify this observer that an item is about to be removed. Called before
@ -97,11 +94,8 @@ 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, in unsigned short aItemType);
void onBeforeItemRemoved(in long long aItemId);
/**
* Notify this observer that an item was removed. Called after the actual
@ -109,17 +103,14 @@ interface nsINavBookmarkObserver : nsISupports
* no additional notifications will be sent.
*
* @param aItemId
* The id of the item that was removed.
* @param aParentId
* The id of the folder from which the item was removed.
* The id of the bookmark that was removed.
* @param aFolder
* The folder that the item was removed from.
* @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 aParentId,
in long aIndex, in unsigned short aItemType);
void onItemRemoved(in long long aItemId, in long long aFolder,
in long aIndex);
/**
* Notify this observer that an item's information has changed. This
@ -130,19 +121,8 @@ interface nsINavBookmarkObserver : nsISupports
* @param aProperty
* The property which changed.
* @param aIsAnnotationProperty
* 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).
*
* Is aProperty the name of an item annotation
*
* property = "cleartime": (history was deleted, there is no last visit date):
* value = empty string.
* property = "title": value = new title.
@ -154,10 +134,9 @@ interface nsINavBookmarkObserver : nsISupports
* property = "lastModified": value = PRTime when the item was last modified
* aIsAnnotationProperty = true: value = empty string.
*/
void onItemChanged(in long long aItemId, in ACString aProperty,
void onItemChanged(in long long aBookmarkId, in ACString aProperty,
in boolean aIsAnnotationProperty,
in AUTF8String aNewValue, in PRTime aLastModified,
in unsigned short aItemType);
in AUTF8String aValue);
/**
* Notify that the item was visited. Normally in bookmarks we use the last
@ -177,22 +156,18 @@ interface nsINavBookmarkObserver : nsISupports
* Notify this observer that an item has been moved.
* @param aItemId
* The id of the item that was moved.
* @param aOldParentId
* @param aOldParent
* The id of the old parent.
* @param aOldIndex
* The old index inside the old parent.
* @param aNewParentId
* The old index inside aOldParent.
* @param aNewParent
* The id of the new parent.
* @param aNewIndex
* The index inside the new parent.
* @param aItemType
* The type of the item that was moved (one of the TYPE_* constants
* defined above).
* The foindex inside aNewParent.
*/
void onItemMoved(in long long aItemId,
in long long aOldParentId, in long aOldIndex,
in long long aNewParentId, in long aNewIndex,
in unsigned short aItemType);
in long long aOldParent, in long aOldIndex,
in long long aNewParent, in long aNewIndex);
};
/**
@ -244,7 +219,7 @@ interface nsINavBookmarksService : nsISupports
/**
* Inserts a child bookmark into the given folder.
*
* @param aParentId
* @param aParentFolder
* The id of the parent folder
* @param aURI
* The URI to insert
@ -254,7 +229,7 @@ interface nsINavBookmarksService : nsISupports
* The title for the new bookmark
* @return The ID of the newly-created bookmark.
*/
long long insertBookmark(in long long aParentId, in nsIURI aURI,
long long insertBookmark(in long long aParentFolder, in nsIURI aURI,
in long aIndex, in AUTF8String aTitle);
/**
@ -295,10 +270,22 @@ 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 aItemId
* @param folder
* The id of the folder to remove.
* @return An object implementing nsITransaction that can be used to undo
* or redo the action.
@ -311,21 +298,21 @@ interface nsINavBookmarksService : nsISupports
* specific IDs (potentially dangerous if abused by other code!) in the
* public API.
*/
nsITransaction getRemoveFolderTransaction(in long long aItemId);
nsITransaction getRemoveFolderTransaction(in long long aFolder);
/**
* Convenience function for container services. Removes
* all children of the given folder.
* @param aItemId
* @param aFolder
* The id of the folder to remove children from.
*/
void removeFolderChildren(in long long aItemId);
void removeFolderChildren(in long long aFolder);
/**
* Moves an item to a different container, preserving its contents.
* @param aItemId
* The id of the item to move
* @param aNewParentId
* @param aNewParent
* The id of the new parent
* @param aIndex
* The index under aNewParent, or DEFAULT_INDEX to append
@ -334,29 +321,48 @@ 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 aNewParentId, in long aIndex);
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);
/**
* Inserts a bookmark separator into the given folder at the given index.
* The separator can be removed using removeChildAt().
* @param aParentId
* The id of the parent folder
* @param aFolder
* Parent folder of the separator
* @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 aParentId, in long aIndex);
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);
/**
* Get the itemId given the containing folder and the index.
* @param aParentId
* The id of the diret parent folder of the item
* @param aFolder
* The direct parent folder of the item
* @param aIndex
* The index of the item within the parent folder.
* Pass DEFAULT_INDEX for the last item.
* The index of the item within aFolder, 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 aParentId, in long aIndex);
long long getIdForItemAt(in long long aFolder, in long aIndex);
/**
* Get a globally unique identifier for an item, meant to be used in
@ -473,10 +479,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 aItemId
* @param aFolder
* the item-id of the folder.
*/
boolean getFolderReadonly(in long long aItemId);
boolean getFolderReadonly(in long long aFolder);
/**
* Sets or unsets the readonly flag from a folder.

View File

@ -21,9 +21,6 @@
*
* 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
@ -58,8 +55,9 @@ interface nsINavHistoryQueryOptions;
interface nsINavHistoryResult;
interface nsINavHistoryBatchCallback;
interface nsITreeColumn;
interface nsIWritablePropertyBag;
[scriptable, uuid(464ae28f-3a9c-4483-afb2-bb0fb0ddb893)]
[scriptable, uuid(47cf89e3-4777-46bf-9677-21793870ce62)]
interface nsINavHistoryResultNode : nsISupports
{
/**
@ -135,7 +133,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 AUTF8String icon;
readonly attribute nsIURI icon;
/**
* This is the number of levels between this node and the top of the
@ -145,6 +143,25 @@ 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
@ -424,8 +441,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 nodeInserted(in nsINavHistoryContainerResultNode aParent,
in nsINavHistoryResultNode aNode,
void itemInserted(in nsINavHistoryContainerResultNode aParent,
in nsINavHistoryResultNode aItem,
in unsigned long aNewIndex);
/**
@ -434,7 +451,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 nodeRemoved(in nsINavHistoryContainerResultNode aParent,
void itemRemoved(in nsINavHistoryContainerResultNode aParent,
in nsINavHistoryResultNode aItem,
in unsigned long aOldIndex);
@ -447,158 +464,53 @@ interface nsINavHistoryResultViewer : nsISupports
* a new node is created for the item, and the itemRemoved/itemAdded methods
* are used.
*/
void nodeMoved(in nsINavHistoryResultNode aNode,
void itemMoved(in nsINavHistoryResultNode aItem,
in nsINavHistoryContainerResultNode aOldParent,
in unsigned long aOldIndex,
in nsINavHistoryContainerResultNode aNewParent,
in unsigned long aNewIndex);
/**
* Called right after aNode's title has changed.
*
* @param aNode
* a result node
* @param aNewTitle
* the new title
* 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.
*/
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);
void itemChanged(in nsINavHistoryResultNode item);
/**
* 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 nodeReplaced(in nsINavHistoryContainerResultNode aParentNode,
in nsINavHistoryResultNode aOldNode,
in nsINavHistoryResultNode aNewNode,
in unsigned long aIndex);
void itemReplaced(in nsINavHistoryContainerResultNode parent,
in nsINavHistoryResultNode oldItem,
in nsINavHistoryResultNode newItem,
in unsigned long index);
/**
* Called after a container node went from closed to opened.
*
* @param aContainerNode
* the container node which was opened
*/
void containerOpened(in nsINavHistoryContainerResultNode aContainerNode);
void containerOpened(in nsINavHistoryContainerResultNode item);
/**
* 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 aContainerNode);
void containerClosed(in nsINavHistoryContainerResultNode item);
/**
* 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 aContainerNode);
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();
/**
* This is called to indicate to the UI that the sort has changed to the
@ -624,8 +536,6 @@ 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,
@ -994,7 +904,7 @@ interface nsINavHistoryQuery : nsISupports
/**
* This object represents the global options for executing a query.
*/
[scriptable, uuid(c6831388-fd4c-46a8-85f3-952917b66d72)]
[scriptable, uuid(b3d5de06-f8ef-4433-84c2-b8b237403b2a)]
interface nsINavHistoryQueryOptions : nsISupports
{
/**
@ -1194,6 +1104,12 @@ 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, aItemType) {
onItemRemoved: function(aItemId, aParentId, aIndex) {
// 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, TYPE_BOOKMARK))
OnItemAdded(*aNewBookmarkId, aFolder, index))
// If the bookmark has been added to a tag container, notify all
// bookmark-folder result nodes which contain a bookmark for the new
@ -1204,12 +1204,8 @@ 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(),
0,
TYPE_BOOKMARK))
OnItemChanged(bookmarks[i], NS_LITERAL_CSTRING("tags"),
PR_FALSE, EmptyCString()))
}
}
}
@ -1256,7 +1252,7 @@ nsNavBookmarks::RemoveItem(PRInt64 aItemId)
}
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnBeforeItemRemoved(aItemId, itemType))
OnBeforeItemRemoved(aItemId))
mozStorageTransaction transaction(mDBConn, PR_FALSE);
@ -1295,7 +1291,7 @@ nsNavBookmarks::RemoveItem(PRInt64 aItemId)
}
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemRemoved(aItemId, folderId, childIndex, itemType))
OnItemRemoved(aItemId, folderId, childIndex))
if (itemType == TYPE_BOOKMARK) {
// If the removed bookmark was a child of a tag container, notify all
@ -1316,12 +1312,8 @@ 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(),
0,
TYPE_BOOKMARK))
OnItemChanged(bookmarks[i], NS_LITERAL_CSTRING("tags"),
PR_FALSE, EmptyCString()))
}
}
}
@ -1430,7 +1422,7 @@ nsNavBookmarks::CreateContainerWithID(PRInt64 aItemId, PRInt64 aParent,
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemAdded(*aNewFolder, aParent, index, containerType))
OnItemAdded(*aNewFolder, aParent, index))
*aIndex = index;
return NS_OK;
@ -1474,7 +1466,7 @@ nsNavBookmarks::InsertSeparator(PRInt64 aParent, PRInt32 aIndex,
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemAdded(*aNewItemId, aParent, index, TYPE_SEPARATOR))
OnItemAdded(*aNewItemId, aParent, index))
return NS_OK;
}
@ -1539,6 +1531,52 @@ 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)
@ -1564,13 +1602,13 @@ nsNavBookmarks::GetParentAndIndexOfFolder(PRInt64 aFolder, PRInt64* aParent,
return NS_OK;
}
NS_HIDDEN_(nsresult)
NS_IMETHODIMP
nsNavBookmarks::RemoveFolder(PRInt64 aFolderId)
{
NS_ENSURE_TRUE(aFolderId != mRoot, NS_ERROR_INVALID_ARG);
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnBeforeItemRemoved(aFolderId, TYPE_FOLDER))
OnBeforeItemRemoved(aFolderId))
mozStorageTransaction transaction(mDBConn, PR_FALSE);
@ -1644,7 +1682,7 @@ nsNavBookmarks::RemoveFolder(PRInt64 aFolderId)
}
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemRemoved(aFolderId, parent, index, TYPE_FOLDER))
OnItemRemoved(aFolderId, parent, index))
return NS_OK;
}
@ -1765,7 +1803,7 @@ nsNavBookmarks::RemoveFolderChildren(PRInt64 aFolderId)
// Notify observers that we are about to remove this child.
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnBeforeItemRemoved(child.itemId, child.itemType))
OnBeforeItemRemoved(child.itemId))
if (child.itemType == TYPE_FOLDER) {
foldersToRemove.AppendLiteral(",");
@ -1840,8 +1878,7 @@ nsNavBookmarks::RemoveFolderChildren(PRInt64 aFolderId)
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemRemoved(child.itemId,
child.parentId,
child.index,
child.itemType));
child.index));
if (child.itemType == TYPE_BOOKMARK) {
// If the removed bookmark was a child of a tag container, notify all
@ -1860,12 +1897,8 @@ 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(),
0,
TYPE_BOOKMARK))
OnItemChanged(bookmarks[i], NS_LITERAL_CSTRING("tags"),
PR_FALSE, EmptyCString()))
}
}
}
@ -2026,7 +2059,7 @@ nsNavBookmarks::MoveItem(PRInt64 aItemId, PRInt64 aNewParent, PRInt32 aIndex)
// notify bookmark observers
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemMoved(aItemId, oldParent, oldIndex, aNewParent,
newIndex, itemType))
newIndex))
// notify dynamic container provider if there is one
if (!folderType.IsEmpty()) {
@ -2040,6 +2073,41 @@ 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)
{
@ -2061,21 +2129,14 @@ nsNavBookmarks::SetItemDateInternal(mozIStorageStatement* aStatement, PRInt64 aI
NS_IMETHODIMP
nsNavBookmarks::SetItemDateAdded(PRInt64 aItemId, PRTime aDateAdded)
{
// GetItemType also ensures that aItemId points to a valid item.
PRUint16 itemType;
nsresult rv = GetItemType(aItemId, &itemType);
NS_ENSURE_ARG_MIN(aItemId, 1);
nsresult rv = SetItemDateInternal(mDBSetItemDateAdded, aItemId, aDateAdded);
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),
aDateAdded,
itemType));
PR_FALSE, nsPrintfCString(16, "%lld", aDateAdded)));
return NS_OK;
}
@ -2102,21 +2163,14 @@ nsNavBookmarks::GetItemDateAdded(PRInt64 aItemId, PRTime *aDateAdded)
NS_IMETHODIMP
nsNavBookmarks::SetItemLastModified(PRInt64 aItemId, PRTime aLastModified)
{
// GetItemType also ensures that aItemId points to a valid item.
PRUint16 itemType;
nsresult rv = GetItemType(aItemId, &itemType);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_ARG_MIN(aItemId, 1);
rv = SetItemDateInternal(mDBSetItemLastModified, aItemId, aLastModified);
nsresult 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),
aLastModified,
itemType));
OnItemChanged(aItemId, NS_LITERAL_CSTRING("lastModified"),
PR_FALSE, nsPrintfCString(16, "%lld", aLastModified)));
return NS_OK;
}
@ -2225,13 +2279,10 @@ nsNavBookmarks::GetItemIdForGUID(const nsAString &aGUID, PRInt64 *aItemId)
NS_IMETHODIMP
nsNavBookmarks::SetItemTitle(PRInt64 aItemId, const nsACString &aTitle)
{
// GetItemType also ensures that aItemId points to a valid item.
PRUint16 itemType;
nsresult rv = GetItemType(aItemId, &itemType);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_ARG_MIN(aItemId, 1);
nsCOMPtr<mozIStorageStatement> statement;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
nsresult 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);
@ -2251,12 +2302,8 @@ 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,
lastModified,
itemType));
OnItemChanged(aItemId, NS_LITERAL_CSTRING("title"),
PR_FALSE, aTitle));
return NS_OK;
}
@ -2652,8 +2699,7 @@ 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,
lastModified, TYPE_BOOKMARK))
OnItemChanged(aBookmarkId, NS_LITERAL_CSTRING("uri"), PR_FALSE, spec))
return NS_OK;
}
@ -2767,7 +2813,6 @@ nsNavBookmarks::SetItemIndex(PRInt64 aItemId, PRInt32 aNewIndex)
nsresult rv;
PRInt32 oldIndex = 0;
PRInt64 parent = 0;
PRUint16 itemType;
{
mozStorageStatementScoper scopeGet(mDBGetItemProperties);
@ -2781,7 +2826,6 @@ 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);
}
@ -2800,9 +2844,14 @@ 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,
OnItemMoved(aItemId, parent, oldIndex, parent,
aNewIndex, itemType))
OnBeforeItemRemoved(aItemId))
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemRemoved(aItemId, parent, oldIndex))
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemAdded(aItemId, parent, aNewIndex))
return NS_OK;
}
@ -2890,8 +2939,7 @@ 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),
lastModified, TYPE_BOOKMARK))
PR_FALSE, NS_ConvertUTF16toUTF8(aKeyword)))
return NS_OK;
}
@ -3094,12 +3142,8 @@ 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(),
0,
TYPE_BOOKMARK))
OnItemChanged(bookmarks[i], NS_LITERAL_CSTRING("cleartime"),
PR_FALSE, EmptyCString()))
}
}
return NS_OK;
@ -3147,12 +3191,8 @@ 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),
0,
TYPE_BOOKMARK));
OnItemChanged(queries[0]->Folders()[0], NS_LITERAL_CSTRING("favicon"),
PR_FALSE, NS_ConvertUTF16toUTF8(aValue)));
}
else {
// query for all bookmarks for that URI, notify for each
@ -3163,12 +3203,8 @@ 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),
0,
TYPE_BOOKMARK));
OnItemChanged(bookmarks[i], NS_LITERAL_CSTRING("favicon"),
PR_FALSE, NS_ConvertUTF16toUTF8(aValue)));
}
}
}
@ -3194,19 +3230,11 @@ nsNavBookmarks::OnPageAnnotationSet(nsIURI* aPage, const nsACString& aName)
NS_IMETHODIMP
nsNavBookmarks::OnItemAnnotationSet(PRInt64 aItemId, const nsACString& aName)
{
// GetItemType also ensures that aItemId points to a valid item.
PRUint16 itemType;
nsresult rv = GetItemType(aItemId, &itemType);
nsresult rv = SetItemDateInternal(mDBSetItemLastModified, aItemId, PR_Now());
NS_ENSURE_SUCCESS(rv, rv);
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));
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(aItemId, aName, PR_TRUE, EmptyCString()));
return NS_OK;
}
@ -3221,19 +3249,11 @@ nsNavBookmarks::OnPageAnnotationRemoved(nsIURI* aPage, const nsACString& aName)
NS_IMETHODIMP
nsNavBookmarks::OnItemAnnotationRemoved(PRInt64 aItemId, const nsACString& aName)
{
// GetItemType also ensures that aItemId points to a valid item.
PRUint16 itemType;
nsresult rv = GetItemType(aItemId, &itemType);
nsresult rv = SetItemDateInternal(mDBSetItemLastModified, aItemId, PR_Now());
NS_ENSURE_SUCCESS(rv, rv);
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));
ENUMERATE_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver,
OnItemChanged(aItemId, aName, PR_TRUE, EmptyCString()));
return NS_OK;
}

View File

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

View File

@ -170,6 +170,7 @@ 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"
@ -601,6 +602,12 @@ 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);
@ -862,6 +869,10 @@ 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,
@ -1487,6 +1498,20 @@ 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)
@ -1542,6 +1567,7 @@ 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,11 +55,10 @@
#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
@ -87,115 +86,10 @@ 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)
@ -208,9 +102,6 @@ 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
@ -230,23 +121,22 @@ nsNavHistoryResultNode::nsNavHistoryResultNode(
mItemId(-1),
mDateAdded(0),
mLastModified(0),
mIndentLevel(-1)
mIndentLevel(-1),
mViewIndex(-1)
{
mTags.SetIsVoid(PR_TRUE);
}
NS_IMETHODIMP
nsNavHistoryResultNode::GetIcon(nsACString& aIcon)
nsNavHistoryResultNode::GetIcon(nsIURI** aURI)
{
if (mFaviconURI.IsEmpty()) {
aIcon.Truncate();
*aURI = nsnull;
return NS_OK;
}
nsFaviconService* faviconService = nsFaviconService::GetFaviconService();
NS_ENSURE_TRUE(faviconService, NS_ERROR_OUT_OF_MEMORY);
faviconService->GetFaviconSpecForIconString(mFaviconURI, aIcon);
return NS_OK;
return faviconService->GetFaviconLinkForIconString(mFaviconURI, aURI);
}
NS_IMETHODIMP
@ -322,6 +212,15 @@ 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
@ -330,6 +229,7 @@ void
nsNavHistoryResultNode::OnRemoving()
{
mParent = nsnull;
mViewIndex = -1;
}
@ -501,30 +401,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;
}
// 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;
if (result->mRootNode == this && result->mView)
return PR_TRUE;
return PR_FALSE;
}
@ -703,11 +603,6 @@ 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) {
@ -715,27 +610,26 @@ 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 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;
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)) {
if ((sortingByVisitCount && aAccessCountChange != 0) ||
(sortingByTime && timeChanged)) {
PRUint32 ourIndex = mParent->FindChild(this);
EnsureItemPosition(ourIndex);
resorted = EnsureItemPosition(ourIndex);
}
if (!resorted) {
// repaint visible rows
nsNavHistoryResult* result = GetResult();
if (result && result->GetView() && mParent->AreChildrenVisible()) {
result->GetView()->ItemChanged(static_cast<nsINavHistoryContainerResultNode*>(mParent));
}
}
mParent->ReverseUpdateStats(aAccessCountChange);
@ -1344,6 +1238,29 @@ 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
@ -1386,6 +1303,7 @@ 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()) {
@ -1404,9 +1322,8 @@ nsNavHistoryContainerResultNode::InsertChildAt(nsNavHistoryResultNode* aNode,
if (mTime < aNode->mTime)
mTime = aNode->mTime;
if (result->GetView() && (!mParent || mParent->AreChildrenVisible()))
result->GetView()->NodeHistoryDetailsChanged(
static_cast<nsINavHistoryContainerResultNode*>(this), mTime,
mAccessCount);
result->GetView()->ItemChanged(
static_cast<nsINavHistoryContainerResultNode*>(this));
ReverseUpdateStats(aNode->mAccessCount);
}
@ -1414,7 +1331,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()->NodeInserted(this, aNode, aIndex);
result->GetView()->ItemInserted(this, aNode, aIndex);
return NS_OK;
}
@ -1495,7 +1412,7 @@ nsNavHistoryContainerResultNode::EnsureItemPosition(PRUint32 aIndex) {
NS_ENSURE_TRUE(result, PR_TRUE);
if (result->GetView() && AreChildrenVisible())
result->GetView()->NodeMoved(node, this, aIndex, this, newIndex);
result->GetView()->ItemMoved(node, this, aIndex, this, newIndex);
return PR_TRUE;
}
@ -1610,7 +1527,7 @@ nsNavHistoryContainerResultNode::ReplaceChildURIAt(PRUint32 aIndex,
nsNavHistoryResult* result = GetResult();
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
if (result->GetView() && AreChildrenVisible())
result->GetView()->NodeReplaced(this, oldItem, aNode, aIndex);
result->GetView()->ItemReplaced(this, oldItem, aNode, aIndex);
mChildren[aIndex]->OnRemoving();
return NS_OK;
@ -1651,7 +1568,7 @@ nsNavHistoryContainerResultNode::RemoveChildAt(PRInt32 aIndex,
// remove from our list and notify the tree
mChildren.RemoveObjectAt(aIndex);
if (result->GetView() && AreChildrenVisible())
result->GetView()->NodeRemoved(this, oldNode, aIndex);
result->GetView()->ItemRemoved(this, oldNode, aIndex);
if (! aIsTemporary) {
ReverseUpdateStats(mAccessCount - oldAccessCount);
@ -1705,7 +1622,7 @@ nsNavHistoryContainerResultNode::RecursiveFindURIs(PRBool aOnlyOne,
void
nsNavHistoryContainerResultNode::UpdateURIs(PRBool aRecursive, PRBool aOnlyOne,
PRBool aUpdateSort, const nsCString& aSpec,
void (*aCallback)(nsNavHistoryResultNode*,void*, nsNavHistoryResult*), void* aClosure)
void (*aCallback)(nsNavHistoryResultNode*,void*), void* aClosure)
{
nsNavHistoryResult* result = GetResult();
if (! result) {
@ -1746,12 +1663,11 @@ 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, result);
PRBool childrenVisible = result->GetView() != nsnull && parent->AreChildrenVisible();
aCallback(node, aClosure);
if (oldAccessCount != node->mAccessCount || oldTime != node->mTime) {
// need to update/redraw the parent
@ -1759,18 +1675,18 @@ nsNavHistoryContainerResultNode::UpdateURIs(PRBool aRecursive, PRBool aOnlyOne,
if (node->mTime > parent->mTime)
parent->mTime = node->mTime;
if (childrenVisible)
result->GetView()->NodeHistoryDetailsChanged(
static_cast<nsINavHistoryContainerResultNode*>(parent),
parent->mTime,
parent->mAccessCount);
result->GetView()->ItemChanged(
static_cast<nsINavHistoryContainerResultNode*>(parent));
parent->ReverseUpdateStats(node->mAccessCount - oldAccessCount);
}
if (aUpdateSort) {
PRInt32 childIndex = parent->FindChild(node);
NS_ASSERTION(childIndex >= 0, "Could not find child we just got a reference to");
if (childIndex >= 0)
parent->EnsureItemPosition(childIndex);
if ((childIndex < 0 || !parent->EnsureItemPosition(childIndex) && childrenVisible)) {
result->GetView()->ItemChanged(node);
}
} else if (childrenVisible) {
result->GetView()->ItemChanged(node);
}
}
}
@ -1784,16 +1700,10 @@ nsNavHistoryContainerResultNode::UpdateURIs(PRBool aRecursive, PRBool aOnlyOne,
// their own callbacks registered.
static void setTitleCallback(
nsNavHistoryResultNode* aNode, void* aClosure,
nsNavHistoryResult* aResult)
nsNavHistoryResultNode* aNode, void* aClosure)
{
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,
@ -2961,16 +2871,10 @@ nsNavHistoryQueryResultNode::OnClearHistory()
//
static void setFaviconCallback(
nsNavHistoryResultNode* aNode, void* aClosure,
nsNavHistoryResult* aResult)
nsNavHistoryResultNode* aNode, void* aClosure)
{
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,
@ -3013,6 +2917,19 @@ 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
@ -3025,57 +2942,41 @@ nsNavHistoryQueryResultNode::OnItemAdded(PRInt64 aItemId,
PRInt32 aIndex,
PRUint16 aItemType)
{
if (aItemType == nsINavBookmarksService::TYPE_BOOKMARK &&
mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
return Refresh();
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnBeforeItemRemoved(PRInt64 aItemId,
PRUint16 aItemType)
nsNavHistoryQueryResultNode::OnBeforeItemRemoved(PRInt64 aItemId)
{
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnItemRemoved(PRInt64 aItemId, PRInt64 aFolder,
PRInt32 aIndex, PRUint16 aItemType)
PRInt32 aIndex)
{
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
return Refresh();
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnItemChanged(PRInt64 aItemId,
const nsACString& aProperty,
PRBool aIsAnnotationProperty,
const nsACString& aNewValue,
PRTime aLastModified,
PRUint16 aItemType)
const nsACString& aValue)
{
// 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) {
// Make sure it's not a folder or a separator.
if (aItemType != nsINavBookmarksService::TYPE_BOOKMARK)
return NS_OK;
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
(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,
aNewValue,
aLastModified,
aItemType);
aValue);
}
NS_IMETHODIMP
@ -3090,20 +2991,12 @@ nsNavHistoryQueryResultNode::OnItemVisited(PRInt64 aItemId,
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnItemMoved(PRInt64 aFolder,
PRInt64 aOldParent, PRInt32 aOldIndex,
PRInt64 aNewParent, PRInt32 aNewIndex,
PRUint16 aItemType)
nsNavHistoryQueryResultNode::OnItemMoved(PRInt64 aFolder, PRInt64 aOldParent,
PRInt32 aOldIndex, PRInt64 aNewParent,
PRInt32 aNewIndex)
{
// 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) {
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
return Refresh();
}
return NS_OK;
}
@ -3566,6 +3459,21 @@ 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
@ -3661,8 +3569,7 @@ nsNavHistoryFolderResultNode::OnItemAdded(PRInt64 aItemId,
// nsNavHistoryFolderResultNode::OnBeforeItemRemoved (nsINavBookmarkObserver)
NS_IMETHODIMP
nsNavHistoryFolderResultNode::OnBeforeItemRemoved(PRInt64 aItemId,
PRUint16 aItemType)
nsNavHistoryFolderResultNode::OnBeforeItemRemoved(PRInt64 aItemId)
{
return NS_OK;
}
@ -3673,8 +3580,7 @@ nsNavHistoryFolderResultNode::OnBeforeItemRemoved(PRInt64 aItemId,
NS_IMETHODIMP
nsNavHistoryFolderResultNode::OnItemRemoved(PRInt64 aItemId,
PRInt64 aParentFolder,
PRInt32 aIndex,
PRUint16 aItemType)
PRInt32 aIndex)
{
// 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
@ -3724,70 +3630,61 @@ NS_IMETHODIMP
nsNavHistoryResultNode::OnItemChanged(PRInt64 aItemId,
const nsACString& aProperty,
PRBool aIsAnnotationProperty,
const nsACString& aNewValue,
PRTime aLastModified,
PRUint16 aItemType)
const nsACString& aValue)
{
if (aItemId != mItemId)
return NS_OK;
mLastModified = aLastModified;
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;
}
nsNavHistoryResult* result = GetResult();
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
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 (result->GetView() && (!mParent || mParent->AreChildrenVisible())) {
result->GetView()->ItemChanged(this);
}
if (!mParent)
@ -3806,9 +3703,7 @@ NS_IMETHODIMP
nsNavHistoryFolderResultNode::OnItemChanged(PRInt64 aItemId,
const nsACString& aProperty,
PRBool aIsAnnotationProperty,
const nsACString& aNewValue,
PRTime aLastModified,
PRUint16 aItemType) {
const nsACString& aValue) {
// The query-item's title is used for simple-query nodes
if (mQueryItemId != -1) {
PRBool isTitleChange = aProperty.EqualsLiteral("title");
@ -3820,9 +3715,7 @@ nsNavHistoryFolderResultNode::OnItemChanged(PRInt64 aItemId,
return nsNavHistoryResultNode::OnItemChanged(aItemId, aProperty,
aIsAnnotationProperty,
aNewValue,
aLastModified,
aItemType);
aValue);
}
// nsNavHistoryFolderResultNode::OnItemVisited (nsINavBookmarkObserver)
@ -3838,12 +3731,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();
@ -3860,11 +3753,6 @@ 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 ||
@ -3876,8 +3764,10 @@ 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;
}
@ -3886,7 +3776,7 @@ nsNavHistoryFolderResultNode::OnItemVisited(PRInt64 aItemId,
NS_IMETHODIMP
nsNavHistoryFolderResultNode::OnItemMoved(PRInt64 aItemId, PRInt64 aOldParent,
PRInt32 aOldIndex, PRInt64 aNewParent,
PRInt32 aNewIndex, PRUint16 aItemType)
PRInt32 aNewIndex)
{
NS_ASSERTION(aOldParent == mItemId || aNewParent == mItemId,
"Got a bookmark message that doesn't belong to us");
@ -3917,9 +3807,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, aItemType);
OnItemRemoved(aItemId, aOldParent, aOldIndex);
if (aNewParent == mItemId)
OnItemAdded(aItemId, aNewParent, aNewIndex, aItemType);
OnItemAdded(aItemId, aNewParent, aNewIndex);
}
return NS_OK;
}
@ -3973,10 +3863,24 @@ 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
@ -4059,6 +3963,7 @@ 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;
@ -4100,6 +4005,38 @@ 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
@ -4256,7 +4193,7 @@ nsNavHistoryResult::SetSortingMode(PRUint16 aSortingMode)
if (mView) {
mView->SortingChanged(aSortingMode);
mView->InvalidateContainer(mRootNode);
mView->InvalidateAll();
}
return NS_OK;
}
@ -4368,15 +4305,21 @@ nsNavHistoryResult::OnEndUpdateBatch()
NS_IMETHODIMP
nsNavHistoryResult::OnItemAdded(PRInt64 aItemId,
PRInt64 aParentId,
PRInt32 aIndex,
PRUint16 aItemType)
PRInt64 aFolder,
PRInt32 aIndex)
{
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));
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));
return NS_OK;
}
@ -4384,7 +4327,7 @@ nsNavHistoryResult::OnItemAdded(PRInt64 aItemId,
// nsNavHistoryResult::OnBeforeItemRemoved (nsINavBookmarkObserver)
NS_IMETHODIMP
nsNavHistoryResult::OnBeforeItemRemoved(PRInt64 aItemId, PRUint16 aItemType)
nsNavHistoryResult::OnBeforeItemRemoved(PRInt64 aItemId)
{
// Nobody actually does anything with this method, so we do not need to notify
return NS_OK;
@ -4395,15 +4338,14 @@ nsNavHistoryResult::OnBeforeItemRemoved(PRInt64 aItemId, PRUint16 aItemType)
NS_IMETHODIMP
nsNavHistoryResult::OnItemRemoved(PRInt64 aItemId,
PRInt64 aParentId, PRInt32 aIndex,
PRUint16 aItemType)
PRInt64 aFolder, PRInt32 aIndex)
{
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(aParentId,
OnItemRemoved(aItemId, aParentId, aIndex, aItemType));
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(aFolder,
OnItemRemoved(aItemId, aFolder, aIndex));
ENUMERATE_ALL_BOOKMARKS_OBSERVERS(
OnItemRemoved(aItemId, aParentId, aIndex, aItemType));
OnItemRemoved(aItemId, aFolder, aIndex));
ENUMERATE_HISTORY_OBSERVERS(
OnItemRemoved(aItemId, aParentId, aIndex, aItemType));
OnItemRemoved(aItemId, aFolder, aIndex));
return NS_OK;
}
@ -4414,13 +4356,10 @@ NS_IMETHODIMP
nsNavHistoryResult::OnItemChanged(PRInt64 aItemId,
const nsACString &aProperty,
PRBool aIsAnnotationProperty,
const nsACString &aNewValue,
PRTime aLastModified,
PRUint16 aItemType)
const nsACString &aValue)
{
ENUMERATE_ALL_BOOKMARKS_OBSERVERS(
OnItemChanged(aItemId, aProperty, aIsAnnotationProperty, aNewValue,
aLastModified, aItemType));
OnItemChanged(aItemId, aProperty, aIsAnnotationProperty, aValue));
// Note: folder-nodes set their own bookmark observer only once they're
// opened, meaning we cannot optimize this code path for changes done to
@ -4450,8 +4389,7 @@ nsNavHistoryResult::OnItemChanged(PRInt64 aItemId,
if (node &&
(!excludeItems || !(node->IsURI() || node->IsSeparator())) &&
folder->StartIncrementalUpdate()) {
node->OnItemChanged(aItemId, aProperty, aIsAnnotationProperty,
aNewValue, aLastModified, aItemType);
node->OnItemChanged(aItemId, aProperty, aIsAnnotationProperty, aValue);
}
}
}
@ -4496,24 +4434,20 @@ nsNavHistoryResult::OnItemVisited(PRInt64 aItemId, PRInt64 aVisitId,
NS_IMETHODIMP
nsNavHistoryResult::OnItemMoved(PRInt64 aItemId,
PRInt64 aOldParent, PRInt32 aOldIndex,
PRInt64 aNewParent, PRInt32 aNewIndex,
PRUint16 aItemType)
PRInt64 aNewParent, PRInt32 aNewIndex)
{
{ // scope for loop index for VC6's broken for loop scoping
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(aOldParent,
OnItemMoved(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex,
aItemType));
OnItemMoved(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex));
}
if (aNewParent != aOldParent) {
ENUMERATE_BOOKMARK_FOLDER_OBSERVERS(aNewParent,
OnItemMoved(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex,
aItemType));
OnItemMoved(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex));
}
ENUMERATE_ALL_BOOKMARKS_OBSERVERS(OnItemMoved(aItemId, aOldParent, aOldIndex,
aNewParent, aNewIndex,
aItemType));
aNewParent, aNewIndex));
ENUMERATE_HISTORY_OBSERVERS(OnItemMoved(aItemId, aOldParent, aOldIndex,
aNewParent, aNewIndex, aItemType));
aNewParent, aNewIndex));
return NS_OK;
}

View File

@ -51,6 +51,7 @@
#include "nsCycleCollectionParticipant.h"
class nsNavHistory;
class nsIWritablePropertyBag;
class nsNavHistoryQuery;
class nsNavHistoryQueryOptions;
@ -106,6 +107,10 @@ 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
@ -136,6 +141,9 @@ 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
@ -179,6 +187,9 @@ public:
nsCOMPtr<nsINavHistoryResultViewer> mView;
// property bags for all result nodes, see PropertyBagFor
nsInterfaceHashtable<nsISupportsHashKey, nsIWritablePropertyBag> mPropertyBags;
// node observers
PRBool mIsHistoryObserver;
PRBool mIsBookmarkFolderObserver;
@ -224,6 +235,10 @@ 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) \
@ -247,14 +262,16 @@ 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(nsACString& aIcon) \
NS_IMETHOD GetIcon(nsIURI** 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 \
@ -275,9 +292,10 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS(nsNavHistoryResultNode)
NS_IMPLEMENT_SIMPLE_RESULTNODE
NS_IMETHOD GetIcon(nsACString& aIcon);
NS_IMETHOD GetIcon(nsIURI** 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)
@ -291,9 +309,7 @@ public:
NS_IMETHOD OnItemChanged(PRInt64 aItemId,
const nsACString &aProperty,
PRBool aIsAnnotationProperty,
const nsACString &aValue,
PRTime aNewLastModified,
PRUint16 aItemType);
const nsACString &aValue);
public:
@ -392,6 +408,14 @@ 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)
@ -626,6 +650,8 @@ 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
@ -648,7 +674,7 @@ public:
nsCOMArray<nsNavHistoryResultNode>* aMatches);
void UpdateURIs(PRBool aRecursive, PRBool aOnlyOne, PRBool aUpdateSort,
const nsCString& aSpec,
void (*aCallback)(nsNavHistoryResultNode*,void*, nsNavHistoryResult*),
void (*aCallback)(nsNavHistoryResultNode*,void*),
void* aClosure);
nsresult ChangeTitles(nsIURI* aURI, const nsACString& aNewTitle,
PRBool aRecursive, PRBool aOnlyOne);
@ -699,6 +725,7 @@ public:
virtual nsresult OpenContainer();
NS_DECL_BOOKMARK_HISTORY_OBSERVER
NS_DECL_EXTENDED_BOOKMARK_OBSERVER
virtual void OnRemoving();
public:
@ -772,6 +799,7 @@ 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,18 +218,17 @@ nsPlacesDBFlush.prototype = {
this._flushWithQueries([kQuerySyncPlacesId, kQuerySyncHistoryVisitsId]);
},
onItemAdded: function(aItemId, aParentId, aIndex, aItemType)
onItemAdded: function(aItemId, aParentId, aIndex)
{
// 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 && aItemType == this._bs.TYPE_BOOKMARK)
if (!this._inBatchMode &&
this._bs.getItemType(aItemId) == this._bs.TYPE_BOOKMARK)
this._flushWithQueries([kQuerySyncPlacesId]);
},
onItemChanged: function DBFlush_onItemChanged(aItemId, aProperty,
aIsAnnotationProperty,
aNewValue, aLastModified,
aItemType)
aIsAnnotationProperty, aValue)
{
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.removeItem(node.itemId);
this._bms.removeFolder(node.itemId);
},
// nsITaggingService
@ -397,21 +397,46 @@ TaggingService.prototype = {
this._inBatch = false;
},
onItemAdded: function(aItemId, aFolderId, aIndex, aItemType) {
onItemAdded: function(aItemId, aFolderId, aIndex) {
// Nothing to do if this is not a tag.
if (aFolderId != this._bms.tagsFolder ||
aItemType != this._bms.TYPE_FOLDER)
if (aFolderId != this._bms.tagsFolder)
return;
this._tagFolders[aItemId] = this._bms.getItemTitle(aItemId);
// 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);
},
onBeforeItemRemoved: function(aItemId, aItemType) {
if (aItemType == this._bms.TYPE_BOOKMARK)
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 {
this._itemsInRemoval[aItemId] = this._bms.getBookmarkURI(aItemId);
}
catch (e) {}
},
onItemRemoved: function(aItemId, aFolderId, aIndex, aItemType) {
onItemRemoved: function(aItemId, aFolderId, aIndex) {
var itemURI = this._itemsInRemoval[aItemId];
delete this._itemsInRemoval[aItemId];
@ -431,16 +456,14 @@ TaggingService.prototype = {
}
},
onItemChanged: function(aItemId, aProperty, aIsAnnotationProperty, aNewValue,
aLastModified, aItemType) {
onItemChanged: function(aItemId, aProperty, aIsAnnotationProperty, aValue) {
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,
aItemType) {
onItemMoved: function(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
if (this._tagFolders[aItemId] && this._bms.tagFolder == aOldParent &&
this._bms.tagFolder != aNewParent)
delete this._tagFolders[aItemId];

View File

@ -47,23 +47,22 @@ try {
var observer = {
onBeginUpdateBatch: function() {},
onEndUpdateBatch: function() {},
onItemAdded: function(id, folder, index, itemType) {
onItemAdded: function(id, folder, index) {
this._itemAddedId = id;
this._itemAddedParent = folder;
this._itemAddedIndex = index;
},
onBeforeItemRemoved: function() {},
onItemRemoved: function() {},
onBeforeItemRemoved: function(id) {},
onItemRemoved: function(id, folder, index) {},
_itemChangedProperty: null,
onItemChanged: function(id, property, isAnnotationProperty, value,
lastModified, itemType) {
onItemChanged: function(id, property, isAnnotationProperty, value) {
this._itemChangedId = id;
this._itemChangedProperty = property;
this._itemChanged_isAnnotationProperty = isAnnotationProperty;
this._itemChangedValue = value;
},
onItemVisited: function() {},
onItemMoved: function() {},
onItemVisited: function(id, visitID, time) {},
onItemMoved: function(id, oldParent, oldIndex, newParent, newIndex) {},
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, itemType) {
onItemAdded: function(id, folder, index) {
this._itemAddedId = id;
this._itemAddedParent = folder;
this._itemAddedIndex = index;
},
onBeforeItemRemoved: function(){},
onItemRemoved: function(id, folder, index, itemType) {
onBeforeItemRemoved: function(id) {
},
onItemRemoved: function(id, folder, index) {
this._itemRemovedId = id;
this._itemRemovedFolder = folder;
this._itemRemovedIndex = index;
},
onItemChanged: function(id, property, isAnnotationProperty, value,
lastModified, itemType) {
onItemChanged: function(id, property, isAnnotationProperty, value) {
this._itemChangedId = id;
this._itemChangedProperty = property;
this._itemChanged_isAnnotationProperty = isAnnotationProperty;
@ -89,8 +89,7 @@ var observer = {
this._itemVisitedVistId = visitID;
this._itemVisitedTime = time;
},
onItemMoved: function(id, oldParent, oldIndex, newParent, newIndex,
itemType) {
onItemMoved: function(id, oldParent, oldIndex, newParent, newIndex) {
this._itemMovedId = id
this._itemMovedOldParent = oldParent;
this._itemMovedOldIndex = oldIndex;
@ -341,6 +340,27 @@ 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,8 +57,6 @@ function Observer(aExpectedId)
Observer.prototype =
{
checked: false,
onItemMovedCalled: false,
onItemRemovedCalled: false,
onBeginUpdateBatch: function() {
},
onEndUpdateBatch: function() {
@ -71,14 +69,13 @@ Observer.prototype =
onItemRemoved: function(id, folder, index) {
do_check_false(this.checked);
do_check_eq(this.removedId, id);
this.onItemRemovedCalled = true;
this.checked = 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) ||
@ -104,7 +101,7 @@ function test_removeItem()
bs.removeItem(id);
// Make sure we were notified!
do_check_true(observer.onItemRemovedCalled);
do_check_true(observer.checked);
bs.removeObserver(observer);
}
@ -119,7 +116,7 @@ function test_removeFolder()
bs.removeItem(id);
// Make sure we were notified!
do_check_true(observer.onItemRemovedCalled);
do_check_true(observer.checked);
bs.removeObserver(observer);
}
@ -136,7 +133,7 @@ function test_removeFolderChildren()
bs.removeFolderChildren(fid);
// Make sure we were notified!
do_check_true(observer.onItemRemovedCalled);
do_check_true(observer.checked);
bs.removeObserver(observer);
}
@ -154,7 +151,7 @@ function test_setItemIndex()
bs.setItemIndex(id, 2);
// Make sure we were notified!
do_check_true(observer.onItemMovedCalled);
do_check_true(observer.checked);
bs.removeObserver(observer);
}

View File

@ -55,6 +55,13 @@ 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, itemType) {
onItemAdded: function(bookmarkId, folderId, index) {
if ( status == 0 ) {
runTest1( folderId );
} else {
runTest2( folderId );
if ( status == 2 ) {
bmsvc.removeObserver(this);
bmsvc.removeItem(gLivemarkId1);
bmsvc.removeItem(gLivemarkId2);
bmsvc.removeFolder(gLivemarkId1);
bmsvc.removeFolder(gLivemarkId2);
SimpleTest.finish();
}
}
},
onBeforeItemRemoved: function(){},
onItemRemoved: function() {},
onItemChanged: function() {}
onItemVisited: function() {}
onItemMoved: function() {}
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){}
};
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.removeItem(gLivemarkId);
bmsvc.removeFolder(gLivemarkId);
SimpleTest.finish();
}
},

View File

@ -53,12 +53,12 @@ var observer =
setTimeout(runTest, 1000);
bmsvc.removeObserver(this);
},
onItemAdded: function(){}.
onBeforeItemRemoved: function(){},
onItemRemoved: function(){},
onItemChanged: function(){},
onItemVisited: function(){},
onItemMoved: function(){},
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){},
};
@ -79,7 +79,7 @@ function runTest() {
}
rootNode.containerOpen = false;
bmsvc.removeItem(gLivemarkId);
bmsvc.removeFolder(gLivemarkId);
SimpleTest.finish();
}

View File

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

View File

@ -51,7 +51,7 @@ var observer =
onBeginUpdateBatch: function(){},
onEndUpdateBatch: function(){
},
onItemAdded: function(itemId, folder, index, itemType) {
onItemAdded: function(itemId, folder, index) {
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(){},
onItemRemoved: function(){},
onItemChanged: function(){},
onItemVisited: function(){},
onItemMoved: function(){},
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){},
};

View File

@ -176,6 +176,7 @@ 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,6 +174,7 @@ 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,6 +463,17 @@ const queryOptionSwitches = [
}
]
},
// showSessions
{
property: "showSessions",
desc: "nsINavHistoryQueryOptions.showSessions",
matches: simplePropertyMatches,
runs: [
function (aQuery, aQueryOptions) {
aQueryOptions.showSessions = true;
}
]
},
// maxResults
{
property: "maxResults",

View File

@ -55,11 +55,10 @@ const kSyncFinished = "places-sync-finished";
// Used to update observer itemId
var bookmarksObserver = {
onItemAdded: function(aItemId, aNewParent, aNewIndex, aItemType) {
onItemAdded: function(aItemId, aNewParent, aNewIndex) {
observer.itemId = aItemId;
},
onItemChanged: function(aItemId, aProperty, aNewValue, aLastModified,
aItemType) {
onItemChanged: function(aItemId, aProperty, aValue) {
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, aItemType) {
onItemAdded: function(aItemId, aParentId, aIndex) {
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
os.notifyObservers(null, "dummy-observer-item-added", null);
},
onItemChanged: function () {},
onItemChanged: function (aItemId, aProperty, aIsAnnotationProperty, aValue) {},
onBeforeItemRemoved: function() {},
onItemRemoved: function() {},
onItemVisited: function() {},

View File

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

View File

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