зеркало из https://github.com/mozilla/gecko-dev.git
Bug 419731 - Changing bookmark title in places should be reflected in tag containers (for mak77@supereva.it, r=mano, a=beltzner)
This commit is contained in:
Родитель
9b4c6077f1
Коммит
aeeedf077c
|
@ -75,15 +75,18 @@ const REMOVE_PAGES_MAX_SINGLEREMOVES = 10;
|
||||||
* insertion point to accommodate the orientation should be done by
|
* insertion point to accommodate the orientation should be done by
|
||||||
* the person who constructs the IP, not the user. The orientation
|
* the person who constructs the IP, not the user. The orientation
|
||||||
* is provided for informational purposes only!
|
* is provided for informational purposes only!
|
||||||
|
* @param [optional] aIsTag
|
||||||
|
* Indicates if parent container is a tag
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function InsertionPoint(aItemId, aIndex, aOrientation) {
|
function InsertionPoint(aItemId, aIndex, aOrientation, aIsTag) {
|
||||||
this.itemId = aItemId;
|
this.itemId = aItemId;
|
||||||
this.index = aIndex;
|
this.index = aIndex;
|
||||||
this.orientation = aOrientation;
|
this.orientation = aOrientation;
|
||||||
|
this.isTag = aIsTag;
|
||||||
}
|
}
|
||||||
InsertionPoint.prototype.toString = function IP_toString() {
|
InsertionPoint.prototype.toString = function IP_toString() {
|
||||||
return "[object InsertionPoint(folder:" + this.itemId + ",index:" + this.index + ",orientation:" + this.orientation + ")]";
|
return "[object InsertionPoint(folder:" + this.itemId + ",index:" + this.index + ",orientation:" + this.orientation + ",isTag:" + this.isTag + ")]";
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -308,7 +311,8 @@ PlacesController.prototype = {
|
||||||
* Determines whether or not nodes can be inserted relative to the selection.
|
* Determines whether or not nodes can be inserted relative to the selection.
|
||||||
*/
|
*/
|
||||||
_canInsert: function PC__canInsert() {
|
_canInsert: function PC__canInsert() {
|
||||||
return this._view.insertionPoint != null;
|
var ip = this._view.insertionPoint;
|
||||||
|
return ip != null && ip.isTag != true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -854,6 +858,18 @@ PlacesController.prototype = {
|
||||||
|
|
||||||
if (PlacesUtils.nodeIsFolder(node))
|
if (PlacesUtils.nodeIsFolder(node))
|
||||||
removedFolders.push(node);
|
removedFolders.push(node);
|
||||||
|
else if (PlacesUtils.nodeIsTagQuery(node.parent)) {
|
||||||
|
var queries = asQuery(node.parent).getQueries({});
|
||||||
|
if (queries.length == 1) {
|
||||||
|
var folders = queries[0].getFolders({});
|
||||||
|
if (folders.length == 1) {
|
||||||
|
var uri = PlacesUtils._uri(node.uri);
|
||||||
|
var tagItemId = folders[0];
|
||||||
|
transactions.push(PlacesUIUtils.ptm.untagURI(uri, [tagItemId]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
transactions.push(PlacesUIUtils.ptm.removeItem(node.itemId));
|
transactions.push(PlacesUIUtils.ptm.removeItem(node.itemId));
|
||||||
}
|
}
|
||||||
|
@ -1337,9 +1353,17 @@ var PlacesControllerDragHelper = {
|
||||||
movedCount++;
|
movedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
transactions.push(PlacesUIUtils.makeTransaction(unwrapped,
|
// if dragging over a tag container we should tag the item
|
||||||
flavor.value, insertionPoint.itemId,
|
if (insertionPoint.isTag) {
|
||||||
index, copy));
|
var uri = PlacesUtils._uri(unwrapped.uri);
|
||||||
|
var tagItemId = insertionPoint.itemId;
|
||||||
|
transactions.push(PlacesUIUtils.ptm.tagURI(uri,[tagItemId]));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
transactions.push(PlacesUIUtils.makeTransaction(unwrapped,
|
||||||
|
flavor.value, insertionPoint.itemId,
|
||||||
|
index, copy));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var txn = PlacesUIUtils.ptm.aggregateTransactions("DropItems", transactions);
|
var txn = PlacesUIUtils.ptm.aggregateTransactions("DropItems", transactions);
|
||||||
|
|
|
@ -189,12 +189,15 @@
|
||||||
<parameter name="aXferData"/>
|
<parameter name="aXferData"/>
|
||||||
<parameter name="aDragAction"/>
|
<parameter name="aDragAction"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
if (aEvent.ctrlKey)
|
// Force a copy action if parent node is a query
|
||||||
|
if (aEvent.ctrlKey ||
|
||||||
|
PlacesUtils.nodeIsQuery(aEvent.target.node.parent))
|
||||||
aDragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
aDragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
||||||
|
|
||||||
// activate the view and cache the dragged node
|
// activate the view and cache the dragged node
|
||||||
this._rootView._draggedNode = aEvent.target.node;
|
this._rootView._draggedNode = aEvent.target.node;
|
||||||
this._rootView.focus();
|
this._rootView.focus();
|
||||||
|
|
||||||
aXferData.data = this._rootView.controller
|
aXferData.data = this._rootView.controller
|
||||||
.getTransferData(aDragAction.action);
|
.getTransferData(aDragAction.action);
|
||||||
]]></body>
|
]]></body>
|
||||||
|
@ -274,7 +277,8 @@
|
||||||
var nodeY = xulNode.boxObject.y - popupY;
|
var nodeY = xulNode.boxObject.y - popupY;
|
||||||
var nodeHeight = xulNode.boxObject.height;
|
var nodeHeight = xulNode.boxObject.height;
|
||||||
if (xulNode.node &&
|
if (xulNode.node &&
|
||||||
PlacesUtils.nodeIsFolder(xulNode.node) &&
|
(PlacesUtils.nodeIsFolder(xulNode.node) ||
|
||||||
|
PlacesUtils.nodeIsTagQuery(xulNode.node)) &&
|
||||||
!PlacesUtils.nodeIsReadOnly(xulNode.node)) {
|
!PlacesUtils.nodeIsReadOnly(xulNode.node)) {
|
||||||
// This is a folder. If the mouse is in the top 25% of the
|
// This is a folder. If the mouse is in the top 25% of the
|
||||||
// node, drop above the folder. If it's in the middle
|
// node, drop above the folder. If it's in the middle
|
||||||
|
@ -893,8 +897,12 @@
|
||||||
// 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 = -1;
|
var index = -1;
|
||||||
var folderId = 0;
|
var folderId = 0;
|
||||||
if (PlacesUtils.nodeIsFolder(this._resultNode))
|
var isTag = false;
|
||||||
|
|
||||||
|
if (PlacesUtils.nodeIsFolder(this._resultNode)) {
|
||||||
folderId = PlacesUtils.getConcreteItemId(this._resultNode);
|
folderId = PlacesUtils.getConcreteItemId(this._resultNode);
|
||||||
|
isTag = PlacesUtils.nodeIsTagQuery(this._resultNode);
|
||||||
|
}
|
||||||
|
|
||||||
var selectedNode = this.selectedNode;
|
var selectedNode = this.selectedNode;
|
||||||
if (selectedNode) {
|
if (selectedNode) {
|
||||||
|
@ -907,10 +915,11 @@
|
||||||
// If there is another type of node selected, the insertion point
|
// If there is another type of node selected, the insertion point
|
||||||
// is after that node.
|
// is after that node.
|
||||||
folderId = PlacesUtils.getConcreteItemId(selectedNode.parent);
|
folderId = PlacesUtils.getConcreteItemId(selectedNode.parent);
|
||||||
index = PlacesUtils.getIndexOfNode(selectedNode)
|
index = PlacesUtils.getIndexOfNode(selectedNode);
|
||||||
|
isTag = PlacesUtils.nodeIsTagQuery(selectedNode.parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new InsertionPoint(folderId, index);
|
return new InsertionPoint(folderId, index, 1, isTag);
|
||||||
]]></getter>
|
]]></getter>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
|
|
|
@ -380,6 +380,7 @@
|
||||||
// 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 = -1;
|
var index = -1;
|
||||||
var folderId = PlacesUtils.getConcreteItemId(this._result.root);
|
var folderId = PlacesUtils.getConcreteItemId(this._result.root);
|
||||||
|
var isTag = false;
|
||||||
|
|
||||||
var selectedNode = this.selectedNode;
|
var selectedNode = this.selectedNode;
|
||||||
if (selectedNode) {
|
if (selectedNode) {
|
||||||
|
@ -393,9 +394,10 @@
|
||||||
// is after that node.
|
// is after that node.
|
||||||
folderId = PlacesUtils.getConcreteItemId(selectedNode.parent);
|
folderId = PlacesUtils.getConcreteItemId(selectedNode.parent);
|
||||||
index = PlacesUtils.getIndexOfNode(selectedNode);
|
index = PlacesUtils.getIndexOfNode(selectedNode);
|
||||||
|
isTag = PlacesUtils.nodeIsTagQuery(selectedNode.parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new InsertionPoint(folderId, index, 1);
|
return new InsertionPoint(folderId, index, 1, isTag);
|
||||||
]]></getter>
|
]]></getter>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
|
|
|
@ -491,6 +491,9 @@
|
||||||
<method name="_disallowInsertion">
|
<method name="_disallowInsertion">
|
||||||
<parameter name="aContainer"/>
|
<parameter name="aContainer"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
|
// allow dropping into Tag containers
|
||||||
|
if (PlacesUtils.nodeIsTagQuery(aContainer))
|
||||||
|
return false;
|
||||||
// Disallow insertion of items under readonly folders
|
// Disallow insertion of items under readonly folders
|
||||||
return (!PlacesUtils.nodeIsFolder(aContainer) ||
|
return (!PlacesUtils.nodeIsFolder(aContainer) ||
|
||||||
PlacesUtils.nodeIsReadOnly(aContainer));
|
PlacesUtils.nodeIsReadOnly(aContainer));
|
||||||
|
@ -554,7 +557,8 @@
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
|
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
|
||||||
index, orientation);
|
index, orientation,
|
||||||
|
PlacesUtils.nodeIsTagQuery(container));
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
@ -669,7 +673,8 @@
|
||||||
// If this node is part of a readonly container (e.g. a livemark) it
|
// If this node is part of a readonly container (e.g. a livemark) it
|
||||||
// cannot be moved, only copied, so we must change the action used
|
// cannot be moved, only copied, so we must change the action used
|
||||||
// by the drag session.
|
// by the drag session.
|
||||||
if (PlacesUtils.nodeIsReadOnly(parent)) {
|
if (PlacesUtils.nodeIsReadOnly(parent) ||
|
||||||
|
PlacesUtils.nodeIsTagQuery(parent)) {
|
||||||
dragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
dragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -998,7 +998,8 @@ PlacesTreeView.prototype = {
|
||||||
if (elt.localName == "tree" && elt.view == this &&
|
if (elt.localName == "tree" && elt.view == this &&
|
||||||
this.selection.isSelected(aRow))
|
this.selection.isSelected(aRow))
|
||||||
return false;
|
return false;
|
||||||
if (node.parent && PlacesUtils.nodeIsReadOnly(node.parent))
|
if (node.parent && PlacesUtils.nodeIsReadOnly(node.parent) &&
|
||||||
|
!PlacesUtils.nodeIsTagQuery(node))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1010,6 +1011,9 @@ PlacesTreeView.prototype = {
|
||||||
// either add a helper to PlacesUtils or keep it here and add insertionPoint
|
// either add a helper to PlacesUtils or keep it here and add insertionPoint
|
||||||
// to the view interface.
|
// to the view interface.
|
||||||
_disallowInsertion: function PTV__disallowInsertion(aContainer) {
|
_disallowInsertion: function PTV__disallowInsertion(aContainer) {
|
||||||
|
// allow dropping into Tag containers
|
||||||
|
if (PlacesUtils.nodeIsTagQuery(aContainer))
|
||||||
|
return false;
|
||||||
// Disallow insertion of items under readonly folders
|
// Disallow insertion of items under readonly folders
|
||||||
return (!PlacesUtils.nodeIsFolder(aContainer) ||
|
return (!PlacesUtils.nodeIsFolder(aContainer) ||
|
||||||
PlacesUtils.nodeIsReadOnly(aContainer));
|
PlacesUtils.nodeIsReadOnly(aContainer));
|
||||||
|
@ -1056,7 +1060,8 @@ PlacesTreeView.prototype = {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
|
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
|
||||||
index, orientation);
|
index, orientation,
|
||||||
|
PlacesUtils.nodeIsTagQuery(container));
|
||||||
},
|
},
|
||||||
|
|
||||||
drop: function PTV_drop(aRow, aOrientation) {
|
drop: function PTV_drop(aRow, aOrientation) {
|
||||||
|
|
|
@ -1163,8 +1163,12 @@ var PlacesUIUtils = {
|
||||||
// XXX: Downloads
|
// XXX: Downloads
|
||||||
|
|
||||||
// Tags Query
|
// Tags Query
|
||||||
uri = PlacesUtils._uri("place:folder=TAGS");
|
uri = PlacesUtils._uri("place:type=" +
|
||||||
itemId = PlacesUtils.bookmarks.insertBookmark(leftPaneRoot, uri, -1, null);
|
Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY +
|
||||||
|
"&sort=" +
|
||||||
|
Ci.nsINavHistoryQueryOptions.SORT_BY_TITLE_ASCENDING);
|
||||||
|
title = PlacesUtils.bookmarks.getItemTitle(PlacesUtils.tagsFolderId);
|
||||||
|
itemId = PlacesUtils.bookmarks.insertBookmark(leftPaneRoot, uri, -1, title);
|
||||||
PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
|
PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
|
||||||
"Tags", 0, EXPIRE_NEVER);
|
"Tags", 0, EXPIRE_NEVER);
|
||||||
self.leftPaneQueries["Tags"] = itemId;
|
self.leftPaneQueries["Tags"] = itemId;
|
||||||
|
|
|
@ -171,7 +171,7 @@ placesTransactionsService.prototype = {
|
||||||
return new placesTagURITransaction(aURI, aTags);
|
return new placesTagURITransaction(aURI, aTags);
|
||||||
},
|
},
|
||||||
|
|
||||||
untagURI: function placesTagURI(aURI, aTags) {
|
untagURI: function placesUntagURI(aURI, aTags) {
|
||||||
return new placesUntagURITransaction(aURI, aTags);
|
return new placesUntagURITransaction(aURI, aTags);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -919,12 +919,13 @@ placesTagURITransaction.prototype = {
|
||||||
__proto__: placesBaseTransaction.prototype,
|
__proto__: placesBaseTransaction.prototype,
|
||||||
|
|
||||||
doTransaction: function PTU_doTransaction() {
|
doTransaction: function PTU_doTransaction() {
|
||||||
if (PlacesUtils.getBookmarksForURI(this._uri).length == 0) {
|
if (PlacesUtils.getMostRecentBookmarkForURI(this._uri) == -1) {
|
||||||
// Force an unfiled bookmark first
|
// Force an unfiled bookmark first
|
||||||
this._unfiledItemId =
|
this._unfiledItemId =
|
||||||
PlacesUtils.bookmarks
|
PlacesUtils.bookmarks
|
||||||
.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||||
this._uri, -1,
|
this._uri,
|
||||||
|
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||||
PlacesUtils.history.getPageTitle(this._uri));
|
PlacesUtils.history.getPageTitle(this._uri));
|
||||||
}
|
}
|
||||||
PlacesUtils.tagging.tagURI(this._uri, this._tags);
|
PlacesUtils.tagging.tagURI(this._uri, this._tags);
|
||||||
|
|
|
@ -842,6 +842,11 @@ interface nsINavHistoryQuery : nsISupports
|
||||||
[retval,array,size_is(count)] out long long folders);
|
[retval,array,size_is(count)] out long long folders);
|
||||||
readonly attribute unsigned long folderCount;
|
readonly attribute unsigned long folderCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For the special result type RESULTS_AS_TAG_CONTENTS we can define only
|
||||||
|
* one folder that must be a tag folder. This is not recursive so results
|
||||||
|
* will be returned from the first level of that folder.
|
||||||
|
*/
|
||||||
void setFolders([const,array, size_is(folderCount)] in long long folders,
|
void setFolders([const,array, size_is(folderCount)] in long long folders,
|
||||||
in unsigned long folderCount);
|
in unsigned long folderCount);
|
||||||
|
|
||||||
|
@ -937,6 +942,13 @@ interface nsINavHistoryQueryOptions : nsISupports
|
||||||
*/
|
*/
|
||||||
const unsigned short RESULTS_AS_TAG_QUERY = 6;
|
const unsigned short RESULTS_AS_TAG_QUERY = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a container with an URI result type that contains the last
|
||||||
|
* modified bookmarks for the given tag.
|
||||||
|
* Tag folder id must be defined in the query.
|
||||||
|
*/
|
||||||
|
const unsigned short RESULTS_AS_TAG_CONTENTS = 7;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sorting mode to be used for this query.
|
* The sorting mode to be used for this query.
|
||||||
* mode is one of SORT_BY_*
|
* mode is one of SORT_BY_*
|
||||||
|
|
|
@ -152,20 +152,21 @@ nsNavBookmarks::Init()
|
||||||
// Results are kGetInfoIndex_*
|
// Results are kGetInfoIndex_*
|
||||||
|
|
||||||
// mDBGetChildren: select all children of a given folder, sorted by position
|
// mDBGetChildren: select all children of a given folder, sorted by position
|
||||||
nsCAutoString selectChildren(
|
// This is a LEFT OUTER JOIN with moz_places since folders does not have
|
||||||
NS_LITERAL_CSTRING("SELECT h.id, h.url, COALESCE(a.title, h.title), "
|
// a reference into that table.
|
||||||
|
rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||||
|
"SELECT h.id, h.url, COALESCE(b.title, h.title), "
|
||||||
"h.rev_host, h.visit_count, "
|
"h.rev_host, h.visit_count, "
|
||||||
SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
|
SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
|
||||||
", f.url, null, a.id, "
|
", f.url, null, b.id, "
|
||||||
"a.dateAdded, a.lastModified, "
|
"b.dateAdded, b.lastModified, "
|
||||||
"a.position, a.type, a.fk "
|
"b.position, b.type, b.fk "
|
||||||
"FROM moz_bookmarks a "
|
"FROM moz_bookmarks b "
|
||||||
"LEFT JOIN moz_places h ON a.fk = h.id "
|
"LEFT OUTER JOIN moz_places h ON b.fk = h.id "
|
||||||
"LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
|
"LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
|
||||||
"WHERE a.parent = ?1 "
|
"WHERE b.parent = ?1 "
|
||||||
" ORDER BY a.position"));
|
"ORDER BY b.position"),
|
||||||
|
getter_AddRefs(mDBGetChildren));
|
||||||
rv = dbConn->CreateStatement(selectChildren, getter_AddRefs(mDBGetChildren));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// mDBFolderCount: count all of the children of a given folder
|
// mDBFolderCount: count all of the children of a given folder
|
||||||
|
@ -345,12 +346,20 @@ nsNavBookmarks::InitTables(mozIStorageConnection* aDBConn)
|
||||||
// Making it compound with "type" speeds up type-differentiation
|
// Making it compound with "type" speeds up type-differentiation
|
||||||
// queries, such as expiration and search.
|
// queries, such as expiration and search.
|
||||||
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||||
"CREATE INDEX moz_bookmarks_itemindex ON moz_bookmarks (fk,type)"));
|
"CREATE INDEX moz_bookmarks_itemindex ON moz_bookmarks (fk, type)"));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// The most common operation is to find the children given a parent and position.
|
// The most common operation is to find the children given a parent and position.
|
||||||
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||||
"CREATE INDEX moz_bookmarks_parentindex ON moz_bookmarks (parent,position)"));
|
"CREATE INDEX moz_bookmarks_parentindex "
|
||||||
|
"ON moz_bookmarks (parent, position)"));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// fast access to lastModified is useful during sync and to get
|
||||||
|
// last modified bookmark title for tags container's children.
|
||||||
|
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||||
|
"CREATE INDEX moz_bookmarks_itemlastmodifiedindex "
|
||||||
|
"ON moz_bookmarks (fk, lastModified)"));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1363,11 +1363,26 @@ nsNavHistory::MigrateV6Up(mozIStorageConnection* aDBConn)
|
||||||
nsresult
|
nsresult
|
||||||
nsNavHistory::EnsureCurrentSchema(mozIStorageConnection* aDBConn, PRBool* aDidMigrate)
|
nsNavHistory::EnsureCurrentSchema(mozIStorageConnection* aDBConn, PRBool* aDidMigrate)
|
||||||
{
|
{
|
||||||
|
// We need an index on lastModified to catch quickly last modified bookmark
|
||||||
|
// title for tag container's children. This will be useful for sync too.
|
||||||
|
PRBool lastModIndexExists = PR_FALSE;
|
||||||
|
nsresult rv = aDBConn->IndexExists(
|
||||||
|
NS_LITERAL_CSTRING("moz_bookmarks_itemlastmodifiedindex"),
|
||||||
|
&lastModIndexExists);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (!lastModIndexExists) {
|
||||||
|
rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||||
|
"CREATE INDEX moz_bookmarks_itemlastmodifiedindex "
|
||||||
|
"ON moz_bookmarks (fk, lastModified)"));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
|
||||||
// We need to do a one-time change of the moz_historyvisits.pageindex
|
// We need to do a one-time change of the moz_historyvisits.pageindex
|
||||||
// to speed up finding last visit date when joinin with moz_places.
|
// to speed up finding last visit date when joinin with moz_places.
|
||||||
// See bug 392399 for more details.
|
// See bug 392399 for more details.
|
||||||
PRBool oldIndexExists = PR_FALSE;
|
PRBool oldIndexExists = PR_FALSE;
|
||||||
nsresult rv = aDBConn->IndexExists(
|
rv = aDBConn->IndexExists(
|
||||||
NS_LITERAL_CSTRING("moz_historyvisits_pageindex"), &oldIndexExists);
|
NS_LITERAL_CSTRING("moz_historyvisits_pageindex"), &oldIndexExists);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
@ -2860,6 +2875,7 @@ PlacesSQLQueryBuilder::Select()
|
||||||
switch (mResultType)
|
switch (mResultType)
|
||||||
{
|
{
|
||||||
case nsINavHistoryQueryOptions::RESULTS_AS_URI:
|
case nsINavHistoryQueryOptions::RESULTS_AS_URI:
|
||||||
|
case nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS:
|
||||||
rv = SelectAsURI();
|
rv = SelectAsURI();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
break;
|
break;
|
||||||
|
@ -2914,14 +2930,43 @@ PlacesSQLQueryBuilder::SelectAsURI()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nsINavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS:
|
case nsINavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS:
|
||||||
mQueryString = NS_LITERAL_CSTRING(
|
if (mResultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS) {
|
||||||
"SELECT b.fk, h.url, COALESCE(b.title, h.title), h.rev_host, "
|
nsNavHistory* history = nsNavHistory::GetHistoryService();
|
||||||
"h.visit_count,"
|
NS_ENSURE_STATE(history);
|
||||||
SQL_STR_FRAGMENT_MAX_VISIT_DATE( "b.fk" )
|
|
||||||
", f.url, null, b.id, b.dateAdded, b.lastModified "
|
// Order-by clause is hardcoded because we need to discard duplicates
|
||||||
"FROM moz_bookmarks b "
|
// in FilterResultSet. We will retain only the last modified item,
|
||||||
"JOIN moz_places h ON b.fk = h.id AND b.type = 1 "
|
// so we are ordering by place id and last modified to do a faster
|
||||||
"LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id ");
|
// filtering.
|
||||||
|
mSkipOrderBy = PR_TRUE;
|
||||||
|
|
||||||
|
mQueryString = NS_LITERAL_CSTRING(
|
||||||
|
"SELECT b2.fk, h.url, COALESCE(b2.title, h.title), h.rev_host, "
|
||||||
|
"h.visit_count, "
|
||||||
|
SQL_STR_FRAGMENT_MAX_VISIT_DATE( "b2.fk" )
|
||||||
|
", f.url, null, b2.id, b2.dateAdded, b2.lastModified "
|
||||||
|
"FROM moz_bookmarks b2 "
|
||||||
|
"JOIN moz_places h ON b2.fk = h.id AND b2.type = 1 "
|
||||||
|
"LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
|
||||||
|
"WHERE b2.id IN ("
|
||||||
|
"SELECT b1.id FROM moz_bookmarks b1 "
|
||||||
|
"WHERE b1.fk IN "
|
||||||
|
"(SELECT b.fk FROM moz_bookmarks b WHERE b.type = 1 {ADDITIONAL_CONDITIONS}) "
|
||||||
|
"AND NOT EXISTS "
|
||||||
|
"(SELECT id FROM moz_bookmarks WHERE id = b1.parent AND parent = ") +
|
||||||
|
nsPrintfCString("%d", history->GetTagsFolder()) +
|
||||||
|
NS_LITERAL_CSTRING(")) ORDER BY b2.fk DESC, b2.lastModified DESC");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mQueryString = NS_LITERAL_CSTRING(
|
||||||
|
"SELECT b.fk, h.url, COALESCE(b.title, h.title), h.rev_host, "
|
||||||
|
"h.visit_count,"
|
||||||
|
SQL_STR_FRAGMENT_MAX_VISIT_DATE( "b.fk" )
|
||||||
|
", f.url, null, b.id, b.dateAdded, b.lastModified "
|
||||||
|
"FROM moz_bookmarks b "
|
||||||
|
"JOIN moz_places h ON b.fk = h.id AND b.type = 1 "
|
||||||
|
"LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id ");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -3142,12 +3187,12 @@ PlacesSQLQueryBuilder::SelectAsTag()
|
||||||
mHasDateColumns = PR_TRUE;
|
mHasDateColumns = PR_TRUE;
|
||||||
|
|
||||||
mQueryString = nsPrintfCString(2048,
|
mQueryString = nsPrintfCString(2048,
|
||||||
"SELECT null, 'place:type=%ld&queryType=%d&excludeQueries=1&folder=' || id, "
|
"SELECT null, 'place:folder=' || id || '&queryType=%d&type=%ld', "
|
||||||
"title, null, null, null, null, null, null, dateAdded, lastModified "
|
"title, null, null, null, null, null, null, dateAdded, lastModified "
|
||||||
"FROM moz_bookmarks "
|
"FROM moz_bookmarks "
|
||||||
"WHERE parent = %ld",
|
"WHERE parent = %ld",
|
||||||
nsINavHistoryQueryOptions::RESULTS_AS_URI,
|
|
||||||
nsINavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS,
|
nsINavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS,
|
||||||
|
nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS,
|
||||||
history->GetTagsFolder());
|
history->GetTagsFolder());
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -4919,6 +4964,13 @@ nsNavHistory::QueryToSelectClause(nsNavHistoryQuery* aQuery, // const
|
||||||
// all URLs with that annotation
|
// all URLs with that annotation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parent parameter is used in tag contents queries.
|
||||||
|
// Only one folder should be defined for them.
|
||||||
|
if (aOptions->ResultType() == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS &&
|
||||||
|
aQuery->Folders().Length() == 1) {
|
||||||
|
clause.Condition("b.parent =").Param(":parent");
|
||||||
|
}
|
||||||
|
|
||||||
clause.GetClauseString(*aClause);
|
clause.GetClauseString(*aClause);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -5048,6 +5100,14 @@ nsNavHistory::BindQueryClauseParameters(mozIStorageStatement* statement,
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parent parameter
|
||||||
|
if (aOptions->ResultType() == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS &&
|
||||||
|
aQuery->Folders().Length() == 1) {
|
||||||
|
rv = statement->BindInt64Parameter(index.For(":parent"),
|
||||||
|
aQuery->Folders()[0]);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
|
||||||
NS_ENSURE_SUCCESS(index.Result(), index.Result());
|
NS_ENSURE_SUCCESS(index.Result(), index.Result());
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -5166,6 +5226,7 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode,
|
||||||
ParseSearchTermsFromQueries(aQueries, &terms);
|
ParseSearchTermsFromQueries(aQueries, &terms);
|
||||||
|
|
||||||
PRUint32 queryIndex;
|
PRUint32 queryIndex;
|
||||||
|
PRUint16 resultType = aOptions->ResultType();
|
||||||
|
|
||||||
// The includeFolders array for each query is initialized with its
|
// The includeFolders array for each query is initialized with its
|
||||||
// query's folders array. We add sub-folders as we check items.
|
// query's folders array. We add sub-folders as we check items.
|
||||||
|
@ -5235,7 +5296,10 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode,
|
||||||
for (queryIndex = 0;
|
for (queryIndex = 0;
|
||||||
queryIndex < aQueries.Count() && !appendNode; queryIndex++) {
|
queryIndex < aQueries.Count() && !appendNode; queryIndex++) {
|
||||||
// parent folder
|
// parent folder
|
||||||
if (includeFolders[queryIndex]->Length() != 0) {
|
// RESULTS_AS_TAG_CONTENTS changes bookmarks parent, so we must not filter
|
||||||
|
// this kind of result based on the parent.
|
||||||
|
if (includeFolders[queryIndex]->Length() != 0 &&
|
||||||
|
resultType != nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS) {
|
||||||
// filter out simple history nodes from bookmark queries
|
// filter out simple history nodes from bookmark queries
|
||||||
if (aSet[nodeIndex]->mItemId == -1)
|
if (aSet[nodeIndex]->mItemId == -1)
|
||||||
continue;
|
continue;
|
||||||
|
@ -5314,6 +5378,14 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode,
|
||||||
|
|
||||||
appendNode = PR_TRUE;
|
appendNode = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RESULTS_AS_TAG_CONTENTS returns a set ordered by place_id and
|
||||||
|
// lastModified. So, to remove duplicates, we can retain the first result
|
||||||
|
// for each uri.
|
||||||
|
if (resultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS &&
|
||||||
|
nodeIndex > 0 && aSet[nodeIndex]->mURI == aSet[nodeIndex-1]->mURI)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (appendNode)
|
if (appendNode)
|
||||||
aFiltered->AppendObject(aSet[nodeIndex]);
|
aFiltered->AppendObject(aSet[nodeIndex]);
|
||||||
|
|
||||||
|
@ -5514,8 +5586,16 @@ nsNavHistory::RowToResult(mozIStorageValueArray* aRow,
|
||||||
aOptions->ResultType() !=
|
aOptions->ResultType() !=
|
||||||
nsINavHistoryQueryOptions::RESULTS_AS_TAG_QUERY)
|
nsINavHistoryQueryOptions::RESULTS_AS_TAG_QUERY)
|
||||||
(*aResult)->GetAsContainer()->mOptions = aOptions;
|
(*aResult)->GetAsContainer()->mOptions = aOptions;
|
||||||
|
|
||||||
|
// RESULTS_AS_TAG_QUERY has date columns
|
||||||
|
if (aOptions->ResultType() == nsNavHistoryQueryOptions::RESULTS_AS_TAG_QUERY) {
|
||||||
|
(*aResult)->mDateAdded = aRow->AsInt64(kGetInfoIndex_ItemDateAdded);
|
||||||
|
(*aResult)->mLastModified = aRow->AsInt64(kGetInfoIndex_ItemLastModified);
|
||||||
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
} else if (aOptions->ResultType() == nsNavHistoryQueryOptions::RESULTS_AS_URI) {
|
} else if (aOptions->ResultType() == nsNavHistoryQueryOptions::RESULTS_AS_URI ||
|
||||||
|
aOptions->ResultType() == nsNavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS) {
|
||||||
*aResult = new nsNavHistoryResultNode(url, title, accessCount, time,
|
*aResult = new nsNavHistoryResultNode(url, title, accessCount, time,
|
||||||
favicon);
|
favicon);
|
||||||
if (!*aResult)
|
if (!*aResult)
|
||||||
|
@ -6026,6 +6106,11 @@ GetSimpleBookmarksQueryFolder(const nsCOMArray<nsNavHistoryQuery>& aQueries,
|
||||||
if (aOptions->MaxResults() > 0)
|
if (aOptions->MaxResults() > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// RESULTS_AS_TAG_CONTENTS is quite similar to a folder shortcut, but we must
|
||||||
|
// avoid treating it like that, since we need to retain all query options.
|
||||||
|
if(aOptions->ResultType() == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS)
|
||||||
|
return 0;
|
||||||
|
|
||||||
// Note that we don't care about the onlyBookmarked flag, if you specify a bookmark
|
// Note that we don't care about the onlyBookmarked flag, if you specify a bookmark
|
||||||
// folder, onlyBookmarked is inferred.
|
// folder, onlyBookmarked is inferred.
|
||||||
NS_ASSERTION(query->Folders()[0] > 0, "bad folder id");
|
NS_ASSERTION(query->Folders()[0] > 0, "bad folder id");
|
||||||
|
|
|
@ -1195,7 +1195,7 @@ nsNavHistoryQueryOptions::GetResultType(PRUint16* aType)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsNavHistoryQueryOptions::SetResultType(PRUint16 aType)
|
nsNavHistoryQueryOptions::SetResultType(PRUint16 aType)
|
||||||
{
|
{
|
||||||
if (aType > RESULTS_AS_TAG_QUERY)
|
if (aType > RESULTS_AS_TAG_CONTENTS)
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
mResultType = aType;
|
mResultType = aType;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
@ -2068,6 +2068,13 @@ nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode(
|
||||||
PRBool
|
PRBool
|
||||||
nsNavHistoryQueryResultNode::CanExpand()
|
nsNavHistoryQueryResultNode::CanExpand()
|
||||||
{
|
{
|
||||||
|
if (IsContainersQuery())
|
||||||
|
return PR_TRUE;
|
||||||
|
|
||||||
|
// if we are child of an ExcludeItems root, we should not expand
|
||||||
|
if (mResult && mResult->mRootNode->mOptions->ExcludeItems())
|
||||||
|
return PR_FALSE;
|
||||||
|
|
||||||
nsNavHistoryQueryOptions* options = GetGeneratingOptions();
|
nsNavHistoryQueryOptions* options = GetGeneratingOptions();
|
||||||
if (options) {
|
if (options) {
|
||||||
if (options->ExcludeItems())
|
if (options->ExcludeItems())
|
||||||
|
@ -2080,6 +2087,20 @@ nsNavHistoryQueryResultNode::CanExpand()
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nsNavHistoryQueryResultNode::IsContainersQuery
|
||||||
|
//
|
||||||
|
// Some query with a particular result type can contain other queries,
|
||||||
|
// they must be always expandable
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
nsNavHistoryQueryResultNode::IsContainersQuery()
|
||||||
|
{
|
||||||
|
PRUint16 resultType = mOptions->ResultType();
|
||||||
|
return resultType == nsINavHistoryQueryOptions::RESULTS_AS_DATE_QUERY ||
|
||||||
|
resultType == nsINavHistoryQueryOptions::RESULTS_AS_DATE_SITE_QUERY ||
|
||||||
|
resultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_QUERY ||
|
||||||
|
resultType == nsINavHistoryQueryOptions::RESULTS_AS_SITE_QUERY;
|
||||||
|
}
|
||||||
|
|
||||||
// nsNavHistoryQueryResultNode::OnRemoving
|
// nsNavHistoryQueryResultNode::OnRemoving
|
||||||
//
|
//
|
||||||
|
@ -2140,10 +2161,49 @@ nsNavHistoryQueryResultNode::OpenContainer()
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsNavHistoryQueryResultNode::GetHasChildren(PRBool* aHasChildren)
|
nsNavHistoryQueryResultNode::GetHasChildren(PRBool* aHasChildren)
|
||||||
{
|
{
|
||||||
if (! CanExpand()) {
|
if (!CanExpand()) {
|
||||||
*aHasChildren = PR_FALSE;
|
*aHasChildren = PR_FALSE;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRUint16 resultType = mOptions->ResultType();
|
||||||
|
// For tag containers query we must check if we have any tag
|
||||||
|
if (resultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_QUERY) {
|
||||||
|
nsNavHistory* history = nsNavHistory::GetHistoryService();
|
||||||
|
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
mozIStorageConnection *dbConn = history->GetStorageConnection();
|
||||||
|
|
||||||
|
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
|
||||||
|
NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
PRInt64 tagsFolderId;
|
||||||
|
nsresult rv = bookmarks->GetTagsFolder(&tagsFolderId);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsCOMPtr<mozIStorageStatement> hasTagsStatement;
|
||||||
|
rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||||
|
"SELECT id FROM moz_bookmarks WHERE parent = ?1 LIMIT 1"),
|
||||||
|
getter_AddRefs(hasTagsStatement));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
rv = hasTagsStatement->BindInt64Parameter(0, tagsFolderId);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
return hasTagsStatement->ExecuteStep(aHasChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For history containers query we must check if we have any history
|
||||||
|
if (resultType == nsINavHistoryQueryOptions::RESULTS_AS_DATE_QUERY ||
|
||||||
|
resultType == nsINavHistoryQueryOptions::RESULTS_AS_DATE_SITE_QUERY ||
|
||||||
|
resultType == nsINavHistoryQueryOptions::RESULTS_AS_SITE_QUERY) {
|
||||||
|
nsNavHistory* history = nsNavHistory::GetHistoryService();
|
||||||
|
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
return history->GetHasHistoryEntries(aHasChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
//XXX: For other containers queries we must:
|
||||||
|
// 1. If it's open, just check mChildren for containers
|
||||||
|
// 2. Else null the view (keep it in a var), open container, check mChildren
|
||||||
|
// for containers, close container, reset the view
|
||||||
|
|
||||||
if (mContentsValid) {
|
if (mContentsValid) {
|
||||||
*aHasChildren = (mChildren.Count() > 0);
|
*aHasChildren = (mChildren.Count() > 0);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -2372,6 +2432,12 @@ nsNavHistoryQueryResultNode::ClearChildren(PRBool aUnregister)
|
||||||
nsresult
|
nsresult
|
||||||
nsNavHistoryQueryResultNode::Refresh()
|
nsNavHistoryQueryResultNode::Refresh()
|
||||||
{
|
{
|
||||||
|
// Some query can return other queries, in this case we could call Refresh
|
||||||
|
// for each child query causing a major slowdown. We should not refresh
|
||||||
|
// nested queries since we are already refreshing the containining one.
|
||||||
|
if (mOptions->ResultType() == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
// Ignore refreshes when there is a batch, EndUpdateBatch will do a refresh
|
// Ignore refreshes when there is a batch, EndUpdateBatch will do a refresh
|
||||||
// to get all the changes.
|
// to get all the changes.
|
||||||
if (mBatchInProgress)
|
if (mBatchInProgress)
|
||||||
|
@ -2657,7 +2723,10 @@ nsNavHistoryQueryResultNode::OnTitleChanged(nsIURI* aURI,
|
||||||
nsCAutoString newTitle = NS_ConvertUTF16toUTF8(aPageTitle);
|
nsCAutoString newTitle = NS_ConvertUTF16toUTF8(aPageTitle);
|
||||||
|
|
||||||
PRBool onlyOneEntry = (mOptions->ResultType() ==
|
PRBool onlyOneEntry = (mOptions->ResultType() ==
|
||||||
nsINavHistoryQueryOptions::RESULTS_AS_URI);
|
nsINavHistoryQueryOptions::RESULTS_AS_URI ||
|
||||||
|
mOptions->ResultType() ==
|
||||||
|
nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS
|
||||||
|
);
|
||||||
return ChangeTitles(aURI, newTitle, PR_TRUE, onlyOneEntry);
|
return ChangeTitles(aURI, newTitle, PR_TRUE, onlyOneEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2671,7 +2740,9 @@ NS_IMETHODIMP
|
||||||
nsNavHistoryQueryResultNode::OnDeleteURI(nsIURI *aURI)
|
nsNavHistoryQueryResultNode::OnDeleteURI(nsIURI *aURI)
|
||||||
{
|
{
|
||||||
PRBool onlyOneEntry = (mOptions->ResultType() ==
|
PRBool onlyOneEntry = (mOptions->ResultType() ==
|
||||||
nsINavHistoryQueryOptions::RESULTS_AS_URI);
|
nsINavHistoryQueryOptions::RESULTS_AS_URI ||
|
||||||
|
mOptions->ResultType() ==
|
||||||
|
nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS);
|
||||||
nsCAutoString spec;
|
nsCAutoString spec;
|
||||||
nsresult rv = aURI->GetSpec(spec);
|
nsresult rv = aURI->GetSpec(spec);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -2736,7 +2807,9 @@ nsNavHistoryQueryResultNode::OnPageChanged(nsIURI *aURI, PRUint32 aWhat,
|
||||||
case nsINavHistoryObserver::ATTRIBUTE_FAVICON: {
|
case nsINavHistoryObserver::ATTRIBUTE_FAVICON: {
|
||||||
nsCString newFavicon = NS_ConvertUTF16toUTF8(aValue);
|
nsCString newFavicon = NS_ConvertUTF16toUTF8(aValue);
|
||||||
PRBool onlyOneEntry = (mOptions->ResultType() ==
|
PRBool onlyOneEntry = (mOptions->ResultType() ==
|
||||||
nsINavHistoryQueryOptions::RESULTS_AS_URI);
|
nsINavHistoryQueryOptions::RESULTS_AS_URI ||
|
||||||
|
mOptions->ResultType() ==
|
||||||
|
nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS);
|
||||||
UpdateURIs(PR_TRUE, onlyOneEntry, PR_FALSE, spec, setFaviconCallback,
|
UpdateURIs(PR_TRUE, onlyOneEntry, PR_FALSE, spec, setFaviconCallback,
|
||||||
&newFavicon);
|
&newFavicon);
|
||||||
break;
|
break;
|
||||||
|
@ -2810,6 +2883,7 @@ nsNavHistoryQueryResultNode::OnItemVisited(PRInt64 aItemId,
|
||||||
NS_NOTREACHED("history observers should not get OnItemVisited, but should get OnVisit instead");
|
NS_NOTREACHED("history observers should not get OnItemVisited, but should get OnVisit instead");
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsNavHistoryQueryResultNode::OnItemMoved(PRInt64 aFolder, PRInt64 aOldParent,
|
nsNavHistoryQueryResultNode::OnItemMoved(PRInt64 aFolder, PRInt64 aOldParent,
|
||||||
PRInt32 aOldIndex, PRInt64 aNewParent,
|
PRInt32 aOldIndex, PRInt64 aNewParent,
|
||||||
|
|
|
@ -706,6 +706,7 @@ public:
|
||||||
NS_DECL_NSINAVHISTORYQUERYRESULTNODE
|
NS_DECL_NSINAVHISTORYQUERYRESULTNODE
|
||||||
|
|
||||||
PRBool CanExpand();
|
PRBool CanExpand();
|
||||||
|
PRBool IsContainersQuery();
|
||||||
|
|
||||||
virtual nsresult OpenContainer();
|
virtual nsresult OpenContainer();
|
||||||
|
|
||||||
|
|
|
@ -255,8 +255,10 @@ var PlacesUtils = {
|
||||||
nodeIsReadOnly: function PU_nodeIsReadOnly(aNode) {
|
nodeIsReadOnly: function PU_nodeIsReadOnly(aNode) {
|
||||||
if (this.nodeIsFolder(aNode))
|
if (this.nodeIsFolder(aNode))
|
||||||
return this.bookmarks.getFolderReadonly(asQuery(aNode).folderItemId);
|
return this.bookmarks.getFolderReadonly(asQuery(aNode).folderItemId);
|
||||||
if (this.nodeIsQuery(aNode))
|
if (this.nodeIsQuery(aNode) &&
|
||||||
return asQuery(aNode).childrenReadOnly;
|
asQuery(aNode).queryOptions.resultType !=
|
||||||
|
Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS)
|
||||||
|
return aNode.childrenReadOnly;
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -288,6 +290,18 @@ var PlacesUtils = {
|
||||||
resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY);
|
resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether or not a result-node is a tag container.
|
||||||
|
* @param aNode
|
||||||
|
* A result-node
|
||||||
|
* @returns true if the node is a tag container, false otherwise
|
||||||
|
*/
|
||||||
|
nodeIsTagQuery: function PU_nodeIsTagQuery(aNode) {
|
||||||
|
return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
|
||||||
|
asQuery(aNode).queryOptions.resultType ==
|
||||||
|
Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether or not a ResultNode is a container.
|
* Determines whether or not a ResultNode is a container.
|
||||||
* @param aNode
|
* @param aNode
|
||||||
|
@ -376,6 +390,13 @@ var PlacesUtils = {
|
||||||
getConcreteItemId: function PU_getConcreteItemId(aNode) {
|
getConcreteItemId: function PU_getConcreteItemId(aNode) {
|
||||||
if (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT)
|
if (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT)
|
||||||
return asQuery(aNode).folderItemId;
|
return asQuery(aNode).folderItemId;
|
||||||
|
else if (PlacesUtils.nodeIsTagQuery(aNode)) {
|
||||||
|
// RESULTS_AS_TAG_CONTENTS queries are similar to folder shortcuts
|
||||||
|
// so we can still get the concrete itemId for them.
|
||||||
|
var queries = aNode.getQueries({});
|
||||||
|
var folders = queries[0].getFolders({});
|
||||||
|
return folders[0];
|
||||||
|
}
|
||||||
return aNode.itemId;
|
return aNode.itemId;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is Places unit test code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Mozilla Corporation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Marco Bonardo <mak77@supereva.it> (Original Author)
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
// Get history services
|
||||||
|
try {
|
||||||
|
var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||||
|
getService(Ci.nsINavHistoryService);
|
||||||
|
var bhist = histsvc.QueryInterface(Ci.nsIBrowserHistory);
|
||||||
|
} catch(ex) {
|
||||||
|
do_throw("Could not get history services\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get bookmark service
|
||||||
|
try {
|
||||||
|
var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||||
|
getService(Ci.nsINavBookmarksService);
|
||||||
|
}
|
||||||
|
catch(ex) {
|
||||||
|
do_throw("Could not get the nav-bookmarks-service\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get tagging service
|
||||||
|
try {
|
||||||
|
var tagssvc = Cc["@mozilla.org/browser/tagging-service;1"].
|
||||||
|
getService(Ci.nsITaggingService);
|
||||||
|
} catch(ex) {
|
||||||
|
do_throw("Could not get tagging service\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// main
|
||||||
|
function run_test() {
|
||||||
|
var uri1 = uri("http://foo.bar/");
|
||||||
|
|
||||||
|
// create 2 bookmarks
|
||||||
|
var bookmark1id = bmsvc.insertBookmark(bmsvc.bookmarksMenuFolder, uri1,
|
||||||
|
bmsvc.DEFAULT_INDEX, "title 1");
|
||||||
|
var bookmark2id = bmsvc.insertBookmark(bmsvc.toolbarFolder, uri1,
|
||||||
|
bmsvc.DEFAULT_INDEX, "title 2");
|
||||||
|
// add a new tag
|
||||||
|
tagssvc.tagURI(uri1, ["foo"]);
|
||||||
|
|
||||||
|
// get tag folder id
|
||||||
|
var options = histsvc.getNewQueryOptions();
|
||||||
|
var query = histsvc.getNewQuery();
|
||||||
|
query.setFolders([bmsvc.tagsFolder], 1);
|
||||||
|
var result = histsvc.executeQuery(query, options);
|
||||||
|
var tagRoot = result.root;
|
||||||
|
tagRoot.containerOpen = true;
|
||||||
|
var tag1node = tagRoot.getChild(0)
|
||||||
|
.QueryInterface(Ci.nsINavHistoryContainerResultNode);
|
||||||
|
var tag1itemId = tag1node.itemId;
|
||||||
|
tagRoot.containerOpen = false;
|
||||||
|
|
||||||
|
// change bookmark 1 title
|
||||||
|
bmsvc.setItemTitle(bookmark1id, "new title 1");
|
||||||
|
|
||||||
|
// check that tag container contains new title
|
||||||
|
options = histsvc.getNewQueryOptions();
|
||||||
|
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
|
||||||
|
options.resultType = options.RESULTS_AS_TAG_CONTENTS;
|
||||||
|
options.includeHidden = true;
|
||||||
|
query = histsvc.getNewQuery();
|
||||||
|
result = histsvc.executeQuery(query, options);
|
||||||
|
var root = result.root;
|
||||||
|
|
||||||
|
root.containerOpen = true;
|
||||||
|
var cc = root.childCount;
|
||||||
|
do_check_eq(cc, 1);
|
||||||
|
var node = root.getChild(0);
|
||||||
|
do_check_eq(node.title, "new title 1");
|
||||||
|
root.containerOpen = false;
|
||||||
|
|
||||||
|
// change bookmark 2 title
|
||||||
|
bmsvc.setItemTitle(bookmark2id, "new title 2");
|
||||||
|
|
||||||
|
// check that tag container contains new title
|
||||||
|
options = histsvc.getNewQueryOptions();
|
||||||
|
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
|
||||||
|
options.resultType = options.RESULTS_AS_TAG_CONTENTS;
|
||||||
|
options.includeHidden = true;
|
||||||
|
query = histsvc.getNewQuery();
|
||||||
|
result = histsvc.executeQuery(query, options);
|
||||||
|
root = result.root;
|
||||||
|
|
||||||
|
root.containerOpen = true;
|
||||||
|
cc = root.childCount;
|
||||||
|
do_check_eq(cc, 1);
|
||||||
|
var node = root.getChild(0);
|
||||||
|
do_check_eq(node.title, "new title 2");
|
||||||
|
root.containerOpen = false;
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче