Bug 324553, r=bryner. Finish remote container API plus manay misc fixes and cleanup.

This commit is contained in:
brettw%gmail.com 2006-01-26 20:24:25 +00:00
parent 702907f622
commit 03e599bde3
16 changed files with 883 additions and 475 deletions

View File

@ -39,9 +39,6 @@ const PREF_PLACES_GROUPING_GENERIC = "browser.places.grouping.generic";
const PREF_PLACES_GROUPING_BOOKMARK = "browser.places.grouping.bookmark"; const PREF_PLACES_GROUPING_BOOKMARK = "browser.places.grouping.bookmark";
// Default Search Queries // Default Search Queries
const QUERY_MONTH_HISTORY = "place:&group=2&sort=1&type=1";
const QUERY_DAY_HISTORY = "place:&beginTimeRef=1&endTimeRef=2&sort=4&type=1";
const QUERY_BOOKMARKS_MENU = "place:&folders=3&group=3";
const INDEX_HISTORY = 0; const INDEX_HISTORY = 0;
const INDEX_BOOKMARKS = 1; const INDEX_BOOKMARKS = 1;

View File

@ -51,8 +51,8 @@ XPIDLSRCS = \
nsIFaviconService.idl \ nsIFaviconService.idl \
nsINavHistoryService.idl \ nsINavHistoryService.idl \
nsINavBookmarksService.idl \ nsINavBookmarksService.idl \
nsIBookmarksContainer.idl \
nsILivemarkService.idl \ nsILivemarkService.idl \
nsIRemoteContainer.idl \
$(NULL) $(NULL)
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

View File

@ -1,101 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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.
*
* 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):
* Annie Sullivan <annie.sullivan@gmail.com> (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 ***** */
#include "nsISupports.idl"
interface nsIURI;
/**
* The Bookmarks Container interface provides a base class
* for services that want to provide containers for bookmarks.
* Some examples of possible services are the livemarks service and
* the filesystem. Containers are implemented as bookmarked folders.
*/
[scriptable, uuid(45bf2020-9683-498c-9638-f08130c4151d)]
interface nsIBookmarksContainer : nsISupports
{
/**
* Called when the given container is about to be shown,
* so that the service can populate the container if necessary.
* @returns true if the data for the node has changed, false otherwise.
* @param container The folderId of the bookmark folder
* representing the container.
*/
boolean onContainerOpening(in PRInt64 container);
/**
* Called when the given container has just been hidden,
* so that the service can do any necessary cleanup.
* @param container The folderId of the bookmark folder
* representing the container.
*/
void onContainerClosed(in PRInt64 container);
/**
* Called when the given container is about to be deleted, so
* that the service can do any necessary cleanup.
* Called BEFORE the container is deleted, so that the service
* can still reference it.
* @param container The folderId of the bookmark folder
* representing the container to be deleted.
*/
void onContainerRemoving(in PRInt64 container);
/**
* Called when the given container has just been moved, in case
* the service needs to do any bookkeeping.
* Called AFTER the container has been moved, so the service can
* get the new URI.
* @param container The folderId of the bookmark folder
* representing the container to be moved.
* @param newFolder The folderId of the new parent folder
* for the container.
* @param newIndex The index the container will be inserted at,
* or -1 for append.
*/
void onContainerMoved(in PRInt64 container,
in PRInt64 newFolder, in PRInt32 newIndex);
/**
* Returns true if containers of this type should not expose UI for
* inserting, moving, or deleting children.
*/
readonly attribute boolean childrenReadOnly;
};

View File

@ -37,12 +37,12 @@
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl" #include "nsISupports.idl"
#include "nsIBookmarksContainer.idl" #include "nsIRemoteContainer.idl"
interface nsIURI; interface nsIURI;
[scriptable, uuid(b1257934-86cf-4143-8386-734ac352b6ba)] [scriptable, uuid(b1257934-86cf-4143-8386-734ac352b6ba)]
interface nsILivemarkService : nsIBookmarksContainer interface nsILivemarkService : nsIRemoteContainer
{ {
/** /**
* Creates a new livemark * Creates a new livemark

View File

@ -42,6 +42,8 @@
interface nsIFile; interface nsIFile;
interface nsINavHistoryContainerResultNode; interface nsINavHistoryContainerResultNode;
interface nsINavHistoryQueryResultNode;
interface nsINavHistoryFolderResultNode;
interface nsINavHistoryQuery; interface nsINavHistoryQuery;
interface nsINavHistoryQueryOptions; interface nsINavHistoryQueryOptions;
interface nsITransactionManager; interface nsITransactionManager;
@ -58,15 +60,20 @@ interface nsINavHistoryResultNode : nsISupports
readonly attribute nsINavHistoryContainerResultNode parent; readonly attribute nsINavHistoryContainerResultNode parent;
/** /**
* Identifies the type of this node. * Identifies the type of this node. This node can then be QI-ed to the
* corresponding specialized result node interface. The remote_container one
* is a little weird, it is a temportary folder generated by the remote
* container API. Note that bookmark folders can also be filled by the
* remote container API (these are the entrypoints for the API) and may
* have a remote container type as well.
*/ */
const PRUint32 RESULT_TYPE_URI = 0; const PRUint32 RESULT_TYPE_URI = 0; // nsINavHistoryURIResultNode
const PRUint32 RESULT_TYPE_VISIT = 1; const PRUint32 RESULT_TYPE_VISIT = 1; // nsINavHistoryVisitResultNode
const PRUint32 RESULT_TYPE_FULL_VISIT = 2; const PRUint32 RESULT_TYPE_FULL_VISIT = 2; // nsINavHistoryFullVisitResultNode
const PRUint32 RESULT_TYPE_HOST = 3; const PRUint32 RESULT_TYPE_HOST = 3; // nsINavHistoryContainerResultNode
const PRUint32 RESULT_TYPE_DAY = 4; const PRUint32 RESULT_TYPE_REMOTE_CONTAINER = 4; // nsINavHistoryContainerResultNode
const PRUint32 RESULT_TYPE_QUERY = 5; const PRUint32 RESULT_TYPE_QUERY = 5; // nsINavHistoryQueryResultNode
const PRUint32 RESULT_TYPE_FOLDER = 6; const PRUint32 RESULT_TYPE_FOLDER = 6; // nsINavHistoryFolderResultNode
readonly attribute PRUint32 type; readonly attribute PRUint32 type;
/** /**
@ -233,6 +240,97 @@ interface nsINavHistoryContainerResultNode : nsINavHistoryResultNode
* been called to override it, and true for non-folder nodes. * been called to override it, and true for non-folder nodes.
*/ */
readonly attribute boolean childrenReadOnly; readonly attribute boolean childrenReadOnly;
// --------------------------------------------------------------------------
// Remote container
/**
* This is a string representing the remote container API service that is
* responsible for this container. It is empty if there is none. This can
* be set for bookmark folders which have been registered, and also for
* RESULT_TYPE_REMOTE_CONTAINER nodes which have been dynamically generated
* by the remote container API.
*/
readonly attribute AUTF8String remoteContainerType;
/**
* Appends a full visit node to this container and returns it. For the remote
* container API. TO BE CALLED FROM nsIRemoteContainer::OnContainerOpening()
* ONLY, and only for non-bookmark-folder containers.
*
* @see nsINavHistoryURIResultNode for parameters.
*/
nsINavHistoryURIResultNode appendURINode(
in AUTF8String aTitle, in PRUint32 aAccessCount, in PRTime aTime,
in AUTF8String aIconURI, in AUTF8String aURI);
/**
* Appends a full visit node to this container and returns it. For the remote
* container API. TO BE CALLED FROM nsIRemoteContainer::OnContainerOpening()
* ONLY, and only for non-bookmark-folder containers.
*
* @see nsINavHistoryVisitResultNode for parameters.
*/
nsINavHistoryVisitResultNode appendVisitNode(
in AUTF8String aTitle, in PRUint32 aAccessCount, in PRTime aTime,
in AUTF8String aIconURI, in AUTF8String aURI, in PRInt64 aSession);
/**
* Appends a full visit node to this container and returns it. For the remote
* container API. TO BE CALLED FROM nsIRemoteContainer::OnContainerOpening()
* ONLY, and only for non-bookmark-folder containers.
*
* @see nsINavHistoryFullVisitResultNode for parameters.
*/
nsINavHistoryFullVisitResultNode appendFullVisitNode(
in AUTF8String aTitle, in PRUint32 aAccessCount, in PRTime aTime,
in AUTF8String aIconURI, in AUTF8String aURI, in PRInt64 aSession,
in PRInt64 aVisitId, in PRInt64 aReferringVisitId,
in PRInt32 aTransitionType);
/**
* Appends a container node to this container and returns it. For the remote
* container API. TO BE CALLED FROM nsIRemoteContainer::OnContainerOpening()
* ONLY, and only for non-bookmark-folder containers.
*
* aContainerType should be either RESULT_TYPE_HOST or
* RESULT_TYPE_REMOTE_CONTAINER. When type is remote container you must
* specify a remote container type, otherwise, the remote container type must
* be null. Use appendQueryNode and appendFolderNode for the other container
* types.
*/
nsINavHistoryContainerResultNode appendContainerNode(
in AUTF8String aTitle, in AUTF8String aIconURI, in PRUint32 aContainerType,
in AUTF8String aRemoteContainerType);
/**
* Appends a query node to this container and returns it. For the remote
* container API. TO BE CALLED FROM nsIRemoteContainer::OnContainerOpening()
* ONLY, and only for non-bookmark-folder containers.
*
* Normally you should supply an empty string for IconURI and it will take
* the default query icon for the current theme.
*/
nsINavHistoryQueryResultNode appendQueryNode(
in AUTF8String aTitle, in AUTF8String aIconURI, in AUTF8String aQueryString);
/**
* Appends a bookmark folder node to this container and returns it. For the
* remote container API. TO BE CALLED FROM nsIRemoteContainer::OnContainerOpening()
* ONLY, and only for non-bookmark-folder containers.
*
* All container attributes will come from the boomkarks service for this
* folder.
*/
nsINavHistoryFolderResultNode appendFolderNode(in PRInt64 aFolderId);
/**
* Clears all children of this container. For the remote container API.
* TO BE CALLED FROM nsIRemoteContainer::OnContainerOpening and
* nsIRemoteContainer::OnContainerClosed ONLY, and valid only for
* non-bookmark-folder containers.
*/
void clearContents();
}; };
@ -635,13 +733,6 @@ interface nsINavHistoryQuery : nsISupports
[scriptable, uuid(25fd4de4-33b0-475e-a63d-2bcb1d123e0d)] [scriptable, uuid(25fd4de4-33b0-475e-a63d-2bcb1d123e0d)]
interface nsINavHistoryQueryOptions : nsISupports interface nsINavHistoryQueryOptions : nsISupports
{ {
/**
* Grouping by day. The results will be an array of nsINavHistoryResults with
* type = RESULT_TYPE_DAY, one for each day where there are results. These
* will have children of corresponding to the search results of that day.
*/
const PRUint32 GROUP_BY_DAY = 0;
/** /**
* Groping by exact host. The results will be an array of nsINavHistoryResults * Groping by exact host. The results will be an array of nsINavHistoryResults
* with type = RESULT_TYPE_HOST, one for each unique host (for example, * with type = RESULT_TYPE_HOST, one for each unique host (for example,
@ -709,12 +800,9 @@ interface nsINavHistoryQueryOptions : nsISupports
/** /**
* The grouping mode to be used for this query. * The grouping mode to be used for this query.
* Grouping mode is an array of GROUP_BY_* values that specifies the structure * Grouping mode is an array of GROUP_BY_* values that specifies the
* of the tree you want. For example, an array consisting of * structure of the tree you want. If you don't want grouping, you can
* [GROUP_BY_DAY, GROUP_BY_DOMAIN] will give you a tree whose first level is * specify an empty array.
* a list of days, and whose second level is a list of domains, and whose
* third level is a list of pages in those domains. If you don't want a tree,
* you can specify an empty array.
*/ */
void getGroupingMode(out PRUint32 groupCount, void getGroupingMode(out PRUint32 groupCount,
[retval,array,size_is(groupCount)] out PRUint32 groupingMode); [retval,array,size_is(groupCount)] out PRUint32 groupingMode);

View File

@ -0,0 +1,141 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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.
*
* 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):
* Annie Sullivan <annie.sullivan@gmail.com> (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 ***** */
#include "nsISupports.idl"
interface nsIURI;
interface nsINavHistoryContainerResultNode;
interface nsINavHistoryQueryOptions;
/**
* The Remote Container interface provides a base class for services that want
* to provide containers for bookmarks. Some examples of possible services are
* the livemarks service and the filesystem.
*
* There are two primary modes of operation: container services might create
* actual bookmarks, or they might fill containers on the fly as needed. The
* livemarks service, for example, queries the feed from time to time and
* creates actual bookmarks in the folder corresponding to the feed. This way
* the items are persistent even if the user is offline, and can be searched.
* In this mode, the service just looks for moves and deletes to update the
* corresponding bookkeeping information. It can use the normal population
* method provided by the bookmark service and need not do any work for the
* onContainerOpen message.
*
* Such a bookmark-based container service might listen for onContainerOpening
* notifications messages to see whether
*
* Persistent bookmarks are not appropriate for more short-lived data, such as
* the filesystem interface. In this case, the service can fill result nodes
* directly into the container when it is being opened. It can use the property
* bag on every result node to store data associated with each item, such as
* full path on disk. It would create additional containers for each folder,
* resgistered to its service. These dynamic containers are not bookmark
* folders in contrast to the initial item.
*/
[scriptable, uuid(45bf2020-9683-498c-9638-f08130c4151d)]
interface nsIRemoteContainer : nsISupports
{
/**
* Called when the given container is about to be populated so that the
* service can populate the container if necessary.
*
* @param container The container node for the container being opened.
* If the node type is a bookmarks container, you can
* QI it to nsINavHistoryFolderResultNode and access the
* folder ID, etc. Note that all result nodes implement
* a property bag if you need to store state.
* @param options The options used to generate this query. Containers
* should follow these when possible, for example,
* whether to expand queries, etc. Implementations should
* use this when possible if adding query and folder nodes
* to the container. DO NOT MODIFY THIS VALUE.
*/
void onContainerOpening(in nsINavHistoryContainerResultNode container,
in nsINavHistoryQueryOptions options);
/**
* Called when the given container has just been hidden so that the service
* can do any necessary cleanup. This is NOT guaranteed to get called. In
* particular, if the query just goes away (like the user switched views on
* the places page) you will not get this call. This only happens when the
* container itself goes from the open state to the closed state. A serviced
* with large numbers of dynamically populated items might use this to do
* some cleanup so those items don't hang around
*
* @param container The container node of the container being closed. The
* service need not worry about removing any created nodes,
* they will be automatically removed when this call
* completes.
*/
void onContainerClosed(in nsINavHistoryContainerResultNode container);
/**
* Called when the given container is about to be deleted, so
* that the service can do any necessary cleanup.
* Called BEFORE the container is deleted, so that the service
* can still reference it.
* @param container The folderId of the bookmark folder
* representing the container to be deleted.
*/
void onContainerRemoving(in PRInt64 container);
/**
* Called when the given container has just been moved, in case
* the service needs to do any bookkeeping.
* Called AFTER the container has been moved, so the service can
* get the new URI.
* @param container The folderId of the bookmark folder
* representing the container to be moved.
* @param newFolder The folderId of the new parent folder
* for the container.
* @param newIndex The index the container will be inserted at,
* or -1 for append.
*/
void onContainerMoved(in PRInt64 container,
in PRInt64 newFolder, in PRInt32 newIndex);
/**
* Returns true if containers of this type should not expose UI for
* inserting, moving, or deleting children.
*/
readonly attribute boolean childrenReadOnly;
};

View File

@ -39,6 +39,7 @@
#include "nsLivemarkService.h" #include "nsLivemarkService.h"
#include "nsIServiceManager.h" #include "nsIServiceManager.h"
#include "nsNavBookmarks.h" #include "nsNavBookmarks.h"
#include "nsNavHistoryResult.h"
#include "nsIAnnotationService.h" #include "nsIAnnotationService.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "rdf.h" #include "rdf.h"
@ -95,7 +96,7 @@ nsLivemarkService::~nsLivemarkService()
mTimer = nsnull; mTimer = nsnull;
} }
// Cancel any pending loads // Cancel any pending loads
for (PRInt32 i = 0; i < mLivemarks.Length(); ++i) { for (PRUint32 i = 0; i < mLivemarks.Length(); ++i) {
LivemarkInfo *li = mLivemarks[i]; LivemarkInfo *li = mLivemarks[i];
if (li->loadGroup) { if (li->loadGroup) {
li->loadGroup->Cancel(NS_BINDING_ABORTED); li->loadGroup->Cancel(NS_BINDING_ABORTED);
@ -105,7 +106,7 @@ nsLivemarkService::~nsLivemarkService()
NS_IMPL_ISUPPORTS2(nsLivemarkService, NS_IMPL_ISUPPORTS2(nsLivemarkService,
nsILivemarkService, nsILivemarkService,
nsIBookmarksContainer) nsIRemoteContainer)
nsresult nsresult
nsLivemarkService::Init() nsLivemarkService::Init()
@ -186,7 +187,7 @@ nsLivemarkService::Init()
&pLivemarks); &pLivemarks);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
for (PRInt32 i = 0; i < numLivemarks; ++i) { for (PRUint32 i = 0; i < numLivemarks; ++i) {
// Get the feed URI from the annotation. // Get the feed URI from the annotation.
nsAutoString feedURIString; nsAutoString feedURIString;
@ -198,26 +199,24 @@ nsLivemarkService::Init()
rv = NS_NewURI(getter_AddRefs(feedURI), NS_ConvertUTF16toUTF8(feedURIString)); rv = NS_NewURI(getter_AddRefs(feedURI), NS_ConvertUTF16toUTF8(feedURIString));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Use QueryStringToQueries() to get the folderId from the place:uri. // Use QueryStringToQueryArray() to get the folderId from the place:uri.
// (It ends up in folders[0]) // (It ends up in folders[0] since we know that this place: uri was
// generated by the bookmark service to uniquely identify the folder)
nsCAutoString folderQueryString; nsCAutoString folderQueryString;
rv = pLivemarks[i]->GetSpec(folderQueryString); rv = pLivemarks[i]->GetSpec(folderQueryString);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
PRUint32 resultCount;
nsINavHistoryQuery** queries = nsnull; nsCOMArray<nsNavHistoryQuery> queries;
nsCOMPtr<nsINavHistoryQueryOptions> options; nsCOMPtr<nsNavHistoryQueryOptions> options;
rv = History()->QueryStringToQueries(folderQueryString, rv = History()->QueryStringToQueryArray(folderQueryString, &queries,
&queries, getter_AddRefs(options));
&resultCount,
getter_AddRefs(options));
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 folderCount;
PRInt64 *folders = nsnull;
rv = queries[0]->GetFolders(&folderCount, &folders);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (queries.Count() != 1 || queries[0]->Folders().Length() != 1)
continue; // invalid folder URI (should identify exactly one folder)
// Create the livemark and add it to the list. // Create the livemark and add it to the list.
LivemarkInfo *li = new LivemarkInfo(folders[0], pLivemarks[i], feedURI); LivemarkInfo *li = new LivemarkInfo(queries[0]->Folders()[0],
pLivemarks[i], feedURI);
NS_ENSURE_TRUE(li, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(li, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE(mLivemarks.AppendElement(li), NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(mLivemarks.AppendElement(li), NS_ERROR_OUT_OF_MEMORY);
} }
@ -283,17 +282,18 @@ nsLivemarkService::CreateLivemark(PRInt64 aFolder,
NS_IMETHODIMP NS_IMETHODIMP
nsLivemarkService::OnContainerOpening(PRInt64 aContainer, PRBool * _result) nsLivemarkService::OnContainerOpening(
nsINavHistoryContainerResultNode* container,
nsINavHistoryQueryOptions* options)
{ {
// Nothing to do here since the containers are filled in // Nothing to do here since the containers are filled in
// as the livemarks are loaded through FireTimer(). // as the livemarks are loaded through FireTimer().
*_result = PR_FALSE;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsLivemarkService::OnContainerClosed(PRInt64 aContainer) nsLivemarkService::OnContainerClosed(nsINavHistoryContainerResultNode* container)
{ {
// Nothing to clean up // Nothing to clean up
return NS_OK; return NS_OK;
@ -308,7 +308,7 @@ nsLivemarkService::OnContainerRemoving(PRInt64 aContainer)
// Find the livemark id in the list of livemarks. // Find the livemark id in the list of livemarks.
PRInt32 lmIndex = -1; PRInt32 lmIndex = -1;
PRInt32 i; PRInt32 i;
for (i = 0; i < mLivemarks.Length(); i++) { for (i = 0; i < PRInt32(mLivemarks.Length()); i++) {
if (mLivemarks[i]->folderId == aContainer) { if (mLivemarks[i]->folderId == aContainer) {
lmIndex = i; lmIndex = i;
break; break;
@ -332,7 +332,7 @@ nsLivemarkService::OnContainerRemoving(PRInt64 aContainer)
// If not, remove the annotations for the feed. // If not, remove the annotations for the feed.
PRBool stillInUse = PR_FALSE; PRBool stillInUse = PR_FALSE;
PRBool urisEqual = PR_FALSE; PRBool urisEqual = PR_FALSE;
for (i = 0; i < mLivemarks.Length(); i++) { for (i = 0; i < PRInt32(mLivemarks.Length()); i++) {
if (i != lmIndex && if (i != lmIndex &&
(NS_OK == mLivemarks[i]->feedURI->Equals(removedItem->feedURI, &urisEqual)) && (NS_OK == mLivemarks[i]->feedURI->Equals(removedItem->feedURI, &urisEqual)) &&
urisEqual) { urisEqual) {
@ -369,7 +369,7 @@ nsLivemarkService::OnContainerMoved(PRInt64 aContainer,
// Find the livemark in the list. // Find the livemark in the list.
PRInt32 index = -1; PRInt32 index = -1;
for (PRInt32 i = 0; i < mLivemarks.Length(); i++) { for (PRInt32 i = 0; i < PRInt32(mLivemarks.Length()); i++) {
if (mLivemarks[i]->folderId == aContainer) { if (mLivemarks[i]->folderId == aContainer) {
index = i; index = i;
break; break;
@ -436,7 +436,7 @@ nsLivemarkService::FireTimer(nsITimer* aTimer, void* aClosure)
if (!lmks) return; if (!lmks) return;
// Go through all of the livemarks, and check if each needs to be updated. // Go through all of the livemarks, and check if each needs to be updated.
for (PRInt32 i = 0; i < lmks->mLivemarks.Length(); i++) { for (PRUint32 i = 0; i < lmks->mLivemarks.Length(); i++) {
lmks->UpdateLivemarkChildren(i); lmks->UpdateLivemarkChildren(i);
} }
} }

View File

@ -52,7 +52,7 @@ class nsLivemarkService : public nsILivemarkService
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_NSIBOOKMARKSCONTAINER NS_DECL_NSIREMOTECONTAINER
NS_DECL_NSILIVEMARKSERVICE NS_DECL_NSILIVEMARKSERVICE
nsLivemarkService(); nsLivemarkService();

View File

@ -43,7 +43,7 @@
#include "nsIServiceManager.h" #include "nsIServiceManager.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsIAnnotationService.h" #include "nsIAnnotationService.h"
#include "nsIBookmarksContainer.h" #include "nsIRemoteContainer.h"
const PRInt32 nsNavBookmarks::kFindBookmarksIndex_ItemChild = 0; const PRInt32 nsNavBookmarks::kFindBookmarksIndex_ItemChild = 0;
const PRInt32 nsNavBookmarks::kFindBookmarksIndex_FolderChild = 1; const PRInt32 nsNavBookmarks::kFindBookmarksIndex_FolderChild = 1;
@ -719,12 +719,12 @@ nsNavBookmarks::RemoveFolder(PRInt64 aFolder)
{ {
// If this is a container bookmark, try to notify its service. // If this is a container bookmark, try to notify its service.
nsresult rv; nsresult rv;
nsAutoString folderType; nsCAutoString folderType;
rv = GetFolderType(aFolder, folderType); rv = GetFolderType(aFolder, folderType);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (folderType.Length() > 0) { if (folderType.Length() > 0) {
// There is a type associated with this folder; it's a livemark. // There is a type associated with this folder; it's a livemark.
nsCOMPtr<nsIBookmarksContainer> bmcServ = do_GetService(NS_ConvertUTF16toUTF8(folderType).get()); nsCOMPtr<nsIRemoteContainer> bmcServ = do_GetService(folderType.get());
if (bmcServ) { if (bmcServ) {
rv = bmcServ->OnContainerRemoving(aFolder); rv = bmcServ->OnContainerRemoving(aFolder);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
@ -796,16 +796,16 @@ nsNavBookmarks::RemoveFolderChildren(PRInt64 aFolder)
nsTArray<PRInt64> folderChildren; nsTArray<PRInt64> folderChildren;
{ {
mozStorageStatementScoper scope(mDBGetFolderChildren); mozStorageStatementScoper scope(mDBGetFolderChildren);
rv = mDBGetChildren->BindInt64Parameter(0, aFolder); rv = mDBGetFolderChildren->BindInt64Parameter(0, aFolder);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
rv = mDBGetChildren->BindInt32Parameter(1, 0); rv = mDBGetFolderChildren->BindInt32Parameter(1, 0);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
rv = mDBGetChildren->BindInt32Parameter(2, PR_INT32_MAX); rv = mDBGetFolderChildren->BindInt32Parameter(2, PR_INT32_MAX);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
PRBool more; PRBool more;
while (NS_SUCCEEDED(rv = mDBGetChildren->ExecuteStep(&more)) && more) { while (NS_SUCCEEDED(rv = mDBGetFolderChildren->ExecuteStep(&more)) && more) {
folderChildren.AppendElement(mDBGetChildren->AsInt64(kGetChildrenIndex_FolderChild)); folderChildren.AppendElement(mDBGetFolderChildren->AsInt64(kGetChildrenIndex_FolderChild));
} }
} }
@ -944,10 +944,23 @@ nsNavBookmarks::MoveFolder(PRInt64 aFolder, PRInt64 aNewParent, PRInt32 aIndex)
rv = transaction.Commit(); rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// notify bookmark observers
ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver, ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver,
OnFolderMoved(aFolder, parent, oldIndex, OnFolderMoved(aFolder, parent, oldIndex,
aNewParent, newIndex)) aNewParent, newIndex))
// notify remote container provider if there is one
nsCAutoString type;
rv = GetFolderType(aFolder, type);
NS_ENSURE_SUCCESS(rv, rv);
if (! type.IsEmpty()) {
nsCOMPtr<nsIRemoteContainer> container =
do_GetService(type.get(), &rv);
if (NS_SUCCEEDED(rv)) {
rv = container->OnContainerMoved(aFolder, aNewParent, newIndex);
NS_ENSURE_SUCCESS(rv, rv);
}
}
return NS_OK; return NS_OK;
} }
@ -1051,7 +1064,7 @@ nsNavBookmarks::GetFolderTitle(PRInt64 aFolder, nsAString &aTitle)
nsresult nsresult
nsNavBookmarks::GetFolderType(PRInt64 aFolder, nsAString &aType) nsNavBookmarks::GetFolderType(PRInt64 aFolder, nsACString &aType)
{ {
mozStorageStatementScoper scope(mDBGetFolderInfo); mozStorageStatementScoper scope(mDBGetFolderInfo);
nsresult rv = mDBGetFolderInfo->BindInt64Parameter(0, aFolder); nsresult rv = mDBGetFolderInfo->BindInt64Parameter(0, aFolder);
@ -1065,7 +1078,7 @@ nsNavBookmarks::GetFolderType(PRInt64 aFolder, nsAString &aType)
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
} }
return mDBGetFolderInfo->GetString(kGetFolderInfoIndex_Type, aType); return mDBGetFolderInfo->GetUTF8String(kGetFolderInfoIndex_Type, aType);
} }
nsresult nsresult
@ -1090,19 +1103,10 @@ nsNavBookmarks::ResultNodeForFolder(PRInt64 aID,
nsCAutoString title; nsCAutoString title;
rv = mDBGetFolderInfo->GetUTF8String(kGetFolderInfoIndex_Title, title); rv = mDBGetFolderInfo->GetUTF8String(kGetFolderInfoIndex_Title, title);
if (folderType.IsEmpty()) { *aNode = new nsNavHistoryFolderResultNode(title, aOptions, aID, folderType);
*aNode = new nsNavHistoryFolderResultNode(title, 0, 0, aOptions, aID); if (! *aNode)
if (! *aNode) return NS_ERROR_OUT_OF_MEMORY;
return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*aNode);
NS_ADDREF(*aNode);
} else {
// a container API thing
// FIXME(brettw)
//NS_NOTREACHED("FIXME: Not implemented");
*aNode = nsnull;
return NS_ERROR_NOT_IMPLEMENTED;
}
return NS_OK; return NS_OK;
} }
@ -1118,7 +1122,7 @@ nsNavBookmarks::GetFolderURI(PRInt64 aFolder, nsIURI **aURI)
// correct string here. // correct string here.
// //
// If you change this, change IsSimpleFolderURI which detects this string. // If you change this, change IsSimpleFolderURI which detects this string.
nsCAutoString spec("place:folders="); nsCAutoString spec("place:folder=");
spec.AppendInt(aFolder); spec.AppendInt(aFolder);
spec.AppendLiteral("&group=3"); // GROUP_BY_FOLDER spec.AppendLiteral("&group=3"); // GROUP_BY_FOLDER
return NS_NewURI(aURI, spec); return NS_NewURI(aURI, spec);
@ -1127,15 +1131,15 @@ nsNavBookmarks::GetFolderURI(PRInt64 aFolder, nsIURI **aURI)
NS_IMETHODIMP NS_IMETHODIMP
nsNavBookmarks::GetFolderReadonly(PRInt64 aFolder, PRBool *aResult) nsNavBookmarks::GetFolderReadonly(PRInt64 aFolder, PRBool *aResult)
{ {
// Ask the folder's nsIBookmarksContainer for the readonly property. // Ask the folder's nsIRemoteContainer for the readonly property.
*aResult = PR_FALSE; *aResult = PR_FALSE;
nsAutoString type; nsCAutoString type;
nsresult rv = GetFolderType(aFolder, type); nsresult rv = GetFolderType(aFolder, type);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (!type.IsEmpty()) { if (!type.IsEmpty()) {
nsCOMPtr<nsIBookmarksContainer> container = nsCOMPtr<nsIRemoteContainer> container =
do_GetService(NS_ConvertUTF16toUTF8(type).get(), &rv); do_GetService(type.get(), &rv);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
rv = container->GetChildrenReadOnly(aResult); rv = container->GetChildrenReadOnly(aResult);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);

View File

@ -96,7 +96,7 @@ private:
PRInt32 aStartIndex, PRInt32 aEndIndex, PRInt32 aStartIndex, PRInt32 aEndIndex,
PRInt32 aDelta); PRInt32 aDelta);
PRInt32 FolderCount(PRInt64 aFolder); PRInt32 FolderCount(PRInt64 aFolder);
nsresult GetFolderType(PRInt64 aFolder, nsAString &aType); nsresult GetFolderType(PRInt64 aFolder, nsACString &aType);
// remove me when there is better query initialization // remove me when there is better query initialization
nsNavHistory* History() { return nsNavHistory::GetHistoryService(); } nsNavHistory* History() { return nsNavHistory::GetHistoryService(); }

View File

@ -120,8 +120,8 @@ static PRInt32 GetTLDType(const nsCString& aHostTail);
static void GetUnreversedHostname(const nsString& aBackward, static void GetUnreversedHostname(const nsString& aBackward,
nsAString& aForward); nsAString& aForward);
static PRBool IsNumericHostName(const nsCString& aHost); static PRBool IsNumericHostName(const nsCString& aHost);
static PRInt64 GetSimpleBookmarksQueryFolder(nsINavHistoryQuery** aQueries, static PRInt64 GetSimpleBookmarksQueryFolder(
PRUint32 aQueryCount); const nsCOMArray<nsNavHistoryQuery>& aQueries);
static void ParseSearchQuery(const nsString& aQuery, nsStringArray* aTerms); static void ParseSearchQuery(const nsString& aQuery, nsStringArray* aTerms);
inline void ReverseString(const nsString& aInput, nsAString& aReversed) inline void ReverseString(const nsString& aInput, nsAString& aReversed)
@ -1192,16 +1192,16 @@ nsNavHistory::NormalizeTime(PRUint32 aRelative, PRTime aOffset)
// change operations as simple instead of complex. // change operations as simple instead of complex.
PRUint32 PRUint32
nsNavHistory::GetUpdateRequirements(nsCOMArray<nsINavHistoryQuery>* aQueries, nsNavHistory::GetUpdateRequirements(const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions* aOptions, nsNavHistoryQueryOptions* aOptions,
PRBool* aHasSearchTerms) PRBool* aHasSearchTerms)
{ {
NS_ASSERTION(aQueries->Count() > 0, "Must have at least one query"); NS_ASSERTION(aQueries.Count() > 0, "Must have at least one query");
// first check if there are search terms // first check if there are search terms
*aHasSearchTerms = PR_FALSE; *aHasSearchTerms = PR_FALSE;
for (PRInt32 i = 0; i < aQueries->Count(); i ++) { for (PRInt32 i = 0; i < aQueries.Count(); i ++) {
(*aQueries)[i]->GetHasSearchTerms(aHasSearchTerms); aQueries[i]->GetHasSearchTerms(aHasSearchTerms);
if (*aHasSearchTerms) if (*aHasSearchTerms)
break; break;
} }
@ -1213,13 +1213,8 @@ nsNavHistory::GetUpdateRequirements(nsCOMArray<nsINavHistoryQuery>* aQueries,
return QUERYUPDATE_COMPLEX; return QUERYUPDATE_COMPLEX;
PRBool nonTimeBasedItems = PR_FALSE; PRBool nonTimeBasedItems = PR_FALSE;
for (PRInt32 i = 0; i < aQueries->Count(); i ++) { for (PRInt32 i = 0; i < aQueries.Count(); i ++) {
nsresult rv; nsNavHistoryQuery* query = aQueries[i];
nsCOMPtr<nsNavHistoryQuery> query = do_QueryInterface((*aQueries)[i], &rv);
if (NS_FAILED(rv)) {
NS_NOTREACHED("Query is not one of our query objects!");
return QUERYUPDATE_COMPLEX;
}
if (query->Folders().Length() > 0 || query->OnlyBookmarked()) { if (query->Folders().Length() > 0 || query->OnlyBookmarked()) {
return QUERYUPDATE_COMPLEX_WITH_BOOKMARKS; return QUERYUPDATE_COMPLEX_WITH_BOOKMARKS;
@ -1232,7 +1227,7 @@ nsNavHistory::GetUpdateRequirements(nsCOMArray<nsINavHistoryQuery>* aQueries,
nonTimeBasedItems = PR_TRUE; nonTimeBasedItems = PR_TRUE;
} }
if (aQueries->Count() == 1 && ! nonTimeBasedItems) if (aQueries.Count() == 1 && ! nonTimeBasedItems)
return QUERYUPDATE_TIME; return QUERYUPDATE_TIME;
return QUERYUPDATE_SIMPLE; return QUERYUPDATE_SIMPLE;
} }
@ -1253,21 +1248,16 @@ nsNavHistory::GetUpdateRequirements(nsCOMArray<nsINavHistoryQuery>* aQueries,
// Returns true if node matches the query, false if not. // Returns true if node matches the query, false if not.
PRBool PRBool
nsNavHistory::EvaluateQueryForNode(nsCOMArray<nsINavHistoryQuery>* aQueries, nsNavHistory::EvaluateQueryForNode(const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions* aOptions, nsNavHistoryQueryOptions* aOptions,
nsNavHistoryURIResultNode* aNode) nsNavHistoryURIResultNode* aNode)
{ {
// lazily created from the node's string when we need to match URIs // lazily created from the node's string when we need to match URIs
nsCOMPtr<nsIURI> nodeUri; nsCOMPtr<nsIURI> nodeUri;
nsresult rv; for (PRInt32 i = 0; i < aQueries.Count(); i ++) {
for (PRInt32 i = 0; i < aQueries->Count(); i ++) {
PRBool hasIt; PRBool hasIt;
nsCOMPtr<nsNavHistoryQuery> query = do_QueryInterface((*aQueries)[i], &rv); nsCOMPtr<nsNavHistoryQuery> query = aQueries[i];
if (NS_FAILED(rv)) {
NS_NOTREACHED("Query is not one of ours.");
return PR_FALSE;
}
// --- begin time --- // --- begin time ---
query->GetHasBeginTime(&hasIt); query->GetHasBeginTime(&hasIt);
@ -1294,7 +1284,7 @@ nsNavHistory::EvaluateQueryForNode(nsCOMArray<nsINavHistoryQuery>* aQueries,
nsCOMArray<nsNavHistoryResultNode> inputSet; nsCOMArray<nsNavHistoryResultNode> inputSet;
inputSet.AppendObject(aNode); inputSet.AppendObject(aNode);
nsCOMArray<nsNavHistoryResultNode> filteredSet; nsCOMArray<nsNavHistoryResultNode> filteredSet;
rv = FilterResultSet(inputSet, &filteredSet, query->SearchTerms()); nsresult rv = FilterResultSet(inputSet, &filteredSet, query->SearchTerms());
if (NS_FAILED(rv)) if (NS_FAILED(rv))
continue; continue;
if (! filteredSet.Count()) if (! filteredSet.Count())
@ -1336,7 +1326,7 @@ nsNavHistory::EvaluateQueryForNode(nsCOMArray<nsINavHistoryQuery>* aQueries,
if (! query->UriIsPrefix()) { if (! query->UriIsPrefix()) {
// easy case: the URI is an exact match // easy case: the URI is an exact match
PRBool equals; PRBool equals;
rv = query->Uri()->Equals(nodeUri, &equals); nsresult rv = query->Uri()->Equals(nodeUri, &equals);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (! equals) if (! equals)
continue; continue;
@ -1640,21 +1630,33 @@ nsNavHistory::ExecuteQueries(nsINavHistoryQuery** aQueries, PRUint32 aQueryCount
nsCOMPtr<nsNavHistoryQueryOptions> options = do_QueryInterface(aOptions); nsCOMPtr<nsNavHistoryQueryOptions> options = do_QueryInterface(aOptions);
NS_ENSURE_TRUE(options, NS_ERROR_INVALID_ARG); NS_ENSURE_TRUE(options, NS_ERROR_INVALID_ARG);
// concrete queries array
nsCOMArray<nsNavHistoryQuery> queries;
for (PRUint32 i = 0; i < aQueryCount; i ++) {
nsCOMPtr<nsNavHistoryQuery> query = do_QueryInterface(aQueries[i], &rv);
NS_ENSURE_SUCCESS(rv, rv);
queries.AppendObject(query);
}
// root node // root node
nsRefPtr<nsNavHistoryContainerResultNode> rootNode; nsRefPtr<nsNavHistoryContainerResultNode> rootNode;
PRInt64 folderId = GetSimpleBookmarksQueryFolder(aQueries, aQueryCount); PRInt64 folderId = GetSimpleBookmarksQueryFolder(queries);
if (folderId) { if (folderId) {
// In the simple case where we're just querying children of a single bookmark // In the simple case where we're just querying children of a single bookmark
// folder, we can more efficiently generate results. // folder, we can more efficiently generate results.
rootNode = new nsNavHistoryFolderResultNode(EmptyCString(), 0, 0, nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
options, folderId); NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsNavHistoryResultNode> tempRootNode;
rv = bookmarks->ResultNodeForFolder(folderId, options,
getter_AddRefs(tempRootNode));
NS_ENSURE_SUCCESS(rv, rv);
rootNode = tempRootNode->GetAsContainer();
} else { } else {
// complex query // complex query
rootNode = new nsNavHistoryQueryResultNode(options, rootNode = new nsNavHistoryQueryResultNode(EmptyCString(), EmptyCString(),
EmptyCString(), 0, 0, EmptyCString(), queries, options);
aQueries, aQueryCount, options); NS_ENSURE_TRUE(rootNode, NS_ERROR_OUT_OF_MEMORY);
} }
NS_ENSURE_TRUE(rootNode, NS_ERROR_OUT_OF_MEMORY);
// result object // result object
nsRefPtr<nsNavHistoryResult> result; nsRefPtr<nsNavHistoryResult> result;
@ -1688,7 +1690,7 @@ nsNavHistory::ExecuteQueries(nsINavHistoryQuery** aQueries, PRUint32 aQueryCount
// it ANDed with the all the rest of the queries. // it ANDed with the all the rest of the queries.
nsresult nsresult
nsNavHistory::GetQueryResults(const nsCOMArray<nsINavHistoryQuery>& aQueries, nsNavHistory::GetQueryResults(const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions *aOptions, nsNavHistoryQueryOptions *aOptions,
nsCOMArray<nsNavHistoryResultNode>* aResults) nsCOMArray<nsNavHistoryResultNode>* aResults)
{ {
@ -1843,15 +1845,13 @@ nsNavHistory::GetQueryResults(const nsCOMArray<nsINavHistoryQuery>& aQueries,
for (i = 0; i < aQueries.Count(); i ++) { for (i = 0; i < aQueries.Count(); i ++) {
PRInt32 clauseParameters = 0; PRInt32 clauseParameters = 0;
rv = BindQueryClauseParameters(statement, numParameters, rv = BindQueryClauseParameters(statement, numParameters,
NS_CONST_CAST(nsINavHistoryQuery*, aQueries[i]), aQueries[i], &clauseParameters);
&clauseParameters);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
numParameters += clauseParameters; numParameters += clauseParameters;
} }
PRBool hasSearchTerms; PRBool hasSearchTerms;
rv = NS_CONST_CAST(nsINavHistoryQuery*, rv = aQueries[0]->GetHasSearchTerms(&hasSearchTerms);
aQueries[0])->GetHasSearchTerms(&hasSearchTerms);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
PRUint32 groupCount; PRUint32 groupCount;
@ -1868,37 +1868,26 @@ nsNavHistory::GetQueryResults(const nsCOMArray<nsINavHistoryQuery>& aQueries,
rv = ResultsAsList(statement, aOptions, &toplevel); rv = ResultsAsList(statement, aOptions, &toplevel);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
/* FIXME(brettw)
if (hasSearchTerms) { if (hasSearchTerms) {
// keyword search // keyword search
nsAutoString searchTerms;
NS_CONST_CAST(nsINavHistoryQuery*, aQueries[0])
->GetSearchTerms(searchTerms);
if (groupCount == 0) { if (groupCount == 0) {
FilterResultSet(toplevel, result->GetTopLevel(), searchTerms); // keyword search with no grouping: can filter directly into the result
FilterResultSet(toplevel, aResults, aQueries[0]->SearchTerms());
} else { } else {
// keyword searching with grouping: need intermediate filtered results
nsCOMArray<nsNavHistoryResultNode> filteredResults; nsCOMArray<nsNavHistoryResultNode> filteredResults;
FilterResultSet(toplevel, &filteredResults, searchTerms); FilterResultSet(toplevel, &filteredResults, aQueries[0]->SearchTerms());
rv = RecursiveGroup(filteredResults, groupings, groupCount, rv = RecursiveGroup(filteredResults, groupings, groupCount,
result->GetTopLevel()); aResults);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
} else */{ } else {
// group unfiltered results // group unfiltered results
rv = RecursiveGroup(toplevel, groupings, groupCount, aResults); rv = RecursiveGroup(toplevel, groupings, groupCount, aResults);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
} }
/*
nsNavHistoryContainerResultNode::SortComparator comparator =
nsNavHistoryContainerResultNode::GetSortingComparator(
sortingMode);
if (sortingMode)
nsNavHistoryContainerResultNode::RecursiveSortArray(
aResults, mCollation, comparator);
*/
// automatically expand things that were expanded before // automatically expand things that were expanded before
// FIXME(brettw) // FIXME(brettw)
//if (gExpandedItems.Count() > 0) //if (gExpandedItems.Count() > 0)
@ -2526,7 +2515,7 @@ nsNavHistory::Observe(nsISupports *aSubject, const char *aTopic,
// no way for those to fail. // no way for those to fail.
nsresult nsresult
nsNavHistory::QueryToSelectClause(nsINavHistoryQuery* aQuery, // const nsNavHistory::QueryToSelectClause(nsNavHistoryQuery* aQuery, // const
PRInt32 aStartParameter, PRInt32 aStartParameter,
nsCString* aClause, nsCString* aClause,
PRInt32* aParamCount, PRInt32* aParamCount,
@ -2559,7 +2548,7 @@ nsNavHistory::QueryToSelectClause(nsINavHistoryQuery* aQuery, // const
// search terms FIXME // search terms FIXME
// only bookmarked // only bookmarked
if (NS_SUCCEEDED(aQuery->GetOnlyBookmarked(&hasIt)) && hasIt) { if (aQuery->OnlyBookmarked()) {
if (! aClause->IsEmpty()) if (! aClause->IsEmpty())
*aClause += NS_LITERAL_CSTRING(" AND "); *aClause += NS_LITERAL_CSTRING(" AND ");
@ -2602,15 +2591,12 @@ nsNavHistory::QueryToSelectClause(nsINavHistoryQuery* aQuery, // const
if (! aClause->IsEmpty()) if (! aClause->IsEmpty())
*aClause += NS_LITERAL_CSTRING(" AND "); *aClause += NS_LITERAL_CSTRING(" AND ");
PRBool uriIsPrefix;
aQuery->GetUriIsPrefix(&uriIsPrefix);
nsCAutoString paramString; nsCAutoString paramString;
parameterString(aStartParameter + *aParamCount, paramString); parameterString(aStartParameter + *aParamCount, paramString);
(*aParamCount) ++; (*aParamCount) ++;
nsCAutoString match; nsCAutoString match;
if (uriIsPrefix) { if (aQuery->UriIsPrefix()) {
// Prefix: want something of the form SUBSTR(h.url, 0, length(?1)) = ?1 // Prefix: want something of the form SUBSTR(h.url, 0, length(?1)) = ?1
*aClause += NS_LITERAL_CSTRING("SUBSTR(h.url, 0, LENGTH(") + *aClause += NS_LITERAL_CSTRING("SUBSTR(h.url, 0, LENGTH(") +
paramString + NS_LITERAL_CSTRING(")) = ") + paramString; paramString + NS_LITERAL_CSTRING(")) = ") + paramString;
@ -2625,14 +2611,11 @@ nsNavHistory::QueryToSelectClause(nsINavHistoryQuery* aQuery, // const
if (! aClause->IsEmpty()) if (! aClause->IsEmpty())
*aClause += NS_LITERAL_CSTRING(" AND "); *aClause += NS_LITERAL_CSTRING(" AND ");
if (hasIt) { if (hasIt) {
PRBool notAnnotation;
aQuery->GetAnnotationIsNot(&notAnnotation);
nsCAutoString paramString; nsCAutoString paramString;
parameterString(aStartParameter + *aParamCount, paramString); parameterString(aStartParameter + *aParamCount, paramString);
(*aParamCount) ++; (*aParamCount) ++;
if (notAnnotation) if (aQuery->AnnotationIsNot())
aClause->AppendLiteral("NOT "); aClause->AppendLiteral("NOT ");
aClause->AppendLiteral("EXISTS (SELECT anno_id FROM moz_anno anno WHERE anno.page = h.id AND anno.name = "); aClause->AppendLiteral("EXISTS (SELECT anno_id FROM moz_anno anno WHERE anno.page = h.id AND anno.name = ");
aClause->Append(paramString); aClause->Append(paramString);
@ -2655,7 +2638,7 @@ nsNavHistory::QueryToSelectClause(nsINavHistoryQuery* aQuery, // const
nsresult nsresult
nsNavHistory::BindQueryClauseParameters(mozIStorageStatement* statement, nsNavHistory::BindQueryClauseParameters(mozIStorageStatement* statement,
PRInt32 aStartParameter, PRInt32 aStartParameter,
nsINavHistoryQuery* aQuery, // const nsNavHistoryQuery* aQuery, // const
PRInt32* aParamCount) PRInt32* aParamCount)
{ {
nsresult rv; nsresult rv;
@ -2665,11 +2648,8 @@ nsNavHistory::BindQueryClauseParameters(mozIStorageStatement* statement,
// begin time // begin time
if (NS_SUCCEEDED(aQuery->GetHasBeginTime(&hasIt)) && hasIt) { if (NS_SUCCEEDED(aQuery->GetHasBeginTime(&hasIt)) && hasIt) {
PRTime time; PRTime time = NormalizeTime(aQuery->BeginTimeReference(),
aQuery->GetBeginTime(&time); aQuery->BeginTime());
PRUint32 timeReference;
aQuery->GetBeginTimeReference(&timeReference);
time = NormalizeTime(timeReference, time);
rv = statement->BindInt64Parameter(aStartParameter + *aParamCount, time); rv = statement->BindInt64Parameter(aStartParameter + *aParamCount, time);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
(*aParamCount) ++; (*aParamCount) ++;
@ -2677,11 +2657,8 @@ nsNavHistory::BindQueryClauseParameters(mozIStorageStatement* statement,
// end time // end time
if (NS_SUCCEEDED(aQuery->GetHasEndTime(&hasIt)) && hasIt) { if (NS_SUCCEEDED(aQuery->GetHasEndTime(&hasIt)) && hasIt) {
PRTime time; PRTime time = NormalizeTime(aQuery->EndTimeReference(),
aQuery->GetEndTime(&time); aQuery->EndTime());
PRUint32 timeReference;
aQuery->GetEndTimeReference(&timeReference);
time = NormalizeTime(timeReference, time);
rv = statement->BindInt64Parameter(aStartParameter + *aParamCount, time); rv = statement->BindInt64Parameter(aStartParameter + *aParamCount, time);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
(*aParamCount) ++; (*aParamCount) ++;
@ -2693,14 +2670,10 @@ nsNavHistory::BindQueryClauseParameters(mozIStorageStatement* statement,
// domain (see GetReversedHostname for more info on reversed host names) // domain (see GetReversedHostname for more info on reversed host names)
if (NS_SUCCEEDED(aQuery->GetHasDomain(&hasIt)) && hasIt) { if (NS_SUCCEEDED(aQuery->GetHasDomain(&hasIt)) && hasIt) {
nsCAutoString domain;
aQuery->GetDomain(domain);
nsString revDomain; nsString revDomain;
GetReversedHostname(NS_ConvertUTF8toUTF16(domain), revDomain); GetReversedHostname(NS_ConvertUTF8toUTF16(aQuery->Domain()), revDomain);
PRBool domainIsHost = PR_FALSE; if (aQuery->DomainIsHost()) {
aQuery->GetDomainIsHost(&domainIsHost);
if (domainIsHost) {
rv = statement->BindStringParameter(aStartParameter + *aParamCount, revDomain); rv = statement->BindStringParameter(aStartParameter + *aParamCount, revDomain);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
(*aParamCount) ++; (*aParamCount) ++;
@ -2722,21 +2695,15 @@ nsNavHistory::BindQueryClauseParameters(mozIStorageStatement* statement,
// URI // URI
if (NS_SUCCEEDED(aQuery->GetHasUri(&hasIt)) && hasIt) { if (NS_SUCCEEDED(aQuery->GetHasUri(&hasIt)) && hasIt) {
nsCOMPtr<nsIURI> uri; BindStatementURI(statement, aStartParameter + *aParamCount, aQuery->Uri());
rv = aQuery->GetUri(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); // if (hasUri) then it should be valid
BindStatementURI(statement, aStartParameter + *aParamCount, uri);
(*aParamCount) ++; (*aParamCount) ++;
} }
// annotation // annotation
aQuery->GetHasAnnotation(&hasIt); aQuery->GetHasAnnotation(&hasIt);
if (hasIt) { if (hasIt) {
nsCAutoString annotationName;
aQuery->GetAnnotation(annotationName);
rv = statement->BindUTF8StringParameter(aStartParameter + *aParamCount, rv = statement->BindUTF8StringParameter(aStartParameter + *aParamCount,
annotationName); aQuery->Annotation());
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
@ -2791,9 +2758,6 @@ nsNavHistory::RecursiveGroup(const nsCOMArray<nsNavHistoryResultNode>& aSource,
nsresult rv; nsresult rv;
switch (aGroupingMode[0]) { switch (aGroupingMode[0]) {
case nsINavHistoryQueryOptions::GROUP_BY_DAY:
rv = GroupByDay(aSource, aDest);
break;
case nsINavHistoryQueryOptions::GROUP_BY_HOST: case nsINavHistoryQueryOptions::GROUP_BY_HOST:
rv = GroupByHost(aSource, aDest, PR_FALSE); rv = GroupByHost(aSource, aDest, PR_FALSE);
break; break;
@ -2825,18 +2789,6 @@ nsNavHistory::RecursiveGroup(const nsCOMArray<nsNavHistoryResultNode>& aSource,
} }
// nsNavHistory::GroupByDay
//
// FIXME TODO IMPLEMENT ME (or maybe we don't care about this?)
nsresult
nsNavHistory::GroupByDay(const nsCOMArray<nsNavHistoryResultNode>& aSource,
nsCOMArray<nsNavHistoryResultNode>* aDest)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
// nsNavHistory::GroupByHost // nsNavHistory::GroupByHost
// //
// OPTIMIZATION: This parses the URI of each node that is coming in. This // OPTIMIZATION: This parses the URI of each node that is coming in. This
@ -2892,7 +2844,7 @@ nsNavHistory::GroupByHost(const nsCOMArray<nsNavHistoryResultNode>& aSource,
TitleForDomain(curHostName, title); TitleForDomain(curHostName, title);
curTopGroup = new nsNavHistoryContainerResultNode(title, EmptyCString(), curTopGroup = new nsNavHistoryContainerResultNode(title, EmptyCString(),
nsNavHistoryResultNode::RESULT_TYPE_HOST); nsNavHistoryResultNode::RESULT_TYPE_HOST, PR_TRUE, EmptyCString());
if (! curTopGroup) if (! curTopGroup)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
@ -2955,29 +2907,28 @@ nsNavHistory::FilterResultSet(const nsCOMArray<nsNavHistoryResultNode>& aSet,
} }
*/ */
/* FIXME(brettw)
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
if (CaseInsensitiveFindInReadable(*terms[termIndex], if (CaseInsensitiveFindInReadable(*terms[termIndex],
NS_ConvertUTF8toUTF16(aSet[nodeIndex]->mTitle)) || NS_ConvertUTF8toUTF16(aSet[nodeIndex]->mTitle)) ||
CaseInsensitiveFindInReadable(*terms[termIndex], (aSet[nodeIndex]->IsURI() &&
NS_ConvertUTF8toUTF16(aSet[nodeIndex]->mUrl))) CaseInsensitiveFindInReadable(*terms[termIndex],
NS_ConvertUTF8toUTF16(aSet[nodeIndex]->GetAsURI()->mURI))))
termFound = PR_TRUE; termFound = PR_TRUE;
// searchable annotations // searchable annotations
if (! termFound) { /*if (! termFound) {
for (PRInt32 annotIndex = 0; annotIndex < curAnnotations.Count(); annotIndex ++) { for (PRInt32 annotIndex = 0; annotIndex < curAnnotations.Count(); annotIndex ++) {
if (CaseInsensitiveFindInReadable(*terms[termIndex], if (CaseInsensitiveFindInReadable(*terms[termIndex],
*curAnnotations[annotIndex])) *curAnnotations[annotIndex]))
termFound = PR_TRUE; termFound = PR_TRUE;
} }
} }*/
if (! termFound) { if (! termFound) {
allTermsFound = PR_FALSE; allTermsFound = PR_FALSE;
break; break;
} }
} }
*/
if (allTermsFound) if (allTermsFound)
aFiltered->AppendObject(aSet[nodeIndex]); aFiltered->AppendObject(aSet[nodeIndex]);
} }
@ -3077,41 +3028,8 @@ nsNavHistory::RowToResult(mozIStorageValueArray* aRow,
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (IsQueryURI(url)) { if (IsQueryURI(url)) {
nsINavHistoryQuery** queries; // special case "place:" URIs: turn them into containers
PRUint32 queryCount; return QueryRowToResult(url, title, accessCount, time, favicon, aResult);
nsCOMPtr<nsINavHistoryQueryOptions> subIOptions;
rv = QueryStringToQueries(url, &queries, &queryCount,
getter_AddRefs(subIOptions));
if (NS_FAILED(rv)) {
// This was a query that did not parse, what do we do? We don't want to
// return failure since that will kill the whole query process. Instead
// make a query node with the query as a string. This way we have a valid
// node for the user to manipulate, but it will never populate since the
// query string is invalid.
*aResult = new nsNavHistoryQueryResultNode(aOptions, title, accessCount,
time, favicon, url);
} else {
nsCOMPtr<nsNavHistoryQueryOptions> subOptions =
do_QueryInterface(subIOptions, &rv);
NS_ASSERTION(NS_SUCCEEDED(rv), "Options must be our concrete ones");
PRInt64 folderId = GetSimpleBookmarksQueryFolder(queries, queryCount);
if (folderId) {
// simple bookmarks folder, magically generate a bookmarks folder node
*aResult = new nsNavHistoryFolderResultNode(title, 0, 0,
subOptions, folderId);
} else {
// regular query
*aResult = new nsNavHistoryQueryResultNode(subOptions, title, 0,
0, EmptyCString(),
queries, queryCount,
subOptions);
}
nsMemory::Free(queries);
}
if (! *aResult)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
return NS_OK;
} else if (aOptions->ResultType() == nsNavHistoryQueryOptions::RESULTS_AS_URI) { } else if (aOptions->ResultType() == nsNavHistoryQueryOptions::RESULTS_AS_URI) {
*aResult = new nsNavHistoryURIResultNode(title, accessCount, time, *aResult = new nsNavHistoryURIResultNode(title, accessCount, time,
favicon, url); favicon, url);
@ -3164,6 +3082,54 @@ nsNavHistory::RowToResult(mozIStorageValueArray* aRow,
} }
// nsNavHistory::QueryRowToResult
//
// Called by RowToResult when the URI is a place: URI to generate the proper
// folder or query node.
nsresult
nsNavHistory::QueryRowToResult(const nsACString& aURI, const nsACString& aTitle,
PRUint32 aAccessCount, PRTime aTime,
const nsACString& aFavicon,
nsNavHistoryResultNode** aNode)
{
nsCOMArray<nsNavHistoryQuery> queries;
nsCOMPtr<nsNavHistoryQueryOptions> options;
nsresult rv = QueryStringToQueryArray(aURI, &queries,
getter_AddRefs(options));
if (NS_FAILED(rv)) {
// This was a query that did not parse, what do we do? We don't want to
// return failure since that will kill the whole query process. Instead
// make a query node with the query as a string. This way we have a valid
// node for the user to manipulate that will look like a query, but it will
// never populate since the query string is invalid.
*aNode = new nsNavHistoryQueryResultNode(aTitle, aFavicon, aURI);
if (! *aNode)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aNode);
} else {
PRInt64 folderId = GetSimpleBookmarksQueryFolder(queries);
if (folderId) {
// simple bookmarks folder, magically generate a bookmarks folder node
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
// this addrefs for us
rv = bookmarks->ResultNodeForFolder(folderId, options, aNode);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// regular query
*aNode = new nsNavHistoryQueryResultNode(aTitle, EmptyCString(),
queries, options);
if (! *aNode)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aNode);
}
}
return NS_OK;
}
// nsNavHistory::VisitIdToResultNode // nsNavHistory::VisitIdToResultNode
// //
// Used by the query results to create new nodes on the fly when // Used by the query results to create new nodes on the fly when
@ -3473,13 +3439,12 @@ PRBool IsNumericHostName(const nsCString& aHost)
// Returns the folder ID if it is a simple folder query, 0 if not. // Returns the folder ID if it is a simple folder query, 0 if not.
static PRInt64 static PRInt64
GetSimpleBookmarksQueryFolder(nsINavHistoryQuery** aQueries, PRUint32 aQueryCount) GetSimpleBookmarksQueryFolder(const nsCOMArray<nsNavHistoryQuery>& aQueries)
{ {
if (aQueryCount != 1) if (aQueries.Count() != 1)
return 0; return 0;
nsresult rv; nsNavHistoryQuery* query = aQueries[0];
nsCOMPtr<nsNavHistoryQuery> query = do_QueryInterface(aQueries[0], &rv);
if (query->Folders().Length() != 1) if (query->Folders().Length() != 1)
return 0; return 0;

View File

@ -200,7 +200,7 @@ public:
// this actually executes a query and gives you results, it is used by // this actually executes a query and gives you results, it is used by
// nsNavHistoryQueryResultNode // nsNavHistoryQueryResultNode
nsresult GetQueryResults(const nsCOMArray<nsINavHistoryQuery>& aQueries, nsresult GetQueryResults(const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions *aOptions, nsNavHistoryQueryOptions *aOptions,
nsCOMArray<nsNavHistoryResultNode>* aResults); nsCOMArray<nsNavHistoryResultNode>* aResults);
@ -209,6 +209,10 @@ 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,
PRUint32 aAccessCount, PRTime aTime,
const nsACString& aFavicon,
nsNavHistoryResultNode** aNode);
nsresult VisitIdToResultNode(PRInt64 visitId, nsresult VisitIdToResultNode(PRInt64 visitId,
nsNavHistoryQueryOptions* aOptions, nsNavHistoryQueryOptions* aOptions,
@ -233,10 +237,10 @@ public:
static const char kAnnotationPreviousEncoding[]; static const char kAnnotationPreviousEncoding[];
// used by query result nodes to update: see comment on body of CanLiveUpdateQuery // used by query result nodes to update: see comment on body of CanLiveUpdateQuery
static PRUint32 GetUpdateRequirements(nsCOMArray<nsINavHistoryQuery>* aQueries, static PRUint32 GetUpdateRequirements(const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions* aOptions, nsNavHistoryQueryOptions* aOptions,
PRBool* aHasSearchTerms); PRBool* aHasSearchTerms);
PRBool EvaluateQueryForNode(nsCOMArray<nsINavHistoryQuery>* aQueries, PRBool EvaluateQueryForNode(const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions* aOptions, nsNavHistoryQueryOptions* aOptions,
nsNavHistoryURIResultNode* aNode); nsNavHistoryURIResultNode* aNode);
@ -249,6 +253,11 @@ public:
const PRUint32* aGroupingMode, PRUint32 aGroupCount, const PRUint32* aGroupingMode, PRUint32 aGroupCount,
nsCOMArray<nsNavHistoryResultNode>* aDest); nsCOMArray<nsNavHistoryResultNode>* aDest);
// better alternative to QueryStringToQueries (in nsNavHistoryQuery.cpp)
nsresult QueryStringToQueryArray(const nsACString& aQueryString,
nsCOMArray<nsNavHistoryQuery>* aQueries,
nsNavHistoryQueryOptions** aOptions);
private: private:
~nsNavHistory(); ~nsNavHistory();
@ -319,14 +328,14 @@ protected:
nsCOMPtr<nsITimer> mExpireNowTimer; nsCOMPtr<nsITimer> mExpireNowTimer;
static void expireNowTimerCallback(nsITimer* aTimer, void* aClosure); static void expireNowTimerCallback(nsITimer* aTimer, void* aClosure);
nsresult QueryToSelectClause(nsINavHistoryQuery* aQuery, nsresult QueryToSelectClause(nsNavHistoryQuery* aQuery,
PRInt32 aStartParameter, PRInt32 aStartParameter,
nsCString* aClause, nsCString* aClause,
PRInt32* aParamCount, PRInt32* aParamCount,
const nsACString& aCommonConditions); const nsACString& aCommonConditions);
nsresult BindQueryClauseParameters(mozIStorageStatement* statement, nsresult BindQueryClauseParameters(mozIStorageStatement* statement,
PRInt32 aStartParameter, PRInt32 aStartParameter,
nsINavHistoryQuery* aQuery, nsNavHistoryQuery* aQuery,
PRInt32* aParamCount); PRInt32* aParamCount);
nsresult ResultsAsList(mozIStorageStatement* statement, nsresult ResultsAsList(mozIStorageStatement* statement,
@ -337,8 +346,6 @@ protected:
nsresult SetPageTitleInternal(nsIURI* aURI, PRBool aIsUserTitle, nsresult SetPageTitleInternal(nsIURI* aURI, PRBool aIsUserTitle,
const nsAString& aTitle); const nsAString& aTitle);
nsresult GroupByDay(const nsCOMArray<nsNavHistoryResultNode>& aSource,
nsCOMArray<nsNavHistoryResultNode>* aDest);
nsresult GroupByHost(const nsCOMArray<nsNavHistoryResultNode>& aSource, nsresult GroupByHost(const nsCOMArray<nsNavHistoryResultNode>& aSource,
nsCOMArray<nsNavHistoryResultNode>* aDest, nsCOMArray<nsNavHistoryResultNode>* aDest,
PRBool aIsDomain); PRBool aIsDomain);
@ -413,7 +420,7 @@ protected:
// in nsNavHistoryQuery.cpp // in nsNavHistoryQuery.cpp
nsresult TokensToQueries(const nsTArray<QueryKeyValuePair>& aTokens, nsresult TokensToQueries(const nsTArray<QueryKeyValuePair>& aTokens,
nsCOMArray<nsINavHistoryQuery>* aQueries, nsCOMArray<nsNavHistoryQuery>* aQueries,
nsNavHistoryQueryOptions* aOptions); nsNavHistoryQueryOptions* aOptions);
// Transaction Manager // Transaction Manager

View File

@ -141,7 +141,7 @@ static void SetOptionsKeyUint32(const nsCString& aValue,
#define QUERYKEY_ONLY_BOOKMARKED "onlyBookmarked" #define QUERYKEY_ONLY_BOOKMARKED "onlyBookmarked"
#define QUERYKEY_DOMAIN_IS_HOST "domainIsHost" #define QUERYKEY_DOMAIN_IS_HOST "domainIsHost"
#define QUERYKEY_DOMAIN "domain" #define QUERYKEY_DOMAIN "domain"
#define QUERYKEY_FOLDERS "folders" #define QUERYKEY_FOLDER "folder"
#define QUERYKEY_NOTANNOTATION "!annotation" #define QUERYKEY_NOTANNOTATION "!annotation"
#define QUERYKEY_ANNOTATION "annotation" #define QUERYKEY_ANNOTATION "annotation"
#define QUERYKEY_URI "uri" #define QUERYKEY_URI "uri"
@ -175,7 +175,11 @@ inline void AppendInt64(nsACString& str, PRInt64 i)
str.Append(tmp); str.Append(tmp);
} }
// nsNavHistory::QueryStringToQueries // nsNavHistory::QueryStringToQueries
//
// From C++ places code, you should use QueryStringToQueryArray, this is
// the harder-to-use XPCOM version.
NS_IMETHODIMP NS_IMETHODIMP
nsNavHistory::QueryStringToQueries(const nsACString& aQueryString, nsNavHistory::QueryStringToQueries(const nsACString& aQueryString,
@ -183,9 +187,42 @@ nsNavHistory::QueryStringToQueries(const nsACString& aQueryString,
PRUint32* aResultCount, PRUint32* aResultCount,
nsINavHistoryQueryOptions** aOptions) nsINavHistoryQueryOptions** aOptions)
{ {
nsresult rv;
*aQueries = nsnull; *aQueries = nsnull;
*aResultCount = 0; *aResultCount = 0;
nsCOMPtr<nsNavHistoryQueryOptions> options;
nsCOMArray<nsNavHistoryQuery> queries;
nsresult rv = QueryStringToQueryArray(aQueryString, &queries,
getter_AddRefs(options));
NS_ENSURE_SUCCESS(rv, rv);
*aResultCount = queries.Count();
if (queries.Count() > 0) {
// convert COM array to raw
*aQueries = NS_STATIC_CAST(nsINavHistoryQuery**,
nsMemory::Alloc(sizeof(nsINavHistoryQuery*) * queries.Count()));
NS_ENSURE_TRUE(*aQueries, NS_ERROR_OUT_OF_MEMORY);
for (PRInt32 i = 0; i < queries.Count(); i ++) {
(*aQueries)[i] = queries[i];
NS_ADDREF((*aQueries)[i]);
}
}
NS_ADDREF(*aOptions = options);
return NS_OK;
}
// nsNavHistory::QueryStringToQueryArray
//
// An internal version of QueryStringToQueries that fills a COM array for
// ease-of-use.
nsresult
nsNavHistory::QueryStringToQueryArray(const nsACString& aQueryString,
nsCOMArray<nsNavHistoryQuery>* aQueries,
nsNavHistoryQueryOptions** aOptions)
{
nsresult rv;
aQueries->Clear();
*aOptions = nsnull; *aOptions = nsnull;
nsRefPtr<nsNavHistoryQueryOptions> options(new nsNavHistoryQueryOptions()); nsRefPtr<nsNavHistoryQueryOptions> options(new nsNavHistoryQueryOptions());
@ -196,30 +233,14 @@ nsNavHistory::QueryStringToQueries(const nsACString& aQueryString,
rv = TokenizeQueryString(aQueryString, &tokens); rv = TokenizeQueryString(aQueryString, &tokens);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsCOMArray<nsINavHistoryQuery> queries; rv = TokensToQueries(tokens, aQueries, options);
rv = TokensToQueries(tokens, &queries, options); if (NS_FAILED(rv)) {
NS_WARNING("Unable to parse the query string: ");
NS_WARNING(PromiseFlatCString(aQueryString).get());
}
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
NS_STATIC_CAST(nsRefPtr<nsINavHistoryQueryOptions>, options).swap(*aOptions);
*aResultCount = queries.Count();
if (queries.Count() == 0) {
// need to special-case 0 queries since we don't allocate an array
*aQueries = nsnull;
return NS_OK;
}
// convert COM array to raw
*aQueries = NS_STATIC_CAST(nsINavHistoryQuery**,
nsMemory::Alloc(sizeof(nsINavHistoryQuery*) * queries.Count()));
if (! *aQueries)
return NS_ERROR_OUT_OF_MEMORY;
for (PRInt32 i = 0; i < queries.Count(); i ++) {
(*aQueries)[i] = queries[i];
NS_ADDREF((*aQueries)[i]);
}
NS_ADDREF(*aOptions = options); NS_ADDREF(*aOptions = options);
return NS_OK; return NS_OK;
} }
@ -352,7 +373,7 @@ nsNavHistory::QueriesToQueryString(nsINavHistoryQuery **aQueries,
query->GetFolders(&folderCount, &folders); query->GetFolders(&folderCount, &folders);
for (PRUint32 i = 0; i < folderCount; ++i) { for (PRUint32 i = 0; i < folderCount; ++i) {
AppendAmpersandIfNonempty(aQueryString); AppendAmpersandIfNonempty(aQueryString);
aQueryString += NS_LITERAL_CSTRING(QUERYKEY_FOLDERS "="); aQueryString += NS_LITERAL_CSTRING(QUERYKEY_FOLDER "=");
AppendInt64(aQueryString, folders[0]); AppendInt64(aQueryString, folders[0]);
} }
} }
@ -465,7 +486,7 @@ TokenizeQueryString(const nsACString& aQuery,
nsresult nsresult
nsNavHistory::TokensToQueries(const nsTArray<QueryKeyValuePair>& aTokens, nsNavHistory::TokensToQueries(const nsTArray<QueryKeyValuePair>& aTokens,
nsCOMArray<nsINavHistoryQuery>* aQueries, nsCOMArray<nsNavHistoryQuery>* aQueries,
nsNavHistoryQueryOptions* aOptions) nsNavHistoryQueryOptions* aOptions)
{ {
nsresult rv; nsresult rv;
@ -475,7 +496,7 @@ nsNavHistory::TokensToQueries(const nsTArray<QueryKeyValuePair>& aTokens,
nsTArray<PRUint32> groups; nsTArray<PRUint32> groups;
nsTArray<PRInt64> folders; nsTArray<PRInt64> folders;
nsCOMPtr<nsINavHistoryQuery> query(new nsNavHistoryQuery()); nsCOMPtr<nsNavHistoryQuery> query(new nsNavHistoryQuery());
if (! query) if (! query)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
if (! aQueries->AppendObject(query)) if (! aQueries->AppendObject(query))
@ -522,7 +543,7 @@ nsNavHistory::TokensToQueries(const nsTArray<QueryKeyValuePair>& aTokens,
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// folders: FIXME use folder name??? // folders: FIXME use folder name???
} else if (kvp.key.EqualsLiteral(QUERYKEY_FOLDERS)) { } else if (kvp.key.EqualsLiteral(QUERYKEY_FOLDER)) {
PRInt64 folder; PRInt64 folder;
if (PR_sscanf(kvp.value.get(), "%lld", &folder) == 1) { if (PR_sscanf(kvp.value.get(), "%lld", &folder) == 1) {
NS_ENSURE_TRUE(folders.AppendElement(folder), NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(folders.AppendElement(folder), NS_ERROR_OUT_OF_MEMORY);

View File

@ -77,6 +77,8 @@ public:
const nsCString& Domain() { return mDomain; } const nsCString& Domain() { return mDomain; }
PRBool UriIsPrefix() { return mUriIsPrefix; } PRBool UriIsPrefix() { return mUriIsPrefix; }
nsIURI* Uri() { return mUri; } // NOT AddRef-ed! nsIURI* Uri() { return mUri; } // NOT AddRef-ed!
PRBool AnnotationIsNot() { return mAnnotationIsNot; }
const nsCString& Annotation() { return mAnnotation; }
const nsTArray<PRInt64>& Folders() const { return mFolders; } const nsTArray<PRInt64>& Folders() const { return mFolders; }
private: private:

View File

@ -52,6 +52,7 @@
#include "nsILocale.h" #include "nsILocale.h"
#include "nsILocaleService.h" #include "nsILocaleService.h"
#include "nsILocalFile.h" #include "nsILocalFile.h"
#include "nsIRemoteContainer.h"
#include "nsIServiceManager.h" #include "nsIServiceManager.h"
#include "nsISupportsPrimitives.h" #include "nsISupportsPrimitives.h"
#include "nsITreeColumns.h" #include "nsITreeColumns.h"
@ -162,6 +163,45 @@ nsNavHistoryResultNode::GetResult()
} }
// nsNavHistoryResultNode::GetGeneratingOptions
//
// Searches up the tree for the closest node that has an options structure.
// This will tell us the options that were used to generate this node.
//
// Be careful, this function walks up the tree, so it can not be used when
// result nodes are created because they have no parent. Only call this
// function after the tree has been built.
nsNavHistoryQueryOptions*
nsNavHistoryResultNode::GetGeneratingOptions()
{
if (! mParent) {
// When we have no parent, it either means we haven't built the tree yet,
// in which case calling this function is a bug, or this node is the root
// of the tree. When we are the root of the tree, our own options are the
// generating options, and we know we are either a query of a folder node.
if (IsFolder())
return GetAsFolder()->mOptions;
else if (IsQuery())
return GetAsQuery()->mOptions;
NS_NOTREACHED("Can't find a generating node for this container, perhaps FillStats has not been called on this tree yet?");
return nsnull;
}
nsNavHistoryContainerResultNode* cur = mParent;
while (cur) {
if (cur->IsFolder())
return cur->GetAsFolder()->mOptions;
else if (cur->IsQuery())
return cur->GetAsQuery()->mOptions;
cur = cur->mParent;
}
// we should always find a folder or query node as an ancestor
NS_NOTREACHED("Can't find a generating node for this container, the tree seemes corrupted.");
return nsnull;
}
// nsNavHistoryURIResultNode *************************************************** // nsNavHistoryURIResultNode ***************************************************
NS_IMPL_ISUPPORTS_INHERITED1(nsNavHistoryURIResultNode, NS_IMPL_ISUPPORTS_INHERITED1(nsNavHistoryURIResultNode,
@ -216,32 +256,17 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsNavHistoryContainerResultNode,
nsNavHistoryResultNode, nsNavHistoryResultNode,
nsINavHistoryContainerResultNode) nsINavHistoryContainerResultNode)
nsNavHistoryContainerResultNode::nsNavHistoryContainerResultNode(
const nsACString& aTitle, PRUint32 aAccessCount, PRTime aTime,
const nsACString& aIconURI, PRUint32 aContainerType, PRBool aReadOnly) :
nsNavHistoryResultNode(aTitle, aAccessCount, aTime, aIconURI),
mResult(nsnull),
mContainerType(aContainerType),
mExpanded(PR_FALSE),
mChildrenReadOnly(aReadOnly)
{
}
nsNavHistoryContainerResultNode::nsNavHistoryContainerResultNode( nsNavHistoryContainerResultNode::nsNavHistoryContainerResultNode(
const nsACString& aTitle, const nsACString& aIconURI, const nsACString& aTitle, const nsACString& aIconURI,
PRUint32 aContainerType) : PRUint32 aContainerType, PRBool aReadOnly,
const nsACString& aRemoteContainerType) :
nsNavHistoryResultNode(aTitle, 0, 0, aIconURI), nsNavHistoryResultNode(aTitle, 0, 0, aIconURI),
mResult(nsnull), mResult(nsnull),
mContainerType(aContainerType), mContainerType(aContainerType),
mExpanded(PR_FALSE), mExpanded(PR_FALSE),
mChildrenReadOnly(PR_TRUE) mChildrenReadOnly(aReadOnly),
mRemoteContainerType(aRemoteContainerType)
{ {
// The container type must be a host or day. This constructor is used when
// we are grouping and want to create host or day containers. Therefore, you
// can't use it with folder or query containers.
NS_ASSERTION(aContainerType == nsINavHistoryResultNode::RESULT_TYPE_HOST ||
aContainerType == nsINavHistoryResultNode::RESULT_TYPE_DAY,
"You are passing in a container type that isn't valid");
} }
@ -312,6 +337,9 @@ nsNavHistoryContainerResultNode::SetContainerOpen(PRBool aContainerOpen)
// nsNavHistoryContainerResultNode::OpenContainer // nsNavHistoryContainerResultNode::OpenContainer
//
// This handles the generic container case. Other container types should
// override this to do their own handling.
nsresult nsresult
nsNavHistoryContainerResultNode::OpenContainer() nsNavHistoryContainerResultNode::OpenContainer()
@ -320,6 +348,20 @@ nsNavHistoryContainerResultNode::OpenContainer()
NS_ASSERTION(! mExpanded, "Container must be expanded to close it"); NS_ASSERTION(! mExpanded, "Container must be expanded to close it");
mExpanded = PR_TRUE; mExpanded = PR_TRUE;
if (! mRemoteContainerType.IsEmpty()) {
// remote container API may want to fill us
nsCOMPtr<nsIRemoteContainer> remote = do_GetService(mRemoteContainerType.get(), &rv);
if (NS_SUCCEEDED(rv)) {
remote->OnContainerOpening(this, GetGeneratingOptions());
} else {
NS_WARNING("Unable to get remote container for ");
NS_WARNING(mRemoteContainerType.get());
}
PRInt32 oldAccessCount = mAccessCount;
FillStats();
ReverseUpdateStats(mAccessCount - oldAccessCount);
}
nsNavHistoryResult* result = GetResult(); nsNavHistoryResult* result = GetResult();
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE); NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
rv = result->RefreshVisibleSection(this); rv = result->RefreshVisibleSection(this);
@ -336,9 +378,17 @@ nsNavHistoryContainerResultNode::CloseContainer()
NS_ASSERTION(mExpanded, "Container must be expanded to close it"); NS_ASSERTION(mExpanded, "Container must be expanded to close it");
mExpanded = PR_FALSE; mExpanded = PR_FALSE;
nsresult rv;
if (! mRemoteContainerType.IsEmpty()) {
// notify remote containers that we are closing
nsCOMPtr<nsIRemoteContainer> remote = do_GetService(mRemoteContainerType.get(), &rv);
if (NS_SUCCEEDED(rv))
remote->OnContainerClosed(this);
}
nsNavHistoryResult* result = GetResult(); nsNavHistoryResult* result = GetResult();
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE); NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
nsresult rv = result->RefreshVisibleSection(this); rv = result->RefreshVisibleSection(this);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return NS_OK; return NS_OK;
} }
@ -691,9 +741,6 @@ PRInt32 PR_CALLBACK nsNavHistoryContainerResultNode::SortComparison_URILess(
nsNavHistoryURIResultNode* aURI = a->GetAsURI(); nsNavHistoryURIResultNode* aURI = a->GetAsURI();
nsNavHistoryURIResultNode* bURI = b->GetAsURI(); nsNavHistoryURIResultNode* bURI = b->GetAsURI();
value = aURI->mURI.Compare(bURI->mURI.get()); value = aURI->mURI.Compare(bURI->mURI.get());
} else if (aType == nsINavHistoryResultNode::RESULT_TYPE_DAY) {
// date nodes use date (skip conflict resolution because it uses date too)
return ComparePRTime(a->mTime, b->mTime);
} else { } else {
// for everything else, use title (= host name) // for everything else, use title (= host name)
nsICollation* collation = NS_STATIC_CAST(nsICollation*, closure); nsICollation* collation = NS_STATIC_CAST(nsICollation*, closure);
@ -1079,6 +1126,20 @@ nsNavHistoryContainerResultNode::RemoveChildAt(PRInt32 aIndex,
} }
// nsNavHistoryContainerResultNode::CanRemoteContainersChange
//
// Returns true if remote containers can manipulate the contents of this
// container. This is false for folders and queries, true for everything
// else.
PRBool
nsNavHistoryContainerResultNode::CanRemoteContainersChange()
{
return (mContainerType != nsINavHistoryResultNode::RESULT_TYPE_FOLDER &&
mContainerType != nsINavHistoryResultNode::RESULT_TYPE_QUERY);
}
// nsNavHistoryContainerResultNode::GetHasChildren // nsNavHistoryContainerResultNode::GetHasChildren
// //
// Complex containers (folders and queries) will override this. Here, we // Complex containers (folders and queries) will override this. Here, we
@ -1131,27 +1192,233 @@ nsNavHistoryContainerResultNode::GetChildrenReadOnly(PRBool *aChildrenReadOnly)
return NS_OK; return NS_OK;
} }
// nsNavHistoryContainerResultNode::GetRemoteContainerType
NS_IMETHODIMP
nsNavHistoryContainerResultNode::GetRemoteContainerType(
nsACString& aRemoteContainerType)
{
aRemoteContainerType = mRemoteContainerType;
return NS_OK;
}
// nsNavHistoryContainerResultNode::AppendURINode
NS_IMETHODIMP
nsNavHistoryContainerResultNode::AppendURINode(
const nsACString& aTitle, PRUint32 aAccessCount, PRTime aTime,
const nsACString& aIconURI, const nsACString& aURI,
nsINavHistoryURIResultNode** _retval)
{
*_retval = nsnull;
if (mRemoteContainerType.IsEmpty() || ! CanRemoteContainersChange())
return NS_ERROR_INVALID_ARG; // we must be a remote container
nsRefPtr<nsNavHistoryURIResultNode> result =
new nsNavHistoryURIResultNode(aTitle, aAccessCount, aTime, aIconURI, aURI);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
// append to our list
if (! mChildren.AppendObject(result))
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*_retval = result);
return NS_OK;
}
// nsNavHistoryContainerResultNode::AppendVisitNode
NS_IMETHODIMP
nsNavHistoryContainerResultNode::AppendVisitNode(
const nsACString& aTitle, PRUint32 aAccessCount, PRTime aTime,
const nsACString& aIconURI, const nsACString& aURI, PRInt64 aSession,
nsINavHistoryVisitResultNode** _retval)
{
*_retval = nsnull;
if (mRemoteContainerType.IsEmpty() || ! CanRemoteContainersChange())
return NS_ERROR_INVALID_ARG; // we must be a remote container
nsRefPtr<nsNavHistoryVisitResultNode> result =
new nsNavHistoryVisitResultNode(aTitle, aAccessCount, aTime,
aIconURI, aURI, aSession);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
// append to our list
if (! mChildren.AppendObject(result))
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*_retval = result);
return NS_OK;
}
// nsNavHistoryContainerResultNode::AppendFullVisitNode
NS_IMETHODIMP
nsNavHistoryContainerResultNode::AppendFullVisitNode(
const nsACString& aTitle, PRUint32 aAccessCount, PRTime aTime,
const nsACString& aIconURI, const nsACString& aURI, PRInt64 aSession,
PRInt64 aVisitId, PRInt64 aReferringVisitId, PRInt32 aTransitionType,
nsINavHistoryFullVisitResultNode** _retval)
{
*_retval = nsnull;
if (mRemoteContainerType.IsEmpty() || ! CanRemoteContainersChange())
return NS_ERROR_INVALID_ARG; // we must be a remote container
nsRefPtr<nsNavHistoryFullVisitResultNode> result =
new nsNavHistoryFullVisitResultNode(aTitle, aAccessCount, aTime,
aIconURI, aURI, aSession,
aVisitId, aReferringVisitId,
aTransitionType);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
// append to our list
if (! mChildren.AppendObject(result))
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*_retval = result);
return NS_OK;
}
// nsNavHistoryContainerResultNode::AppendContainerNode
NS_IMETHODIMP
nsNavHistoryContainerResultNode::AppendContainerNode(
const nsACString& aTitle, const nsACString& aIconURI,
PRUint32 aContainerType, const nsACString& aRemoteContainerType,
nsINavHistoryContainerResultNode** _retval)
{
*_retval = nsnull;
if (mRemoteContainerType.IsEmpty() || ! CanRemoteContainersChange())
return NS_ERROR_INVALID_ARG; // we must be a remote container
if (! IsTypeContainer(aContainerType) || IsTypeFolder(aContainerType) ||
IsTypeQuery(aContainerType))
return NS_ERROR_INVALID_ARG; // not proper container type
if (aContainerType == nsINavHistoryResultNode::RESULT_TYPE_REMOTE_CONTAINER &&
aRemoteContainerType.IsEmpty())
return NS_ERROR_INVALID_ARG; // remote containers must have r.c. type
if (aContainerType != nsINavHistoryResultNode::RESULT_TYPE_REMOTE_CONTAINER &&
! aRemoteContainerType.IsEmpty())
return NS_ERROR_INVALID_ARG; // non-remote containers must NOT have r.c. type
nsRefPtr<nsNavHistoryContainerResultNode> result =
new nsNavHistoryContainerResultNode(aTitle, aIconURI, aContainerType,
PR_TRUE, aRemoteContainerType);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
// append to our list
if (! mChildren.AppendObject(result))
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*_retval = result);
return NS_OK;
}
// nsNavHistoryContainerResultNode::AppendQueryNode
NS_IMETHODIMP
nsNavHistoryContainerResultNode::AppendQueryNode(
const nsACString& aTitle, const nsACString& aIconURI,
const nsACString& aQueryString, nsINavHistoryQueryResultNode** _retval)
{
*_retval = nsnull;
if (mRemoteContainerType.IsEmpty() || ! CanRemoteContainersChange())
return NS_ERROR_INVALID_ARG; // we must be a remote container
nsRefPtr<nsNavHistoryQueryResultNode> result =
new nsNavHistoryQueryResultNode(aTitle, aIconURI, aQueryString);
NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
// append to our list
if (! mChildren.AppendObject(result))
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*_retval = result);
return NS_OK;
}
// nsNavHistoryContainerResultNode::AppendFolderNode
NS_IMETHODIMP
nsNavHistoryContainerResultNode::AppendFolderNode(
PRInt64 aFolderId, nsINavHistoryFolderResultNode** _retval)
{
*_retval = nsnull;
if (mRemoteContainerType.IsEmpty() || ! CanRemoteContainersChange())
return NS_ERROR_INVALID_ARG; // we must be a remote container
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
// create the node, it will be addrefed for us
nsRefPtr<nsNavHistoryResultNode> result;
nsresult rv = bookmarks->ResultNodeForFolder(aFolderId,
GetGeneratingOptions(),
getter_AddRefs(result));
NS_ENSURE_SUCCESS(rv, rv);
// append to our list
if (! mChildren.AppendObject(result))
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*_retval = result->GetAsFolder());
return NS_OK;
}
// nsNavHistoryContainerResultNode::ClearContents
//
// Used by the remote container API to clear this container
NS_IMETHODIMP
nsNavHistoryContainerResultNode::ClearContents()
{
if (mRemoteContainerType.IsEmpty() || ! CanRemoteContainersChange())
return NS_ERROR_INVALID_ARG; // we must be a remote container
// we know if CanRemoteContainersChange() then we are a regular container
// and not a query or folder, so clearing doesn't need anything else to
// happen (like unregistering observers). Also, since this should only
// happen when the container is closed, we don't need to redraw the screen.
mChildren.Clear();
PRUint32 oldAccessCount = mAccessCount;
mAccessCount = 0;
mTime = 0;
ReverseUpdateStats(-oldAccessCount);
return NS_OK;
}
// nsNavHistoryQueryResultNode ************************************************* // nsNavHistoryQueryResultNode *************************************************
// //
// HOW QUERY UPDATING WORKS // HOW QUERY UPDATING WORKS
// //
// Queries are different than bookmark folders in that we can not always // Queries are different than bookmark folders in that we can not always
// do dynamic updates (easily) and updates are more expensive. // do dynamic updates (easily) and updates are more expensive. Therefore,
// we do NOT query if we are not open and want to see if we have any children
// (for drawing a twisty) and always assume we will.
// //
// // When the container is opened, we execute the query and register the
// listeners. Like bookmark folders, we stay registered even when closed,
// and clear ourselves as soon as a message comes in. This lets us respond
// quickly if the user closes and reopens the container.
//
// We try to handle the most common notifications for the most common query
// types dynamically, that is, figuring out what should happen in response
// to a message without doing a requery. For complex changes or complex
// queries, we give up and requery.
NS_IMPL_ISUPPORTS_INHERITED1(nsNavHistoryQueryResultNode, NS_IMPL_ISUPPORTS_INHERITED1(nsNavHistoryQueryResultNode,
nsNavHistoryContainerResultNode, nsNavHistoryContainerResultNode,
nsINavHistoryQueryResultNode) nsINavHistoryQueryResultNode)
nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode( nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode(
nsNavHistoryQueryOptions* aGeneratingOptions, const nsACString& aTitle, const nsACString& aIconURI,
const nsACString& aTitle, PRUint32 aAccessCount, PRTime aTime, const nsACString& aQueryURI) :
const nsACString& aIconURI, const nsACString& aQueryURI) : nsNavHistoryContainerResultNode(aTitle, aIconURI,
nsNavHistoryContainerResultNode(aTitle, aAccessCount, aTime, aIconURI,
nsINavHistoryResultNode::RESULT_TYPE_QUERY, nsINavHistoryResultNode::RESULT_TYPE_QUERY,
PR_TRUE), PR_TRUE, EmptyCString()),
mGeneratingOptions(aGeneratingOptions),
mQueryURI(aQueryURI), mQueryURI(aQueryURI),
mHasSearchTerms(PR_FALSE), mHasSearchTerms(PR_FALSE),
mContentsValid(PR_FALSE), mContentsValid(PR_FALSE),
@ -1163,26 +1430,27 @@ nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode(
} }
nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode( nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode(
nsNavHistoryQueryOptions* aGeneratingOptions, const nsACString& aTitle, const nsACString& aIconURI,
const nsACString& aTitle, PRUint32 aAccessCount, PRTime aTime, const nsCOMArray<nsNavHistoryQuery>& aQueries,
const nsACString& aIconURI, nsINavHistoryQuery** aQueries, nsNavHistoryQueryOptions* aOptions) :
PRUint32 aQueryCount, nsNavHistoryQueryOptions* aOptions) : nsNavHistoryContainerResultNode(aTitle, aIconURI,
nsNavHistoryContainerResultNode(aTitle, aAccessCount, aTime, aIconURI,
nsINavHistoryResultNode::RESULT_TYPE_QUERY, nsINavHistoryResultNode::RESULT_TYPE_QUERY,
PR_TRUE), PR_TRUE, EmptyCString()),
mGeneratingOptions(aGeneratingOptions), mQueries(aQueries),
mOptions(aOptions),
mContentsValid(PR_FALSE), mContentsValid(PR_FALSE),
mBatchInProgress(PR_FALSE) mBatchInProgress(PR_FALSE)
{ {
NS_ASSERTION(aQueryCount > 0, "Must have at least one query"); NS_ASSERTION(aQueries.Count() > 0, "Must have at least one query");
/*
for (PRUint32 i = 0; i < aQueryCount; i ++) for (PRUint32 i = 0; i < aQueryCount; i ++)
mQueries.AppendObject(aQueries[i]); mQueries.AppendObject(aQueries[i]);
aOptions->Clone(getter_AddRefs(mOptions)); aOptions->Clone(getter_AddRefs(mOptions));
*/
nsNavHistory* history = nsNavHistory::GetHistoryService(); nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ASSERTION(history, "History service missing"); NS_ASSERTION(history, "History service missing");
mLiveUpdate = history->GetUpdateRequirements(&mQueries, mOptions, mLiveUpdate = history->GetUpdateRequirements(mQueries, mOptions,
&mHasSearchTerms); &mHasSearchTerms);
// queries have special icons if not otherwise set // queries have special icons if not otherwise set
@ -1200,7 +1468,8 @@ nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode(
PRBool PRBool
nsNavHistoryQueryResultNode::CanExpand() nsNavHistoryQueryResultNode::CanExpand()
{ {
if (mGeneratingOptions->ExpandQueries()) nsNavHistoryQueryOptions* options = GetGeneratingOptions();
if (options && options->ExpandQueries())
return PR_TRUE; return PR_TRUE;
if (mResult && mResult->mRootNode == this) if (mResult && mResult->mRootNode == this)
return PR_TRUE; return PR_TRUE;
@ -1233,13 +1502,18 @@ nsNavHistoryQueryResultNode::OnRemoving()
nsresult nsresult
nsNavHistoryQueryResultNode::OpenContainer() nsNavHistoryQueryResultNode::OpenContainer()
{ {
NS_ASSERTION(! mExpanded, "Container must be expanded to close it");
if (! CanExpand()) if (! CanExpand())
return NS_OK; return NS_OK;
if (! mContentsValid) { if (! mContentsValid) {
nsresult rv = FillChildren(); nsresult rv = FillChildren();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
return nsNavHistoryContainerResultNode::OpenContainer();
mExpanded = PR_TRUE;
nsNavHistoryResult* result = GetResult();
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
return result->RefreshVisibleSection(this);
} }
@ -1329,31 +1603,11 @@ nsNavHistoryQueryResultNode::VerifyQueriesParsed()
nsNavHistory* history = nsNavHistory::GetHistoryService(); nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
nsINavHistoryQuery** queries; nsresult rv = history->QueryStringToQueryArray(mQueryURI, &mQueries,
PRUint32 queryCount; getter_AddRefs(mOptions));
nsCOMPtr<nsINavHistoryQueryOptions> options;
nsresult rv = history->QueryStringToQueries(mQueryURI, &queries, &queryCount,
getter_AddRefs(options));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
mOptions = do_QueryInterface(options, &rv); // need concrete pointer
if (NS_FAILED(rv)) {
nsMemory::Free(queries);
return rv;
}
// Copy the individual queries into our array. At the same time, note if mLiveUpdate = history->GetUpdateRequirements(mQueries, mOptions,
// we have any bookmark components so we know whether to pay attention to
// bookmark notifications.
for (PRUint32 i = 0; i < queryCount; i ++) {
if (! mQueries.AppendObject(queries[i])) {
nsMemory::Free(queries);
mQueries.Clear();
return NS_ERROR_OUT_OF_MEMORY;
}
}
nsMemory::Free(queries);
mLiveUpdate = history->GetUpdateRequirements(&mQueries, mOptions,
&mHasSearchTerms); &mHasSearchTerms);
return NS_OK; return NS_OK;
} }
@ -1726,7 +1980,7 @@ nsNavHistoryQueryResultNode::OnVisit(nsIURI* aURI, PRInt64 aVisitId,
rv = history->VisitIdToResultNode(aVisitId, mOptions, rv = history->VisitIdToResultNode(aVisitId, mOptions,
getter_AddRefs(addition)); getter_AddRefs(addition));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (! history->EvaluateQueryForNode(&mQueries, mOptions, if (! history->EvaluateQueryForNode(mQueries, mOptions,
addition->GetAsURI())) addition->GetAsURI()))
return NS_OK; // don't need to include in our query return NS_OK; // don't need to include in our query
break; break;
@ -2051,11 +2305,11 @@ NS_IMPL_ISUPPORTS_INHERITED2(nsNavHistoryFolderResultNode,
nsINavHistoryFolderResultNode) nsINavHistoryFolderResultNode)
nsNavHistoryFolderResultNode::nsNavHistoryFolderResultNode( nsNavHistoryFolderResultNode::nsNavHistoryFolderResultNode(
const nsACString& aTitle, PRUint32 aAccessCount, PRTime aTime, const nsACString& aTitle, nsNavHistoryQueryOptions* aOptions,
nsNavHistoryQueryOptions* aOptions, PRInt64 aFolderId) : PRInt64 aFolderId, const nsACString& aRemoteContainerType) :
nsNavHistoryContainerResultNode(aTitle, aAccessCount, aTime, EmptyCString(), nsNavHistoryContainerResultNode(aTitle, EmptyCString(),
nsINavHistoryResultNode::RESULT_TYPE_FOLDER, nsINavHistoryResultNode::RESULT_TYPE_FOLDER,
PR_FALSE), PR_FALSE, aRemoteContainerType),
mContentsValid(PR_FALSE), mContentsValid(PR_FALSE),
mOptions(aOptions), mOptions(aOptions),
mFolderId(aFolderId) mFolderId(aFolderId)
@ -2104,11 +2358,28 @@ nsNavHistoryFolderResultNode::OnRemoving()
nsresult nsresult
nsNavHistoryFolderResultNode::OpenContainer() nsNavHistoryFolderResultNode::OpenContainer()
{ {
NS_ASSERTION(! mExpanded, "Container must be expanded to close it");
nsresult rv;
if (! mRemoteContainerType.IsEmpty()) {
// remote container API may want to change the bookmarks for this folder.
nsCOMPtr<nsIRemoteContainer> remote = do_GetService(mRemoteContainerType.get(), &rv);
if (NS_SUCCEEDED(rv)) {
remote->OnContainerOpening(NS_STATIC_CAST(nsINavHistoryFolderResultNode*, this),
mOptions);
} else {
NS_WARNING("Unable to get remote container for ");
NS_WARNING(mRemoteContainerType.get());
}
}
if (! mContentsValid) { if (! mContentsValid) {
nsresult rv = FillChildren(); rv = FillChildren();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
return nsNavHistoryContainerResultNode::OpenContainer(); mExpanded = PR_TRUE;
nsNavHistoryResult* result = GetResult();
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
return result->RefreshVisibleSection(this);
} }
@ -2734,11 +3005,9 @@ nsNavHistoryResult::ComputeShowSessions()
return; // not date sorting return; // not date sorting
PRUint32 groupCount; PRUint32 groupCount;
const PRUint32* groups = mOptions->GroupingMode(&groupCount); mOptions->GroupingMode(&groupCount);
for (PRUint32 i = 0; i < groupCount; i ++) { if (groupCount > 0)
if (groups[i] != nsINavHistoryQueryOptions::GROUP_BY_DAY) return;
return; // non-time-based grouping
}
mShowSessions = PR_TRUE; mShowSessions = PR_TRUE;
} }

View File

@ -53,6 +53,7 @@ class nsNavHistory;
class nsNavHistoryResult; class nsNavHistoryResult;
class nsIDateTimeFormat; class nsIDateTimeFormat;
class nsIWritablePropertyBag; class nsIWritablePropertyBag;
class nsNavHistoryQuery;
class nsNavHistoryQueryOptions; class nsNavHistoryQueryOptions;
class nsNavHistoryContainerResultNode; class nsNavHistoryContainerResultNode;
@ -167,13 +168,14 @@ public:
public: public:
nsNavHistoryResult* GetResult(); nsNavHistoryResult* GetResult();
nsNavHistoryQueryOptions* GetGeneratingOptions();
// These functions test the type. We don't use a virtual function since that // These functions test the type. We don't use a virtual function since that
// would take a vtable slot for every one of (potentially very many) nodes. // would take a vtable slot for every one of (potentially very many) nodes.
// Note that GetType() already has a vtable slot because its on the iface. // Note that GetType() already has a vtable slot because its on the iface.
PRBool IsTypeContainer(PRUint32 type) { PRBool IsTypeContainer(PRUint32 type) {
return (type == nsINavHistoryResultNode::RESULT_TYPE_HOST || return (type == nsINavHistoryResultNode::RESULT_TYPE_HOST ||
type == nsINavHistoryResultNode::RESULT_TYPE_DAY || type == nsINavHistoryResultNode::RESULT_TYPE_REMOTE_CONTAINER ||
type == nsINavHistoryResultNode::RESULT_TYPE_QUERY || type == nsINavHistoryResultNode::RESULT_TYPE_QUERY ||
type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER); type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER);
} }
@ -184,10 +186,10 @@ public:
} }
static PRBool IsTypeQuerySubcontainer(PRUint32 type) { static PRBool IsTypeQuerySubcontainer(PRUint32 type) {
// Tests containers that are inside queries that really belong to the query // Tests containers that are inside queries that really belong to the query
// itself, and is used when recursively updating a query. This include host // itself, and is used when recursively updating a query. This currently
// and day containers, but doesn't include other queries and folders. // includes only host containers, but may be extended to support things
return (type == nsINavHistoryResultNode::RESULT_TYPE_HOST || // like days or other criteria. It doesn't include other queries and folders.
type == nsINavHistoryResultNode::RESULT_TYPE_DAY); return (type == nsINavHistoryResultNode::RESULT_TYPE_HOST);
} }
PRBool IsQuerySubcontainer() { PRBool IsQuerySubcontainer() {
PRUint32 type; PRUint32 type;
@ -371,17 +373,31 @@ public:
NS_IMETHOD GetChild(PRUint32 index, nsINavHistoryResultNode **_retval) \ NS_IMETHOD GetChild(PRUint32 index, nsINavHistoryResultNode **_retval) \
{ return nsNavHistoryContainerResultNode::GetChild(index, _retval); } \ { return nsNavHistoryContainerResultNode::GetChild(index, _retval); } \
NS_IMETHOD GetChildrenReadOnly(PRBool *aChildrenReadOnly) \ NS_IMETHOD GetChildrenReadOnly(PRBool *aChildrenReadOnly) \
{ return nsNavHistoryContainerResultNode::GetChildrenReadOnly(aChildrenReadOnly); } { return nsNavHistoryContainerResultNode::GetChildrenReadOnly(aChildrenReadOnly); } \
NS_IMETHOD GetRemoteContainerType(nsACString& aRemoteContainerType) \
{ return nsNavHistoryContainerResultNode::GetRemoteContainerType(aRemoteContainerType); } \
NS_IMETHOD AppendURINode(const nsACString& aTitle, PRUint32 aAccessCount, PRTime aTime, const nsACString& aIconURI, const nsACString & aURI, nsINavHistoryURIResultNode **_retval) \
{ return nsNavHistoryContainerResultNode::AppendURINode(aTitle, aAccessCount, aTime, aIconURI, aURI, _retval); } \
NS_IMETHOD AppendVisitNode(const nsACString & aTitle, PRUint32 aAccessCount, PRTime aTime, const nsACString & aIconURI, const nsACString & aURI, PRInt64 aSession, nsINavHistoryVisitResultNode **_retval) \
{ return nsNavHistoryContainerResultNode::AppendVisitNode(aTitle, aAccessCount, aTime, aIconURI, aURI, aSession, _retval); } \
NS_IMETHOD AppendFullVisitNode(const nsACString & aTitle, PRUint32 aAccessCount, PRTime aTime, const nsACString & aIconURI, const nsACString & aURI, PRInt64 aSession, PRInt64 aVisitId, PRInt64 aReferringVisitId, PRInt32 aTransitionType, nsINavHistoryFullVisitResultNode **_retval) \
{ return nsNavHistoryContainerResultNode::AppendFullVisitNode(aTitle, aAccessCount, aTime, aIconURI, aURI, aSession, aVisitId, aReferringVisitId, aTransitionType, _retval); } \
NS_IMETHOD AppendContainerNode(const nsACString & aTitle, const nsACString & aIconURI, PRUint32 aContainerType, const nsACString & aRemoteContainerType, nsINavHistoryContainerResultNode **_retval) \
{ return nsNavHistoryContainerResultNode::AppendContainerNode(aTitle, aIconURI, aContainerType, aRemoteContainerType, _retval); } \
NS_IMETHOD AppendQueryNode(const nsACString & aTitle, const nsACString & aIconURI, const nsACString & aQueryString, nsINavHistoryQueryResultNode **_retval) \
{ return nsNavHistoryContainerResultNode::AppendQueryNode(aTitle, aIconURI, aQueryString, _retval); } \
NS_IMETHOD AppendFolderNode(PRInt64 aFolderId, nsINavHistoryFolderResultNode **_retval) \
{ return nsNavHistoryContainerResultNode::AppendFolderNode(aFolderId, _retval); } \
NS_IMETHOD ClearContents() \
{ return nsNavHistoryContainerResultNode::ClearContents(); }
class nsNavHistoryContainerResultNode : public nsNavHistoryResultNode, class nsNavHistoryContainerResultNode : public nsNavHistoryResultNode,
public nsINavHistoryContainerResultNode public nsINavHistoryContainerResultNode
{ {
public: public:
nsNavHistoryContainerResultNode(const nsACString& aTitle, PRUint32 aAccessCount,
PRTime aTime, const nsACString& aIconURI, PRUint32 aContainerType,
PRBool aReadOnly);
nsNavHistoryContainerResultNode(const nsACString& aTitle, nsNavHistoryContainerResultNode(const nsACString& aTitle,
const nsACString& aIconURI, PRUint32 aContainerType); const nsACString& aIconURI, PRUint32 aContainerType,
PRBool aReadOnly, const nsACString& aRemoteContainerType);
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_RESULTNODE_TO_BASE_EXCEPT_GETTYPE NS_FORWARD_RESULTNODE_TO_BASE_EXCEPT_GETTYPE
@ -397,7 +413,7 @@ public:
// overridded by descendents to populate // overridded by descendents to populate
virtual nsresult OpenContainer(); virtual nsresult OpenContainer();
virtual nsresult CloseContainer(); nsresult CloseContainer();
// this points to the result that owns this container. All containers have // this points to the result that owns this container. All containers have
// their result pointer set so we can quickly get to the result without having // their result pointer set so we can quickly get to the result without having
@ -405,8 +421,8 @@ public:
// for every leaf node to the result. // for every leaf node to the result.
nsNavHistoryResult* mResult; nsNavHistoryResult* mResult;
// for example, RESULT_TYPE_HOST or RESULT_TYPE_DAY. Query and Folder results // for example, RESULT_TYPE_HOST. Query and Folder results override GetType
// override GetType so this is not used, but is still kept in sync. // so this is not used, but is still kept in sync.
PRUint32 mContainerType; PRUint32 mContainerType;
// when there are children, this stores the open state in the tree // when there are children, this stores the open state in the tree
@ -418,6 +434,11 @@ public:
PRBool mChildrenReadOnly; PRBool mChildrenReadOnly;
// ID of a remote container interface that we can use GetService to get.
// This is empty to indicate there is no remote container service for this
// container (the common case).
nsCString mRemoteContainerType;
void FillStats(); void FillStats();
void ReverseUpdateStats(PRInt32 aAccessCountChange); void ReverseUpdateStats(PRInt32 aAccessCountChange);
@ -472,6 +493,8 @@ public:
nsresult ReplaceChildURIAt(PRUint32 aIndex, nsresult ReplaceChildURIAt(PRUint32 aIndex,
nsNavHistoryURIResultNode* aNode); nsNavHistoryURIResultNode* aNode);
nsresult RemoveChildAt(PRInt32 aIndex, PRBool aIsTemporary = PR_FALSE); nsresult RemoveChildAt(PRInt32 aIndex, PRBool aIsTemporary = PR_FALSE);
PRBool CanRemoteContainersChange();
}; };
@ -485,14 +508,12 @@ class nsNavHistoryQueryResultNode : public nsNavHistoryContainerResultNode,
public nsINavHistoryQueryResultNode public nsINavHistoryQueryResultNode
{ {
public: public:
nsNavHistoryQueryResultNode(nsNavHistoryQueryOptions* aGeneratingOptions, nsNavHistoryQueryResultNode(const nsACString& aTitle,
const nsACString& aTitle, PRUint32 aAccessCount, const nsACString& aIconURI,
PRTime aTime, const nsACString& aIconURI,
const nsACString& aQueryURI); const nsACString& aQueryURI);
nsNavHistoryQueryResultNode(nsNavHistoryQueryOptions* aGeneratingOptions, nsNavHistoryQueryResultNode(const nsACString& aTitle,
const nsACString& aTitle, PRUint32 aAccessCount, const nsACString& aIconURI,
PRTime aTime, const nsACString& aIconURI, const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsINavHistoryQuery** aQueries, PRUint32 aQueryCount,
nsNavHistoryQueryOptions* aOptions); nsNavHistoryQueryOptions* aOptions);
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
@ -511,13 +532,6 @@ public:
virtual void OnRemoving(); virtual void OnRemoving();
public: public:
// These are the options that caused this node to be generated. For just
// running queries directly, this node will be the root of the result and
// mGeneratingOptions will be the same as mOptions. When queries are in
// bookmark folders, this it the options structure used to generate the
// bookmarks tree. It tells us, for example, if we should expand ourselves.
nsCOMPtr<nsNavHistoryQueryOptions> mGeneratingOptions;
// this may be constructedlazily from mQueries and mOptions, call VerifyQueriesSerialized // this may be constructedlazily from mQueries and mOptions, call VerifyQueriesSerialized
// either this or mQueries/mOptions should be valid // either this or mQueries/mOptions should be valid
nsCString mQueryURI; nsCString mQueryURI;
@ -525,7 +539,7 @@ public:
// these may be constructed lazily from mQueryURI, call VerifyQueriesParsed // these may be constructed lazily from mQueryURI, call VerifyQueriesParsed
// either this or mQueryURI should be valid // either this or mQueryURI should be valid
nsCOMArray<nsINavHistoryQuery> mQueries; nsCOMArray<nsNavHistoryQuery> mQueries;
nsCOMPtr<nsNavHistoryQueryOptions> mOptions; nsCOMPtr<nsNavHistoryQueryOptions> mOptions;
PRUint32 mLiveUpdate; // one of QUERYUPDATE_* in nsNavHistory.h PRUint32 mLiveUpdate; // one of QUERYUPDATE_* in nsNavHistory.h
PRBool mHasSearchTerms; PRBool mHasSearchTerms;
@ -561,9 +575,10 @@ class nsNavHistoryFolderResultNode : public nsNavHistoryContainerResultNode,
public nsINavHistoryFolderResultNode public nsINavHistoryFolderResultNode
{ {
public: public:
nsNavHistoryFolderResultNode(const nsACString& aTitle, PRUint32 aAccessCount, nsNavHistoryFolderResultNode(const nsACString& aTitle,
PRTime aTime, nsNavHistoryQueryOptions* options, nsNavHistoryQueryOptions* options,
PRInt64 aFolderId); PRInt64 aFolderId,
const nsACString& aRemoteContainerType);
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_RESULTNODE_TO_BASE_EXCEPT_GETTYPE NS_FORWARD_RESULTNODE_TO_BASE_EXCEPT_GETTYPE