Bug 707955 - Tags should avoid results overhead.

r=dietrich
This commit is contained in:
Marco Bonardo 2011-12-07 21:56:30 +01:00
parent faecbfc0c2
commit e6acfd675f

View File

@ -61,29 +61,6 @@ function TaggingService() {
}
TaggingService.prototype = {
/**
* If there's no tag with the given name or id, null is returned;
*/
_getTagResult: function TS__getTagResult(aTagNameOrId) {
if (!aTagNameOrId)
throw Cr.NS_ERROR_INVALID_ARG;
var tagId = null;
if (typeof(aTagNameOrId) == "string")
tagId = this._getItemIdForTag(aTagNameOrId);
else
tagId = aTagNameOrId;
if (tagId == -1)
return null;
var options = PlacesUtils.history.getNewQueryOptions();
var query = PlacesUtils.history.getNewQuery();
query.setFolders([tagId], 1);
var result = PlacesUtils.history.executeQuery(query, options);
return result;
},
/**
* Creates a tag container under the tags-root with the given name.
*
@ -116,11 +93,24 @@ TaggingService.prototype = {
var tagId = this._getItemIdForTag(aTagName);
if (tagId == -1)
return -1;
var bookmarkIds = PlacesUtils.bookmarks.getBookmarkIdsForURI(aURI);
for (var i=0; i < bookmarkIds.length; i++) {
var parent = PlacesUtils.bookmarks.getFolderIdForItem(bookmarkIds[i]);
if (parent == tagId)
return bookmarkIds[i];
// Using bookmarks service API for this would be a pain.
// Until tags implementation becomes sane, go the query way.
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
let stmt = db.createStatement(
"SELECT id FROM moz_bookmarks "
+ "WHERE parent = :tag_id "
+ "AND fk = (SELECT id FROM moz_places WHERE url = :page_url)"
);
stmt.params.tag_id = tagId;
stmt.params.page_url = aURI.spec;
try {
if (stmt.executeStep()) {
return stmt.row.id;
}
}
finally {
stmt.finalize();
}
return -1;
},
@ -223,14 +213,24 @@ TaggingService.prototype = {
* the itemId of the tag element under the tags root
*/
_removeTagIfEmpty: function TS__removeTagIfEmpty(aTagId) {
var result = this._getTagResult(aTagId);
if (!result)
return;
var node = PlacesUtils.asContainer(result.root);
node.containerOpen = true;
var cc = node.childCount;
node.containerOpen = false;
if (cc == 0) {
let count = 0;
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
let stmt = db.createStatement(
"SELECT count(*) AS count FROM moz_bookmarks "
+ "WHERE parent = :tag_id"
);
stmt.params.tag_id = aTagId;
try {
if (stmt.executeStep()) {
count = stmt.row.count;
}
}
finally {
stmt.finalize();
}
if (count == 0) {
PlacesUtils.bookmarks.removeItem(aTagId);
}
},
@ -271,27 +271,34 @@ TaggingService.prototype = {
},
// nsITaggingService
getURIsForTag: function TS_getURIsForTag(aTag) {
if (!aTag || aTag.length == 0)
getURIsForTag: function TS_getURIsForTag(aTagName) {
if (!aTagName || aTagName.length == 0)
throw Cr.NS_ERROR_INVALID_ARG;
var uris = [];
var tagResult = this._getTagResult(aTag);
if (tagResult) {
var tagNode = tagResult.root;
tagNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
tagNode.containerOpen = true;
var cc = tagNode.childCount;
for (var i = 0; i < cc; i++) {
let uris = [];
let tagId = this._getItemIdForTag(aTagName);
if (tagId == -1)
return uris;
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
let stmt = db.createStatement(
"SELECT h.url FROM moz_places h "
+ "JOIN moz_bookmarks b ON b.fk = h.id "
+ "WHERE b.parent = :tag_id "
);
stmt.params.tag_id = tagId;
try {
while (stmt.executeStep()) {
try {
uris.push(Services.io.newURI(tagNode.getChild(i).uri, null, null));
} catch (ex) {
// This is an invalid node, tags should only contain valid uri nodes.
// continue to next node.
}
uris.push(Services.io.newURI(stmt.row.url, null, null));
} catch (ex) {}
}
tagNode.containerOpen = false;
}
finally {
stmt.finalize();
}
return uris;
},
@ -321,18 +328,21 @@ TaggingService.prototype = {
get _tagFolders() {
if (!this.__tagFolders) {
this.__tagFolders = [];
var options = PlacesUtils.history.getNewQueryOptions();
var query = PlacesUtils.history.getNewQuery();
query.setFolders([PlacesUtils.tagsFolderId], 1);
var tagsResult = PlacesUtils.history.executeQuery(query, options);
var root = tagsResult.root;
root.containerOpen = true;
var cc = root.childCount;
for (var i=0; i < cc; i++) {
var child = root.getChild(i);
this.__tagFolders[child.itemId] = child.title;
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
let stmt = db.createStatement(
"SELECT id, title FROM moz_bookmarks WHERE parent = :tags_root "
);
stmt.params.tags_root = PlacesUtils.tagsFolderId;
try {
while (stmt.executeStep()) {
this.__tagFolders[stmt.row.id] = stmt.row.title;
}
}
finally {
stmt.finalize();
}
root.containerOpen = false;
}
return this.__tagFolders;
@ -365,29 +375,47 @@ TaggingService.prototype = {
/**
* If the only bookmark items associated with aURI are contained in tag
* folders, returns the IDs of those tag folders. This can be the case if
* folders, returns the IDs of those items. This can be the case if
* the URI was bookmarked and tagged at some point, but the bookmark was
* removed, leaving only the bookmark items in tag folders. Returns null
* if the URI is either properly bookmarked or not tagged.
* removed, leaving only the bookmark items in tag folders. If the URI is
* either properly bookmarked or not tagged just returns and empty array.
*
* @param aURI
* A URI (string) that may or may not be bookmarked
* @returns null or an array of tag IDs
* @returns an array of item ids
*/
_getTagsIfUnbookmarkedURI: function TS__getTagsIfUnbookmarkedURI(aURI) {
var tagIds = [];
_getTaggedItemIdsIfUnbookmarkedURI:
function TS__getTaggedItemIdsIfUnbookmarkedURI(aURI) {
var itemIds = [];
var isBookmarked = false;
var itemIds = PlacesUtils.bookmarks.getBookmarkIdsForURI(aURI);
for (let i = 0; !isBookmarked && i < itemIds.length; i++) {
var parentId = PlacesUtils.bookmarks.getFolderIdForItem(itemIds[i]);
if (this._tagFolders[parentId])
tagIds.push(parentId);
else
isBookmarked = true;
// Using bookmarks service API for this would be a pain.
// Until tags implementation becomes sane, go the query way.
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.DBConnection;
let stmt = db.createStatement(
"SELECT id, parent "
+ "FROM moz_bookmarks "
+ "WHERE fk = (SELECT id FROM moz_places WHERE url = :page_url)"
);
stmt.params.page_url = aURI.spec;
try {
while (stmt.executeStep() && !isBookmarked) {
if (this._tagFolders[stmt.row.parent]) {
// This is a tag entry.
itemIds.push(stmt.row.id);
}
else {
// This is a real bookmark, so the bookmarked URI is not an orphan.
isBookmarked = true;
}
}
}
finally {
stmt.finalize();
}
return !isBookmarked && tagIds.length > 0 ? tagIds : null;
return isBookmarked ? [] : itemIds;
},
// nsINavBookmarkObserver
@ -404,20 +432,21 @@ TaggingService.prototype = {
onItemRemoved: function TS_onItemRemoved(aItemId, aFolderId, aIndex,
aItemType, aURI) {
// Item is a tag folder.
if (aFolderId == PlacesUtils.tagsFolderId && this._tagFolders[aItemId])
if (aFolderId == PlacesUtils.tagsFolderId && this._tagFolders[aItemId]) {
delete this._tagFolders[aItemId];
}
// Item is a bookmark that was removed from a non-tag folder.
else if (aURI && !this._tagFolders[aFolderId]) {
// If the only bookmark items now associated with the bookmark's URI are
// contained in tag folders, the URI is no longer properly bookmarked, so
// untag it.
var tagIds = this._getTagsIfUnbookmarkedURI(aURI);
if (tagIds)
this.untagURI(aURI, tagIds);
let itemIds = this._getTaggedItemIdsIfUnbookmarkedURI(aURI);
for (let i = 0; i < itemIds.length; i++) {
try {
PlacesUtils.bookmarks.removeItem(itemIds[i]);
} catch (ex) {}
}
}
// Item is a tag entry. If this was the last entry for this tag, remove it.
else if (aURI && this._tagFolders[aFolderId]) {
this._removeTagIfEmpty(aFolderId);