зеркало из https://github.com/mozilla/pjs.git
Bug 317847 Implement "Save this Search" (r=mano)
This commit is contained in:
Родитель
b598dd7662
Коммит
49382c7e2e
|
@ -192,10 +192,6 @@ var PlacesOrganizer = {
|
||||||
// Items are only excluded on the left pane
|
// Items are only excluded on the left pane
|
||||||
var options = node.queryOptions.clone();
|
var options = node.queryOptions.clone();
|
||||||
options.excludeItems = false;
|
options.excludeItems = false;
|
||||||
// Unset excludeQueries so incremental update is enabled for the content
|
|
||||||
// pane.
|
|
||||||
// XXXmano: remove that once we unset excludeQueries for the left pane.
|
|
||||||
options.excludeQueries = false;
|
|
||||||
|
|
||||||
this._content.load(queries,
|
this._content.load(queries,
|
||||||
OptionsFilter.filter(queries, options, null));
|
OptionsFilter.filter(queries, options, null));
|
||||||
|
@ -343,6 +339,57 @@ var PlacesOrganizer = {
|
||||||
}
|
}
|
||||||
gEditItemOverlay.uninitPanel();
|
gEditItemOverlay.uninitPanel();
|
||||||
deck.selectedIndex = 0;
|
deck.selectedIndex = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the current search (or advanced query) to the bookmarks root.
|
||||||
|
*/
|
||||||
|
saveSearch: function PP_saveSearch() {
|
||||||
|
// Get the place: uri for the query.
|
||||||
|
// If the advanced query builder is showing, use that.
|
||||||
|
var queries = [];
|
||||||
|
var options = this.getCurrentOptions();
|
||||||
|
options.excludeQueries = true;
|
||||||
|
var advancedSearch = document.getElementById("advancedSearch");
|
||||||
|
if (!advancedSearch.collapsed) {
|
||||||
|
queries = PlacesQueryBuilder.queries;
|
||||||
|
}
|
||||||
|
// If not, use the value of the search box.
|
||||||
|
else if (PlacesSearchBox.value && PlacesSearchBox.value.length > 0) {
|
||||||
|
var query = PlacesUtils.history.getNewQuery();
|
||||||
|
query.searchTerms = PlacesSearchBox.value;
|
||||||
|
queries.push(query);
|
||||||
|
}
|
||||||
|
// if there is no query, do nothing.
|
||||||
|
else {
|
||||||
|
// XXX should probably have a dialog here to explain that the user needs to search first.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var placeSpec = PlacesUtils.history.queriesToQueryString(queries,
|
||||||
|
queries.length,
|
||||||
|
options);
|
||||||
|
var placeURI = IO.newURI(placeSpec);
|
||||||
|
|
||||||
|
// Prompt the user for a name for the query.
|
||||||
|
// XXX - using prompt service for now; will need to make
|
||||||
|
// a real dialog and localize when we're sure this is the UI we want.
|
||||||
|
var title = PlacesUtils.getString("saveSearch.title");
|
||||||
|
var inputLabel = PlacesUtils.getString("saveSearch.inputLabel");
|
||||||
|
var defaultText = PlacesUtils.getString("saveSearch.defaultText");
|
||||||
|
|
||||||
|
var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].
|
||||||
|
getService(Ci.nsIPromptService);
|
||||||
|
var check = {value: false};
|
||||||
|
var input = {value: defaultText};
|
||||||
|
var save = prompts.prompt(null, title, inputLabel, input, null, check);
|
||||||
|
|
||||||
|
// Don't add the query if the user cancels or clears the seach name.
|
||||||
|
if (!save || input.value == "")
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Add the place: uri as a bookmark under the places root.
|
||||||
|
var txn = PlacesUtils.ptm.createItem(placeURI, PlacesUtils.bookmarks.bookmarksRoot, PlacesUtils.bookmarks.DEFAULT_INDEX, input.value);
|
||||||
|
PlacesUtils.ptm.commitTransaction(txn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -384,8 +431,10 @@ var PlacesSearchBox = {
|
||||||
PO.setHeaderText(PO.HEADER_TYPE_SEARCH, filterString);
|
PO.setHeaderText(PO.HEADER_TYPE_SEARCH, filterString);
|
||||||
break;
|
break;
|
||||||
case "bookmarks":
|
case "bookmarks":
|
||||||
if (filterString != "")
|
if (filterString) {
|
||||||
content.applyFilter(filterString, true);
|
content.applyFilter(filterString, true);
|
||||||
|
PO.setHeaderText(PO.HEADER_TYPE_SEARCH, filterString);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
PlacesOrganizer.onPlaceSelected();
|
PlacesOrganizer.onPlaceSelected();
|
||||||
break;
|
break;
|
||||||
|
@ -445,6 +494,8 @@ var PlacesSearchBox = {
|
||||||
},
|
},
|
||||||
set filterCollection(collectionName) {
|
set filterCollection(collectionName) {
|
||||||
this.searchFilter.setAttribute("collection", collectionName);
|
this.searchFilter.setAttribute("collection", collectionName);
|
||||||
|
if (this.searchFilter.value)
|
||||||
|
return; // don't overwrite pre-existing search terms
|
||||||
var newGrayText = null;
|
var newGrayText = null;
|
||||||
if (collectionName == "collection")
|
if (collectionName == "collection")
|
||||||
newGrayText = PlacesOrganizer._places.selectedNode.title;
|
newGrayText = PlacesOrganizer._places.selectedNode.title;
|
||||||
|
@ -484,6 +535,9 @@ var PlacesSearchBox = {
|
||||||
*/
|
*/
|
||||||
var PlacesQueryBuilder = {
|
var PlacesQueryBuilder = {
|
||||||
|
|
||||||
|
queries: [],
|
||||||
|
queryOptions: null,
|
||||||
|
|
||||||
_numRows: 0,
|
_numRows: 0,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -906,7 +960,7 @@ var PlacesQueryBuilder = {
|
||||||
doSearch: function PQB_doSearch() {
|
doSearch: function PQB_doSearch() {
|
||||||
// Create the individual queries.
|
// Create the individual queries.
|
||||||
var queryType = document.getElementById("advancedSearchType").selectedItem.value;
|
var queryType = document.getElementById("advancedSearchType").selectedItem.value;
|
||||||
var queries = [];
|
this.queries = [];
|
||||||
if (queryType == "and")
|
if (queryType == "and")
|
||||||
queries.push(PlacesUtils.history.getNewQuery());
|
queries.push(PlacesUtils.history.getNewQuery());
|
||||||
var updated = 0;
|
var updated = 0;
|
||||||
|
@ -922,7 +976,7 @@ var PlacesQueryBuilder = {
|
||||||
// If they're being OR-ed, add a separate query for each row.
|
// If they're being OR-ed, add a separate query for each row.
|
||||||
var query;
|
var query;
|
||||||
if (queryType == "and")
|
if (queryType == "and")
|
||||||
query = queries[0];
|
query = this.queries[0];
|
||||||
else
|
else
|
||||||
query = PlacesUtils.history.getNewQuery();
|
query = PlacesUtils.history.getNewQuery();
|
||||||
|
|
||||||
|
@ -930,15 +984,15 @@ var PlacesQueryBuilder = {
|
||||||
this._queryBuilders[querySubject](query, prefix);
|
this._queryBuilders[querySubject](query, prefix);
|
||||||
|
|
||||||
if (queryType == "or")
|
if (queryType == "or")
|
||||||
queries.push(query);
|
this.queries.push(query);
|
||||||
|
|
||||||
++updated;
|
++updated;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we're getting uri results, not visits
|
// Make sure we're getting uri results, not visits
|
||||||
var options = PlacesOrganizer.getCurrentOptions();
|
this.options = PlacesOrganizer.getCurrentOptions();
|
||||||
options.resultType = options.RESULT_TYPE_URI;
|
this.options.resultType = options.RESULT_TYPE_URI;
|
||||||
|
|
||||||
// XXXben - find some public way of doing this!
|
// XXXben - find some public way of doing this!
|
||||||
PlacesOrganizer._content.load(queries,
|
PlacesOrganizer._content.load(queries,
|
||||||
|
|
|
@ -86,7 +86,8 @@
|
||||||
oncommand="PlacesOrganizer.exportBookmarks();"/>
|
oncommand="PlacesOrganizer.exportBookmarks();"/>
|
||||||
<command id="OrganizerCommand_import"
|
<command id="OrganizerCommand_import"
|
||||||
oncommand="PlacesOrganizer.importBookmarks();"/>
|
oncommand="PlacesOrganizer.importBookmarks();"/>
|
||||||
<command id="OrganizerCommand_search:save"/>
|
<command id="OrganizerCommand_search:save"
|
||||||
|
oncommand="PlacesOrganizer.saveSearch();"/>
|
||||||
<command id="OrganizerCommand_search:moreCriteria"
|
<command id="OrganizerCommand_search:moreCriteria"
|
||||||
oncommand="PlacesQueryBuilder.addRow();"/>
|
oncommand="PlacesQueryBuilder.addRow();"/>
|
||||||
</commandset>
|
</commandset>
|
||||||
|
|
|
@ -155,25 +155,25 @@
|
||||||
command="cmd_cut"
|
command="cmd_cut"
|
||||||
label="&cutCmd.label;"
|
label="&cutCmd.label;"
|
||||||
accesskey="&cutCmd.accesskey;"
|
accesskey="&cutCmd.accesskey;"
|
||||||
selection="separator|link|folder|mixed"
|
selection="separator|link|folder|mixed|query"
|
||||||
forcehideselection="livemarkChild"/>
|
forcehideselection="livemarkChild"/>
|
||||||
<menuitem id="placesContext_copy"
|
<menuitem id="placesContext_copy"
|
||||||
command="cmd_copy"
|
command="cmd_copy"
|
||||||
label="©Cmd.label;"
|
label="©Cmd.label;"
|
||||||
accesskey="©Cmd.accesskey;"
|
accesskey="©Cmd.accesskey;"
|
||||||
selection="separator|link|folder"/>
|
selection="separator|link|folder|query"/>
|
||||||
<menuitem id="placesContext_paste"
|
<menuitem id="placesContext_paste"
|
||||||
command="cmd_paste"
|
command="cmd_paste"
|
||||||
label="&pasteCmd.label;"
|
label="&pasteCmd.label;"
|
||||||
accesskey="&pasteCmd.accesskey;"
|
accesskey="&pasteCmd.accesskey;"
|
||||||
selection="mutable"/>
|
selection="mutable|query"/>
|
||||||
<menuseparator id="placesContext_editSeparator"/>
|
<menuseparator id="placesContext_editSeparator"/>
|
||||||
<menuitem id="placesContext_delete"
|
<menuitem id="placesContext_delete"
|
||||||
command="cmd_delete"
|
command="cmd_delete"
|
||||||
label="&deleteCmd.label;"
|
label="&deleteCmd.label;"
|
||||||
accesskey="&deleteCmd.accesskey;"
|
accesskey="&deleteCmd.accesskey;"
|
||||||
closemenu="single"
|
closemenu="single"
|
||||||
selection="host|separator|link|folder|day"
|
selection="host|separator|link|folder|day|query"
|
||||||
forcehideselection="livemarkChild"/>
|
forcehideselection="livemarkChild"/>
|
||||||
<menuseparator id="placesContext_deleteSeparator"/>
|
<menuseparator id="placesContext_deleteSeparator"/>
|
||||||
<menuitem id="placesContext_reload"
|
<menuitem id="placesContext_reload"
|
||||||
|
|
|
@ -77,3 +77,7 @@ status_foldercount = %S object(s)
|
||||||
|
|
||||||
SelectImport=Import Bookmarks File
|
SelectImport=Import Bookmarks File
|
||||||
EnterExport=Export Bookmarks File
|
EnterExport=Export Bookmarks File
|
||||||
|
|
||||||
|
saveSearch.title=Save Search
|
||||||
|
saveSearch.inputLabel=Name:
|
||||||
|
saveSearch.defaultText=New Query
|
||||||
|
|
|
@ -1550,7 +1550,7 @@ nsNavHistory::EvaluateQueryForNode(const nsCOMArray<nsNavHistoryQuery>& aQueries
|
||||||
nsCOMArray<nsNavHistoryResultNode> inputSet;
|
nsCOMArray<nsNavHistoryResultNode> inputSet;
|
||||||
inputSet.AppendObject(aNode);
|
inputSet.AppendObject(aNode);
|
||||||
nsCOMArray<nsNavHistoryResultNode> filteredSet;
|
nsCOMArray<nsNavHistoryResultNode> filteredSet;
|
||||||
nsresult rv = FilterResultSet(inputSet, &filteredSet, query->SearchTerms());
|
nsresult rv = FilterResultSet(nsnull, inputSet, &filteredSet, query->SearchTerms());
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
continue;
|
continue;
|
||||||
if (! filteredSet.Count())
|
if (! filteredSet.Count())
|
||||||
|
@ -2412,11 +2412,11 @@ nsNavHistory::GetQueryResults(nsNavHistoryQueryResultNode *aResultNode,
|
||||||
// keyword search
|
// keyword search
|
||||||
if (groupCount == 0) {
|
if (groupCount == 0) {
|
||||||
// keyword search with no grouping: can filter directly into the result
|
// keyword search with no grouping: can filter directly into the result
|
||||||
FilterResultSet(toplevel, aResults, aQueries[0]->SearchTerms());
|
FilterResultSet(aResultNode, toplevel, aResults, aQueries[0]->SearchTerms());
|
||||||
} else {
|
} else {
|
||||||
// keyword searching with grouping: need intermediate filtered results
|
// keyword searching with grouping: need intermediate filtered results
|
||||||
nsCOMArray<nsNavHistoryResultNode> filteredResults;
|
nsCOMArray<nsNavHistoryResultNode> filteredResults;
|
||||||
FilterResultSet(toplevel, &filteredResults, aQueries[0]->SearchTerms());
|
FilterResultSet(aResultNode, toplevel, &filteredResults, aQueries[0]->SearchTerms());
|
||||||
rv = RecursiveGroup(aResultNode, filteredResults, groupings, groupCount,
|
rv = RecursiveGroup(aResultNode, filteredResults, groupings, groupCount,
|
||||||
aResults);
|
aResults);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -4096,21 +4096,26 @@ nsNavHistory::GroupByHost(nsNavHistoryQueryResultNode *aResultNode,
|
||||||
|
|
||||||
// nsNavHistory::FilterResultSet
|
// nsNavHistory::FilterResultSet
|
||||||
//
|
//
|
||||||
// Currently, this just does title/url filtering. This should be expanded in
|
// This does some post-query-execution filtering:
|
||||||
// the future.
|
// - searching on title & url
|
||||||
|
// - excludeQueries
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsNavHistory::FilterResultSet(const nsCOMArray<nsNavHistoryResultNode>& aSet,
|
nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aParentNode,
|
||||||
|
const nsCOMArray<nsNavHistoryResultNode>& aSet,
|
||||||
nsCOMArray<nsNavHistoryResultNode>* aFiltered,
|
nsCOMArray<nsNavHistoryResultNode>* aFiltered,
|
||||||
const nsString& aSearch)
|
const nsString& aSearch)
|
||||||
{
|
{
|
||||||
|
nsresult rv;
|
||||||
nsStringArray terms;
|
nsStringArray terms;
|
||||||
ParseSearchQuery(aSearch, &terms);
|
ParseSearchQuery(aSearch, &terms);
|
||||||
|
|
||||||
// if there are no search terms, just return everything (i.e. do nothing)
|
// filter against query options
|
||||||
if (terms.Count() == 0) {
|
// XXX only excludeQueries is supported at the moment
|
||||||
aFiltered->AppendObjects(aSet);
|
PRBool excludeQueries = PR_FALSE;
|
||||||
return NS_OK;
|
if (aParentNode) {
|
||||||
|
rv = aParentNode->mOptions->GetExcludeQueries(&excludeQueries);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCStringArray searchAnnotations;
|
nsCStringArray searchAnnotations;
|
||||||
|
@ -4124,6 +4129,14 @@ nsNavHistory::FilterResultSet(const nsCOMArray<nsNavHistoryResultNode>& aSet,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (PRInt32 nodeIndex = 0; nodeIndex < aSet.Count(); nodeIndex ++) {
|
for (PRInt32 nodeIndex = 0; nodeIndex < aSet.Count(); nodeIndex ++) {
|
||||||
|
if (aParentNode) {
|
||||||
|
if (aParentNode->mItemId == aSet[nodeIndex]->mItemId)
|
||||||
|
continue; // filter out nodes that are the same as the parent
|
||||||
|
}
|
||||||
|
|
||||||
|
if (excludeQueries && IsQueryURI(aSet[nodeIndex]->mURI))
|
||||||
|
continue;
|
||||||
|
|
||||||
PRBool allTermsFound = PR_TRUE;
|
PRBool allTermsFound = PR_TRUE;
|
||||||
|
|
||||||
nsStringArray curAnnotations;
|
nsStringArray curAnnotations;
|
||||||
|
@ -4141,6 +4154,9 @@ nsNavHistory::FilterResultSet(const nsCOMArray<nsNavHistoryResultNode>& aSet,
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (terms.Count() == 0) {
|
||||||
|
allTermsFound = PR_TRUE;
|
||||||
|
} else {
|
||||||
for (PRInt32 termIndex = 0; termIndex < terms.Count(); termIndex ++) {
|
for (PRInt32 termIndex = 0; termIndex < terms.Count(); termIndex ++) {
|
||||||
PRBool termFound = PR_FALSE;
|
PRBool termFound = PR_FALSE;
|
||||||
// title and URL
|
// title and URL
|
||||||
|
@ -4163,6 +4179,8 @@ nsNavHistory::FilterResultSet(const nsCOMArray<nsNavHistoryResultNode>& aSet,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (allTermsFound)
|
if (allTermsFound)
|
||||||
aFiltered->AppendObject(aSet[nodeIndex]);
|
aFiltered->AppendObject(aSet[nodeIndex]);
|
||||||
}
|
}
|
||||||
|
@ -4318,9 +4336,8 @@ nsNavHistory::RowToResult(mozIStorageValueArray* aRow,
|
||||||
|
|
||||||
if (IsQueryURI(url)) {
|
if (IsQueryURI(url)) {
|
||||||
// special case "place:" URIs: turn them into containers
|
// special case "place:" URIs: turn them into containers
|
||||||
// XXX: should we set the bookmark identifier for this sort of nodes? It
|
PRInt64 itemId = aRow->AsInt64(kGetInfoIndex_ItemId);
|
||||||
// would sure break few assumption on the frontend side
|
return QueryRowToResult(itemId, url, title, accessCount, time, favicon, aResult);
|
||||||
return QueryRowToResult(url, title, accessCount, time, favicon, aResult);
|
|
||||||
} else if (aOptions->ResultType() == nsNavHistoryQueryOptions::RESULTS_AS_URI) {
|
} else if (aOptions->ResultType() == nsNavHistoryQueryOptions::RESULTS_AS_URI) {
|
||||||
*aResult = new nsNavHistoryResultNode(url, title, accessCount, time,
|
*aResult = new nsNavHistoryResultNode(url, title, accessCount, time,
|
||||||
favicon);
|
favicon);
|
||||||
|
@ -4387,7 +4404,8 @@ nsNavHistory::RowToResult(mozIStorageValueArray* aRow,
|
||||||
// folder or query node.
|
// folder or query node.
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsNavHistory::QueryRowToResult(const nsACString& aURI, const nsACString& aTitle,
|
nsNavHistory::QueryRowToResult(PRInt64 itemId, const nsACString& aURI,
|
||||||
|
const nsACString& aTitle,
|
||||||
PRUint32 aAccessCount, PRTime aTime,
|
PRUint32 aAccessCount, PRTime aTime,
|
||||||
const nsACString& aFavicon,
|
const nsACString& aFavicon,
|
||||||
nsNavHistoryResultNode** aNode)
|
nsNavHistoryResultNode** aNode)
|
||||||
|
@ -4422,6 +4440,7 @@ nsNavHistory::QueryRowToResult(const nsACString& aURI, const nsACString& aTitle,
|
||||||
queries, options);
|
queries, options);
|
||||||
if (! *aNode)
|
if (! *aNode)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
(*aNode)->mItemId = itemId;
|
||||||
NS_ADDREF(*aNode);
|
NS_ADDREF(*aNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,7 +249,8 @@ public:
|
||||||
nsresult RowToResult(mozIStorageValueArray* aRow,
|
nsresult RowToResult(mozIStorageValueArray* aRow,
|
||||||
nsNavHistoryQueryOptions* aOptions,
|
nsNavHistoryQueryOptions* aOptions,
|
||||||
nsNavHistoryResultNode** aResult);
|
nsNavHistoryResultNode** aResult);
|
||||||
nsresult QueryRowToResult(const nsACString& aURI, const nsACString& aTitle,
|
nsresult QueryRowToResult(PRInt64 aItemId, const nsACString& aURI,
|
||||||
|
const nsACString& aTitle,
|
||||||
PRUint32 aAccessCount, PRTime aTime,
|
PRUint32 aAccessCount, PRTime aTime,
|
||||||
const nsACString& aFavicon,
|
const nsACString& aFavicon,
|
||||||
nsNavHistoryResultNode** aNode);
|
nsNavHistoryResultNode** aNode);
|
||||||
|
@ -510,7 +511,8 @@ protected:
|
||||||
nsCOMArray<nsNavHistoryResultNode>* aDest,
|
nsCOMArray<nsNavHistoryResultNode>* aDest,
|
||||||
PRBool aIsDomain);
|
PRBool aIsDomain);
|
||||||
|
|
||||||
nsresult FilterResultSet(const nsCOMArray<nsNavHistoryResultNode>& aSet,
|
nsresult FilterResultSet(nsNavHistoryQueryResultNode *aParentNode,
|
||||||
|
const nsCOMArray<nsNavHistoryResultNode>& aSet,
|
||||||
nsCOMArray<nsNavHistoryResultNode>* aFiltered,
|
nsCOMArray<nsNavHistoryResultNode>* aFiltered,
|
||||||
const nsString& aSearch);
|
const nsString& aSearch);
|
||||||
|
|
||||||
|
|
|
@ -470,9 +470,9 @@ nsNavHistory::QueriesToQueryString(nsINavHistoryQuery **aQueries,
|
||||||
}
|
}
|
||||||
|
|
||||||
// expand queries
|
// expand queries
|
||||||
if (options->ExpandQueries()) {
|
if (!options->ExpandQueries()) {
|
||||||
AppendAmpersandIfNonempty(queryString);
|
AppendAmpersandIfNonempty(queryString);
|
||||||
queryString += NS_LITERAL_CSTRING(QUERYKEY_EXPAND_QUERIES "=1");
|
queryString += NS_LITERAL_CSTRING(QUERYKEY_EXPAND_QUERIES "=0");
|
||||||
}
|
}
|
||||||
|
|
||||||
// include hidden
|
// include hidden
|
||||||
|
|
|
@ -122,7 +122,7 @@ public:
|
||||||
mExcludeItems(PR_FALSE),
|
mExcludeItems(PR_FALSE),
|
||||||
mExcludeQueries(PR_FALSE),
|
mExcludeQueries(PR_FALSE),
|
||||||
mExcludeReadOnlyFolders(PR_FALSE),
|
mExcludeReadOnlyFolders(PR_FALSE),
|
||||||
mExpandQueries(PR_FALSE),
|
mExpandQueries(PR_TRUE),
|
||||||
mIncludeHidden(PR_FALSE),
|
mIncludeHidden(PR_FALSE),
|
||||||
mShowSessions(PR_FALSE),
|
mShowSessions(PR_FALSE),
|
||||||
mMaxResults(0),
|
mMaxResults(0),
|
||||||
|
|
|
@ -1894,14 +1894,19 @@ nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode(
|
||||||
//
|
//
|
||||||
// Whoever made us may want non-expanding queries. However, we always
|
// Whoever made us may want non-expanding queries. However, we always
|
||||||
// expand when we are the root node, or else asking for non-expanding
|
// expand when we are the root node, or else asking for non-expanding
|
||||||
// queries would be useless.
|
// queries would be useless. A query node is not expandable if excludeItems=1
|
||||||
|
// or expandQueries=0.
|
||||||
|
|
||||||
PRBool
|
PRBool
|
||||||
nsNavHistoryQueryResultNode::CanExpand()
|
nsNavHistoryQueryResultNode::CanExpand()
|
||||||
{
|
{
|
||||||
nsNavHistoryQueryOptions* options = GetGeneratingOptions();
|
nsNavHistoryQueryOptions* options = GetGeneratingOptions();
|
||||||
if (options && options->ExpandQueries())
|
if (options) {
|
||||||
|
if (options->ExcludeItems())
|
||||||
|
return PR_FALSE;
|
||||||
|
if (options->ExpandQueries())
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
|
}
|
||||||
if (mResult && mResult->mRootNode == this)
|
if (mResult && mResult->mRootNode == this)
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
|
@ -1939,7 +1944,7 @@ nsNavHistoryQueryResultNode::OnRemoving()
|
||||||
nsresult
|
nsresult
|
||||||
nsNavHistoryQueryResultNode::OpenContainer()
|
nsNavHistoryQueryResultNode::OpenContainer()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(! mExpanded, "Container must be expanded to close it");
|
NS_ASSERTION(!mExpanded, "Container must be closed to open it");
|
||||||
mExpanded = PR_TRUE;
|
mExpanded = PR_TRUE;
|
||||||
if (!CanExpand())
|
if (!CanExpand())
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -2568,7 +2573,7 @@ nsNavHistoryQueryResultNode::OnItemChanged(PRInt64 aItemId,
|
||||||
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
|
if (mLiveUpdate == QUERYUPDATE_COMPLEX_WITH_BOOKMARKS)
|
||||||
return Refresh();
|
return Refresh();
|
||||||
else
|
else
|
||||||
NS_NOTREACHED("history observers should not get OnItemChanged, but should get the corresponding history notifications instead");
|
NS_WARNING("history observers should not get OnItemChanged, but should get the corresponding history notifications instead");
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3050,8 +3055,21 @@ nsNavHistoryFolderResultNode::OnItemAdded(PRInt64 aItemId,
|
||||||
nsresult rv = bookmarks->GetItemType(aItemId, &itemType);
|
nsresult rv = bookmarks->GetItemType(aItemId, &itemType);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// check for query URIs, which are bookmarks, but treated as containers
|
||||||
|
// in results and views.
|
||||||
|
PRBool isQuery = PR_FALSE;
|
||||||
|
if (itemType == nsINavBookmarksService::TYPE_BOOKMARK) {
|
||||||
|
nsCOMPtr<nsIURI> itemURI;
|
||||||
|
rv = bookmarks->GetBookmarkURI(aItemId, getter_AddRefs(itemURI));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
nsCAutoString itemURISpec;
|
||||||
|
rv = itemURI->GetSpec(itemURISpec);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
isQuery = IsQueryURI(itemURISpec);
|
||||||
|
}
|
||||||
|
|
||||||
if (itemType != nsINavBookmarksService::TYPE_FOLDER &&
|
if (itemType != nsINavBookmarksService::TYPE_FOLDER &&
|
||||||
mOptions->ExcludeItems()) {
|
!isQuery && mOptions->ExcludeItems()) {
|
||||||
// don't update items when we aren't displaying them, but we still need
|
// don't update items when we aren't displaying them, but we still need
|
||||||
// to adjust bookmark indices to account for the insertion
|
// to adjust bookmark indices to account for the insertion
|
||||||
ReindexRange(aIndex, PR_INT32_MAX, 1);
|
ReindexRange(aIndex, PR_INT32_MAX, 1);
|
||||||
|
@ -3517,7 +3535,7 @@ nsNavHistoryResult::AddAllBookmarksObserver(nsNavHistoryQueryResultNode* aNode)
|
||||||
mIsAllBookmarksObserver = PR_TRUE;
|
mIsAllBookmarksObserver = PR_TRUE;
|
||||||
}
|
}
|
||||||
if (mAllBookmarksObservers.IndexOf(aNode) != mAllBookmarksObservers.NoIndex) {
|
if (mAllBookmarksObservers.IndexOf(aNode) != mAllBookmarksObservers.NoIndex) {
|
||||||
NS_NOTREACHED("Attempting to register an observer twice!");
|
NS_WARNING("Attempting to register an observer twice!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mAllBookmarksObservers.AppendElement(aNode);
|
mAllBookmarksObservers.AppendElement(aNode);
|
||||||
|
|
|
@ -443,7 +443,8 @@ function run_test() {
|
||||||
var node = rootNode.getChild(i);
|
var node = rootNode.getChild(i);
|
||||||
if (node.type == node.RESULT_TYPE_FOLDER ||
|
if (node.type == node.RESULT_TYPE_FOLDER ||
|
||||||
node.type == node.RESULT_TYPE_URI ||
|
node.type == node.RESULT_TYPE_URI ||
|
||||||
node.type == node.RESULT_TYPE_SEPARATOR) {
|
node.type == node.RESULT_TYPE_SEPARATOR ||
|
||||||
|
node.type == node.RESULT_TYPE_QUERY) {
|
||||||
do_check_true(node.itemId > 0);
|
do_check_true(node.itemId > 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -0,0 +1,250 @@
|
||||||
|
/* -*- 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 mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is Google Inc.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Darin Fisher <darin@meer.net>
|
||||||
|
* Dietrich Ayala <dietrich@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
|
||||||
|
* 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 bookmark service
|
||||||
|
try {
|
||||||
|
var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].getService(Ci.nsINavBookmarksService);
|
||||||
|
} catch(ex) {
|
||||||
|
do_throw("Could not get nav-bookmarks-service\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get history service
|
||||||
|
try {
|
||||||
|
var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].getService(Ci.nsINavHistoryService);
|
||||||
|
} catch(ex) {
|
||||||
|
do_throw("Could not get history service\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get annotation service
|
||||||
|
try {
|
||||||
|
var annosvc= Cc["@mozilla.org/browser/annotation-service;1"].getService(Ci.nsIAnnotationService);
|
||||||
|
} catch(ex) {
|
||||||
|
do_throw("Could not get annotation service\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get global history service
|
||||||
|
try {
|
||||||
|
var bhist = Cc["@mozilla.org/browser/global-history;2"].getService(Ci.nsIBrowserHistory);
|
||||||
|
} catch(ex) {
|
||||||
|
do_throw("Could not get history service\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// get bookmarks root id
|
||||||
|
var root = bmsvc.bookmarksRoot;
|
||||||
|
|
||||||
|
// main
|
||||||
|
function run_test() {
|
||||||
|
// a search term that matches a default bookmark
|
||||||
|
var searchTerm = "about";
|
||||||
|
|
||||||
|
// create a folder to hold all the tests
|
||||||
|
// this makes the tests more tolerant of changes to the default bookmarks set
|
||||||
|
// also, name it using the search term, for testing that containers that match don't show up in query results
|
||||||
|
var testRoot = bmsvc.createFolder(root, searchTerm, bmsvc.DEFAULT_INDEX);
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* saved searches - bookmarks
|
||||||
|
******************************************/
|
||||||
|
|
||||||
|
// add a bookmark that matches the search term
|
||||||
|
var bookmarkId = bmsvc.insertBookmark(root, uri("http://foo.com"), bmsvc.DEFAULT_INDEX, searchTerm);
|
||||||
|
|
||||||
|
// create a saved-search that matches a default bookmark
|
||||||
|
var searchId = bmsvc.insertBookmark(testRoot,
|
||||||
|
uri("place:terms=" + searchTerm + "&excludeQueries=1&expandQueries=1&queryType=1"),
|
||||||
|
bmsvc.DEFAULT_INDEX, searchTerm);
|
||||||
|
|
||||||
|
// query for the test root, expandQueries=0
|
||||||
|
// the query should show up as a regular bookmark
|
||||||
|
try {
|
||||||
|
var options = histsvc.getNewQueryOptions();
|
||||||
|
options.expandQueries = 0;
|
||||||
|
var query = histsvc.getNewQuery();
|
||||||
|
query.setFolders([testRoot], 1);
|
||||||
|
var result = histsvc.executeQuery(query, options);
|
||||||
|
var rootNode = result.root;
|
||||||
|
rootNode.containerOpen = true;
|
||||||
|
var cc = rootNode.childCount;
|
||||||
|
do_check_eq(cc, 1);
|
||||||
|
for (var i = 0; i < cc; i++) {
|
||||||
|
var node = rootNode.getChild(i);
|
||||||
|
// test that queries have valid itemId
|
||||||
|
do_check_true(node.itemId > 0);
|
||||||
|
// test that the container is closed
|
||||||
|
node.QueryInterface(Ci.nsINavHistoryContainerResultNode);
|
||||||
|
do_check_eq(node.containerOpen, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(ex) {
|
||||||
|
do_throw("expandQueries=0 query error: " + ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bookmark saved search
|
||||||
|
// query for the test root, expandQueries=1
|
||||||
|
// the query should show up as a query container, with 1 child
|
||||||
|
try {
|
||||||
|
var options = histsvc.getNewQueryOptions();
|
||||||
|
options.expandQueries = 1;
|
||||||
|
var query = histsvc.getNewQuery();
|
||||||
|
query.setFolders([testRoot], 1);
|
||||||
|
var result = histsvc.executeQuery(query, options);
|
||||||
|
var rootNode = result.root;
|
||||||
|
rootNode.containerOpen = true;
|
||||||
|
var cc = rootNode.childCount;
|
||||||
|
do_check_eq(cc, 1);
|
||||||
|
for (var i = 0; i < cc; i++) {
|
||||||
|
var node = rootNode.getChild(i);
|
||||||
|
// test that query node type is container when expandQueries=1
|
||||||
|
do_check_eq(node.type, node.RESULT_TYPE_QUERY);
|
||||||
|
// test that queries (as containers) have valid itemId
|
||||||
|
do_check_true(node.itemId > 0);
|
||||||
|
node.QueryInterface(Ci.nsINavHistoryContainerResultNode);
|
||||||
|
node.containerOpen = true;
|
||||||
|
|
||||||
|
// test that queries have children when excludeItems=1
|
||||||
|
// test that query nodes don't show containers (shouldn't have our folder that matches)
|
||||||
|
// test that queries don't show themselves in query results (shouldn't have our saved search)
|
||||||
|
do_check_eq(node.childCount, 1);
|
||||||
|
|
||||||
|
// test that bookmark shows in query results
|
||||||
|
var item = node.getChild(0);
|
||||||
|
do_check_eq(item.itemId, bookmarkId);
|
||||||
|
|
||||||
|
// XXX - FAILING - test live-update of query results - add a bookmark that matches the query
|
||||||
|
//var tmpBmId = bmsvc.insertBookmark(root, uri("http://" + searchTerm + ".com"), bmsvc.DEFAULT_INDEX, searchTerm + "blah");
|
||||||
|
//do_check_eq(query.childCount, 2);
|
||||||
|
|
||||||
|
// XXX - test live-update of query results - delete a bookmark that matches the query
|
||||||
|
//bmsvc.removeItem(tmpBMId);
|
||||||
|
//do_check_eq(query.childCount, 1);
|
||||||
|
|
||||||
|
// test live-update of query results - add a folder that matches the query
|
||||||
|
bmsvc.createFolder(root, searchTerm + "zaa", bmsvc.DEFAULT_INDEX);
|
||||||
|
do_check_eq(node.childCount, 1);
|
||||||
|
// test live-update of query results - add a query that matches the query
|
||||||
|
bmsvc.insertBookmark(root, uri("place:terms=foo&excludeQueries=1&expandQueries=1&queryType=1"),
|
||||||
|
bmsvc.DEFAULT_INDEX, searchTerm + "blah");
|
||||||
|
do_check_eq(node.childCount, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(ex) {
|
||||||
|
do_throw("expandQueries=1 bookmarks query: " + ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the bookmark search
|
||||||
|
bmsvc.removeItem(searchId);
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* saved searches - history
|
||||||
|
******************************************/
|
||||||
|
|
||||||
|
// add a visit that matches the search term
|
||||||
|
var testURI = uri("http://" + searchTerm + ".com");
|
||||||
|
bhist.addPageWithDetails(testURI, searchTerm, Date.now());
|
||||||
|
|
||||||
|
// create a saved-search that matches the visit we added
|
||||||
|
var searchId = bmsvc.insertBookmark(testRoot,
|
||||||
|
uri("place:terms=" + searchTerm + "&excludeQueries=1&expandQueries=1&queryType=0"),
|
||||||
|
bmsvc.DEFAULT_INDEX, searchTerm);
|
||||||
|
|
||||||
|
// query for the test root, expandQueries=1
|
||||||
|
// the query should show up as a query container, with 1 child
|
||||||
|
try {
|
||||||
|
var options = histsvc.getNewQueryOptions();
|
||||||
|
options.expandQueries = 1;
|
||||||
|
var query = histsvc.getNewQuery();
|
||||||
|
query.setFolders([testRoot], 1);
|
||||||
|
var result = histsvc.executeQuery(query, options);
|
||||||
|
var rootNode = result.root;
|
||||||
|
rootNode.containerOpen = true;
|
||||||
|
var cc = rootNode.childCount;
|
||||||
|
do_check_eq(cc, 1);
|
||||||
|
for (var i = 0; i < cc; i++) {
|
||||||
|
var node = rootNode.getChild(i);
|
||||||
|
// test that query node type is container when expandQueries=1
|
||||||
|
do_check_eq(node.type, node.RESULT_TYPE_QUERY);
|
||||||
|
// test that queries (as containers) have valid itemId
|
||||||
|
do_check_eq(node.itemId, searchId);
|
||||||
|
node.QueryInterface(Ci.nsINavHistoryContainerResultNode);
|
||||||
|
node.containerOpen = true;
|
||||||
|
|
||||||
|
// test that queries have children when excludeItems=1
|
||||||
|
// test that query nodes don't show containers (shouldn't have our folder that matches)
|
||||||
|
// test that queries don't show themselves in query results (shouldn't have our saved search)
|
||||||
|
do_check_eq(node.childCount, 1);
|
||||||
|
|
||||||
|
// test that history visit shows in query results
|
||||||
|
var item = node.getChild(0);
|
||||||
|
do_check_eq(item.type, item.RESULT_TYPE_URI);
|
||||||
|
do_check_eq(item.itemId, -1); // history visit
|
||||||
|
do_check_eq(item.uri, testURI.spec); // history visit
|
||||||
|
|
||||||
|
// test live-update of query results - add a history visit that matches the query
|
||||||
|
bhist.addPageWithDetails(uri("http://foo.com"), searchTerm + "blah", Date.now());
|
||||||
|
do_check_eq(node.childCount, 2);
|
||||||
|
|
||||||
|
// test live-update of query results - delete a history visit that matches the query
|
||||||
|
bhist.removePage(uri("http://foo.com"));
|
||||||
|
do_check_eq(node.childCount, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test live-update of moved queries
|
||||||
|
var tmpFolderId = bmsvc.createFolder(testRoot, "foo", bmsvc.DEFAULT_INDEX);
|
||||||
|
bmsvc.moveItem(searchId, tmpFolderId, bmsvc.DEFAULT_INDEX);
|
||||||
|
var tmpFolderNode = rootNode.getChild(0);
|
||||||
|
do_check_eq(tmpFolderNode.itemId, tmpFolderId);
|
||||||
|
tmpFolderNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
|
||||||
|
tmpFolderNode.containerOpen = true;
|
||||||
|
do_check_eq(tmpFolderNode.childCount, 1);
|
||||||
|
|
||||||
|
// test live-update of renamed queries
|
||||||
|
bmsvc.setItemTitle(searchId, "foo");
|
||||||
|
do_check_eq(tmpFolderNode.title, "foo");
|
||||||
|
|
||||||
|
// test live-update of deleted queries
|
||||||
|
bmsvc.removeItem(searchId);
|
||||||
|
try {
|
||||||
|
var tmpFolderNode = root.getChild(1);
|
||||||
|
do_throw("query was not removed");
|
||||||
|
} catch(ex) {}
|
||||||
|
}
|
||||||
|
catch(ex) {
|
||||||
|
do_throw("expandQueries=1 bookmarks query: " + ex);
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче