Bug 702639 - Kill excludeItemsIfParentHasAnnotation query option.

r=dietrich sr=gavin
This commit is contained in:
Marco Bonardo 2012-02-24 23:43:49 +01:00
parent fb651909f4
commit 2c3db1bc42
9 changed files with 94 additions and 219 deletions

View File

@ -1300,7 +1300,7 @@ BrowserGlue.prototype = {
// be set to the version it has been added in, we will compare its value
// to users' smartBookmarksVersion and add new smart bookmarks without
// recreating old deleted ones.
const SMART_BOOKMARKS_VERSION = 2;
const SMART_BOOKMARKS_VERSION = 3;
const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark";
const SMART_BOOKMARKS_PREF = "browser.places.smartBookmarksVersion";
@ -1346,7 +1346,6 @@ BrowserGlue.prototype = {
Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS +
"&sort=" +
Ci.nsINavHistoryQueryOptions.SORT_BY_DATEADDED_DESCENDING +
"&excludeItemIfParentHasAnnotation=livemark%2FfeedURI" +
"&maxResults=" + MAX_RESULTS +
"&excludeQueries=1"),
parent: PlacesUtils.bookmarksMenuFolderId,

View File

@ -102,7 +102,7 @@ let (backup_date = new Date().toLocaleFormat("%Y-%m-%d")) {
}
// Smart bookmarks constants.
const SMART_BOOKMARKS_VERSION = 2;
const SMART_BOOKMARKS_VERSION = 3;
const SMART_BOOKMARKS_ON_TOOLBAR = 1;
const SMART_BOOKMARKS_ON_MENU = 3; // Takes in count the additional separator.

View File

@ -1040,7 +1040,7 @@ interface nsINavHistoryQuery : nsISupports
/**
* This object represents the global options for executing a query.
*/
[scriptable, uuid(2d8ff86b-f8c2-451c-8a1a-1ff0749a074e)]
[scriptable, uuid(d46a1ae7-aef8-47a2-9a5c-e6347253f9b2)]
interface nsINavHistoryQueryOptions : nsISupports
{
/**
@ -1188,15 +1188,6 @@ interface nsINavHistoryQueryOptions : nsISupports
*/
attribute boolean excludeReadOnlyFolders;
/**
* This option excludes items from a bookmarks query
* if the parent of the item has this annotation.
* An example is to exclude livemark items
* (parent folders have the "livemark/feedURI" annotation)
* Ignored for queries over history.
*/
attribute AUTF8String excludeItemIfParentHasAnnotation;
/**
* When set, allows items with "place:" URIs to appear as containers,
* with the container's contents filled in from the stored query.

View File

@ -1051,6 +1051,48 @@ nsNavBookmarks::GetRemoveFolderTransaction(PRInt64 aFolderId, nsITransaction** a
}
nsresult
nsNavBookmarks::GetDescendantFolders(PRInt64 aFolderId,
nsTArray<PRInt64>& aDescendantFoldersArray) {
nsresult rv;
// New descendant folders will be added from this index on.
PRUint32 startIndex = aDescendantFoldersArray.Length();
{
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
"SELECT id "
"FROM moz_bookmarks "
"WHERE parent = :parent "
"AND type = :item_type "
);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("parent"), aFolderId);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("item_type"), TYPE_FOLDER);
NS_ENSURE_SUCCESS(rv, rv);
bool hasMore = false;
while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) && hasMore) {
PRInt64 itemId;
rv = stmt->GetInt64(0, &itemId);
NS_ENSURE_SUCCESS(rv, rv);
aDescendantFoldersArray.AppendElement(itemId);
}
}
// Recursively call GetDescendantFolders for added folders.
// We start at startIndex since previous folders are checked
// by previous calls to this method.
PRUint32 childCount = aDescendantFoldersArray.Length();
for (PRUint32 i = startIndex; i < childCount; ++i) {
GetDescendantFolders(aDescendantFoldersArray[i], aDescendantFoldersArray);
}
return NS_OK;
}
nsresult
nsNavBookmarks::GetDescendantChildren(PRInt64 aFolderId,
const nsACString& aFolderGuid,

View File

@ -255,6 +255,17 @@ public:
*/
void NotifyItemChanged(const ItemChangeData& aData);
/**
* Recursively builds an array of descendant folders inside a given folder.
*
* @param aFolderId
* The folder to fetch descendants from.
* @param aDescendantFoldersArray
* Output array to put descendant folders id.
*/
nsresult GetDescendantFolders(PRInt64 aFolderId,
nsTArray<PRInt64>& aDescendantFoldersArray);
private:
static nsNavBookmarks* gBookmarksService;

View File

@ -1704,32 +1704,8 @@ static
bool NeedToFilterResultSet(const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions *aOptions)
{
// Never filter queries returning queries
PRUint16 resultType = aOptions->ResultType();
if (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)
return false;
// Always filter bookmarks queries to avoid the inclusion of query nodes,
// but RESULTS AS TAG QUERY never needs to be filtered.
if (aOptions->QueryType() == nsINavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS)
return true;
nsCString parentAnnotationToExclude;
nsresult rv = aOptions->GetExcludeItemIfParentHasAnnotation(parentAnnotationToExclude);
NS_ENSURE_SUCCESS(rv, true);
if (!parentAnnotationToExclude.IsEmpty())
return true;
// Need to filter on parent if any folder is set.
for (PRInt32 i = 0; i < aQueries.Count(); ++i) {
if (aQueries[i]->Folders().Length() != 0) {
return true;
}
}
return false;
return resultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS;
}
// ** Helper class for ConstructQueryString **/
@ -4026,6 +4002,7 @@ nsNavHistory::QueryToSelectClause(nsNavHistoryQuery* aQuery, // const
nsCString* aClause)
{
bool hasIt;
bool excludeQueries = aOptions->ExcludeQueries();
ConditionBuilder clause(aQueryIndex);
@ -4051,6 +4028,8 @@ nsNavHistory::QueryToSelectClause(nsNavHistoryQuery* aQuery, // const
.Str(", h.url, page_title, tags, ")
.Str(nsPrintfCString(17, "0, 0, 0, 0, %d, 0)",
mozIPlacesAutoComplete::MATCH_ANYWHERE_UNMODIFIED).get());
// Serching by terms implicitly exclude queries.
excludeQueries = true;
}
// min and max visit count
@ -4142,11 +4121,35 @@ nsNavHistory::QueryToSelectClause(nsNavHistoryQuery* aQuery, // const
).Param(param.get()).Str(" LIMIT 1)");
}
// 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");
// folders
const nsTArray<PRInt64>& folders = aQuery->Folders();
if (folders.Length() > 0) {
nsTArray<PRInt64> includeFolders;
includeFolders.AppendElements(folders);
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_STATE(bookmarks);
for (nsTArray<PRInt64>::size_type i = 0; i < folders.Length(); ++i) {
nsTArray<PRInt64> subFolders;
if (NS_FAILED(bookmarks->GetDescendantFolders(folders[i], subFolders)))
continue;
includeFolders.AppendElements(subFolders);
}
clause.Condition("b.parent IN(");
for (nsTArray<PRInt64>::size_type i = 0; i < includeFolders.Length(); ++i) {
clause.Str(nsPrintfCString("%d", includeFolders[i]).get());
if (i < includeFolders.Length() - 1) {
clause.Str(",");
}
}
clause.Str(")");
}
if (excludeQueries) {
// Serching by terms implicitly exclude queries.
clause.Condition("NOT h.url BETWEEN 'place:' AND 'place;'");
}
clause.GetClauseString(*aClause);
@ -4304,15 +4307,6 @@ nsNavHistory::BindQueryClauseParameters(mozIStorageBaseStatement* statement,
}
}
// parent parameter
if (aOptions->ResultType() == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS &&
aQuery->Folders().Length() == 1) {
rv = statement->BindInt64ByName(
NS_LITERAL_CSTRING("parent") + qIndex, aQuery->Folders()[0]
);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
@ -4389,12 +4383,8 @@ nsNavHistory::GetTagsFolder()
// nsNavHistory::FilterResultSet
//
// This does some post-query-execution filtering:
// - searching on title & url
// - parent folder (recursively)
// - excludeQueries
// - tags
// - searching on title, url and tags
// - limit count
// - excludingLivemarkItems
//
// Note: changes to filtering in FilterResultSet()
// may require changes to NeedToFilterResultSet()
@ -4406,8 +4396,6 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode,
const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions *aOptions)
{
nsresult rv;
// get the bookmarks service
nsNavBookmarks *bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
@ -4416,59 +4404,6 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode,
nsTArray<nsTArray<nsString>*> terms;
ParseSearchTermsFromQueries(aQueries, &terms);
// The includeFolders array for each query is initialized with its
// query's folders array. We add sub-folders as we check items.
nsTArray< nsTArray<PRInt64>* > includeFolders;
nsTArray< nsTArray<PRInt64>* > excludeFolders;
for (PRInt32 queryIndex = 0;
queryIndex < aQueries.Count(); queryIndex++) {
includeFolders.AppendElement(new nsTArray<PRInt64>(aQueries[queryIndex]->Folders()));
excludeFolders.AppendElement(new nsTArray<PRInt64>());
}
// Filter against query options.
// XXX Only excludeQueries and excludeItemIfParentHasAnnotation are supported
// at the moment.
bool excludeQueries = false;
if (aQueryNode) {
rv = aQueryNode->mOptions->GetExcludeQueries(&excludeQueries);
NS_ENSURE_SUCCESS(rv, rv);
}
nsCString parentAnnotationToExclude;
nsTArray<PRInt64> parentFoldersToExclude;
if (aQueryNode) {
rv = aQueryNode->mOptions->GetExcludeItemIfParentHasAnnotation(parentAnnotationToExclude);
NS_ENSURE_SUCCESS(rv, rv);
}
if (!parentAnnotationToExclude.IsEmpty()) {
// Find all the folders with the annotation we are excluding and save their
// item ids. When doing filtering, if item id of a result's parent
// matches one of the saved item ids, the result will be excluded.
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
"SELECT a.item_id, a.content "
"FROM moz_anno_attributes n "
"JOIN moz_items_annos a ON n.id = a.anno_attribute_id "
"WHERE n.name = :anno_name "
);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
rv = stmt->BindUTF8StringByName(
NS_LITERAL_CSTRING("anno_name"), parentAnnotationToExclude
);
NS_ENSURE_SUCCESS(rv, rv);
bool hasMore = false;
while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) && hasMore) {
PRInt64 folderId = 0;
rv = stmt->GetInt64(0, &folderId);
NS_ENSURE_SUCCESS(rv, rv);
parentFoldersToExclude.AppendElement(folderId);
}
}
PRUint16 resultType = aOptions->ResultType();
for (PRInt32 nodeIndex = 0; nodeIndex < aSet.Count(); nodeIndex++) {
// exclude-queries is implicit when searching, we're only looking at
@ -4490,12 +4425,6 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode,
parentId = aSet[nodeIndex]->mFolderId;
}
// if we are excluding items by parent annotation,
// exclude items who's parent is a folder with that annotation
if (!parentAnnotationToExclude.IsEmpty() &&
parentFoldersToExclude.Contains(parentId))
continue;
// Append the node only if it matches one of the queries.
bool appendNode = false;
for (PRInt32 queryIndex = 0;
@ -4528,55 +4457,13 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode,
continue;
}
// Filter bookmarks on parent folder.
// RESULTS_AS_TAG_CONTENTS changes bookmarks' parents, so we cannot filter
// this kind of result based on the parent.
if (includeFolders[queryIndex]->Length() != 0 &&
resultType != nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS) {
// Filter out the node if its parent is in the excludeFolders
// cache or it has no parent.
if (excludeFolders[queryIndex]->Contains(parentId) || parentId == -1) {
continue;
}
if (!includeFolders[queryIndex]->Contains(parentId)) {
// If parent is not found in current includeFolders cache, we check
// its ancestors.
PRInt64 ancestor = parentId;
bool belongs = false;
nsTArray<PRInt64> ancestorFolders;
while (!belongs) {
// Avoid using |ancestor| itself if GetFolderIdForItem failed.
ancestorFolders.AppendElement(ancestor);
// GetFolderIdForItems throws when called for the places-root
if (NS_FAILED(bookmarks->GetFolderIdForItem(ancestor, &ancestor))) {
break;
} else if (excludeFolders[queryIndex]->Contains(ancestor)) {
break;
} else if (includeFolders[queryIndex]->Contains(ancestor)) {
belongs = true;
}
}
// if the parentId or any of its ancestors "belong",
// include all of them. otherwise, exclude all of them.
if (belongs) {
includeFolders[queryIndex]->AppendElements(ancestorFolders);
} else {
excludeFolders[queryIndex]->AppendElements(ancestorFolders);
continue;
}
}
}
// We passed all filters, so we can append the node to filtered results.
appendNode = true;
}
if (appendNode)
aFiltered->AppendObject(aSet[nodeIndex]);
// Stop once we have reached max results.
if (aOptions->MaxResults() > 0 &&
(PRUint32)aFiltered->Count() >= aOptions->MaxResults())
@ -4586,8 +4473,6 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode,
// De-allocate the temporary matrixes.
for (PRInt32 i = 0; i < aQueries.Count(); i++) {
delete terms[i];
delete includeFolders[i];
delete excludeFolders[i];
}
return NS_OK;

View File

@ -168,7 +168,6 @@ static void SetOptionsKeyUint32(const nsCString& aValue,
#define QUERYKEY_EXCLUDE_ITEMS "excludeItems"
#define QUERYKEY_EXCLUDE_QUERIES "excludeQueries"
#define QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS "excludeReadOnlyFolders"
#define QUERYKEY_EXCLUDE_ITEM_IF_PARENT_HAS_ANNOTATION "excludeItemIfParentHasAnnotation"
#define QUERYKEY_EXPAND_QUERIES "expandQueries"
#define QUERYKEY_FORCE_ORIGINAL_TITLE "originalTitle"
#define QUERYKEY_INCLUDE_HIDDEN "includeHidden"
@ -583,18 +582,6 @@ nsNavHistory::QueriesToQueryString(nsINavHistoryQuery **aQueries,
queryString += NS_LITERAL_CSTRING(QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS "=1");
}
// exclude item if parent has annotation
nsCAutoString parentAnnotationToExclude;
if (NS_SUCCEEDED(options->GetExcludeItemIfParentHasAnnotation(parentAnnotationToExclude)) &&
!parentAnnotationToExclude.IsEmpty()) {
nsCString escaped;
if (!NS_Escape(parentAnnotationToExclude, escaped, url_XAlphas))
return NS_ERROR_OUT_OF_MEMORY;
AppendAmpersandIfNonempty(queryString);
queryString += NS_LITERAL_CSTRING(QUERYKEY_EXCLUDE_ITEM_IF_PARENT_HAS_ANNOTATION "=");
queryString.Append(escaped);
}
// expand queries
if (!options->ExpandQueries()) {
AppendAmpersandIfNonempty(queryString);
@ -881,13 +868,6 @@ nsNavHistory::TokensToQueries(const nsTArray<QueryKeyValuePair>& aTokens,
SetOptionsKeyBool(kvp.value, aOptions,
&nsINavHistoryQueryOptions::SetExcludeReadOnlyFolders);
// exclude item if parent has annotation
} else if (kvp.key.EqualsLiteral(QUERYKEY_EXCLUDE_ITEM_IF_PARENT_HAS_ANNOTATION)) {
nsCString parentAnnotationToExclude = kvp.value;
NS_UnescapeURL(parentAnnotationToExclude);
rv = aOptions->SetExcludeItemIfParentHasAnnotation(parentAnnotationToExclude);
NS_ENSURE_SUCCESS(rv, rv);
// expand queries
} else if (kvp.key.EqualsLiteral(QUERYKEY_EXPAND_QUERIES)) {
SetOptionsKeyBool(kvp.value, aOptions,
@ -1513,19 +1493,6 @@ nsNavHistoryQueryOptions::SetExcludeReadOnlyFolders(bool aExclude)
return NS_OK;
}
// excludeItemIfParentHasAnnotation
NS_IMETHODIMP
nsNavHistoryQueryOptions::GetExcludeItemIfParentHasAnnotation(nsACString& _result) {
_result.Assign(mParentAnnotationToExclude);
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryOptions::SetExcludeItemIfParentHasAnnotation(const nsACString& aParentAnnotationToExclude) {
mParentAnnotationToExclude.Assign(aParentAnnotationToExclude);
return NS_OK;
}
// expandQueries
NS_IMETHODIMP
nsNavHistoryQueryOptions::GetExpandQueries(bool* aExpand)

View File

@ -3709,15 +3709,10 @@ nsNavHistoryFolderResultNode::StartIncrementalUpdate()
{
// if any items are excluded, we can not do incremental updates since the
// indices from the bookmark service will not be valid
nsCAutoString parentAnnotationToExclude;
nsresult rv = mOptions->GetExcludeItemIfParentHasAnnotation(parentAnnotationToExclude);
NS_ENSURE_SUCCESS(rv, false);
if (!mOptions->ExcludeItems() &&
!mOptions->ExcludeQueries() &&
!mOptions->ExcludeReadOnlyFolders() &&
parentAnnotationToExclude.IsEmpty()) {
if (!mOptions->ExcludeItems() &&
!mOptions->ExcludeQueries() &&
!mOptions->ExcludeReadOnlyFolders()) {
// easy case: we are visible, always do incremental update
if (mExpanded || AreChildrenVisible())
return true;

View File

@ -458,21 +458,6 @@ const queryOptionSwitches = [
}
]
},
// excludeItemIfParentHasAnnotation
{
property: "excludeItemIfParentHasAnnotation",
desc: "nsINavHistoryQueryOptions.excludeItemIfParentHasAnnotation",
matches: simplePropertyMatches,
runs: [
function (aQuery, aQueryOptions) {
aQueryOptions.excludeItemIfParentHasAnnotation =
"bookmarks/toolbarFolder";
},
function (aQuery, aQueryOptions) {
aQueryOptions.excludeItemIfParentHasAnnotation = "";
}
]
},
// expandQueries
{
property: "expandQueries",