diff --git a/browser/components/places/content/menu.xml b/browser/components/places/content/menu.xml index 88ff40ad89fa..f6b4db052ce7 100755 --- a/browser/components/places/content/menu.xml +++ b/browser/components/places/content/menu.xml @@ -240,9 +240,15 @@ onItemMoved: function TB_O_onItemMoved(bookmark, folder, oldIndex, newIndex) { //this._self.init(); }, - onItemChanged: function TB_O_onItemChanged(bookmark, property) { + onItemChanged: function TB_O_onItemChanged(bookmark, property, value) { //this._self.init(); }, + onItemVisited: function TB_0_onItemVisited(bookmark, time) { + //this._self.init(); + }, + onItemReplaced: function TB_0_onItemReplaced(filder, item, newItem) { + // this._self.init(); + }, onFolderAdded: function TB_O_onFolderAdded(folder, parent, index) { //this._self.init(); }, diff --git a/browser/components/places/content/toolbar.xml b/browser/components/places/content/toolbar.xml index 83414a92ee86..7b2248d02a4d 100755 --- a/browser/components/places/content/toolbar.xml +++ b/browser/components/places/content/toolbar.xml @@ -282,9 +282,15 @@ onItemMoved: function TB_O_onItemMoved(bookmark, folder, oldIndex, newIndex) { this._self.init(); }, - onItemChanged: function TB_O_onItemChanged(bookmark, property) { + onItemChanged: function TB_O_onItemChanged(bookmark, property, value) { this._self.init(); }, + onItemVisited: function TB_0_onItemVisited(bookmark, time) { + //this._self.init(); + }, + onItemReplaced: function TB_0_onItemReplaced(filder, item, newItem) { + // this._self.init(); + }, onFolderAdded: function TB_O_onFolderAdded(folder, parent, index) { this._self.init(); }, diff --git a/browser/components/places/public/nsINavBookmarksService.idl b/browser/components/places/public/nsINavBookmarksService.idl index f896e4e9232c..d2a13fedf008 100644 --- a/browser/components/places/public/nsINavBookmarksService.idl +++ b/browser/components/places/public/nsINavBookmarksService.idl @@ -117,8 +117,25 @@ interface nsINavBookmarkObserver : nsISupports * * @param bookmark The bookmark which changed. * @param property The property which changed. + * + * property = "cleartime" (history was deleted, there is no last visit date): + * value = none + * property = "title": value = new title + * property = "favicon": value = new "moz-anno" URL of favicon image */ - void onItemChanged(in nsIURI bookmark, in ACString property); + void onItemChanged(in nsIURI bookmark, in ACString property, + in AString value); + + /** + * Notify that the item was visited. Normally in bookmarks we use the last + * visit date, and normally the time will be a new visit that will be more + * recent, but this is not guaranteed. You should check to see if it's + * actually more recent before using this new time. + * + * @see onItemChanged properth = "cleartime" for when all visit dates are + * deleted for the URI. + */ + void onItemVisited(in nsIURI bookmark, in PRTime time); /** * Notify this observer that a bookmark has been replaced. diff --git a/browser/components/places/public/nsINavHistoryService.idl b/browser/components/places/public/nsINavHistoryService.idl index fbd321acaf3a..1f69b01b824e 100644 --- a/browser/components/places/public/nsINavHistoryService.idl +++ b/browser/components/places/public/nsINavHistoryService.idl @@ -323,30 +323,43 @@ interface nsINavHistoryObserver : nsISupports void onEndUpdateBatch(); /** - * True requests that you want to get called for all updates, false if you - * don't necessarily care about which exact things changed during a batch - * update. If false, this will sometimes not call you for things in between - * onBeginUpdateBatch and onEndUpdateBatch. You'll still get the begin and - * end, so you'll know something changed. + * Called when a resource is visited. This is called the first time a + * resource (page, image, etc.) is seen as well as every subsequent time. * - * Lots of observers don't care about what changes, only that something - * changed so they can update their UI. This allows delete operations to - * avoid iterating over every item, and just doing a single bulk SQL DELETE - * command, which is much more efficient. + * Normally, transition types of TRANSITION_EMBED (corresponding to images in + * a page, for example) are not displayed in history results (unless + * includeHidden is set). Many observers can ignore _EMBED notifications + * (which will comprise the majority of visit notifications) to save work. * - * Note that you still might get called if you say false in some situations. - * This only skips certain time-consuming notifications if NO observers - * want the information. + * @param aVisitID ID of the visit that was just created. + * @param aTime Time of the visit + * @param aSessionID The ID of one connected sequence of visits. + * @param aReferringID The ID of the visit the user came from. 0 if empty. + * @param aTransitionType One of nsINavHistory.TRANSITION_* */ - readonly attribute boolean wantAllDetails; + void onVisit(in nsIURI aURI, in PRInt64 aVisitID, in PRTime aTime, + in PRInt64 aSessionID, in PRInt64 aReferringID, + in PRUint32 aTransitionType); /** - * A page has been added that was visited at a given time. It's very possible - * that this page already existed in history, but was just visited again. - * Note that adding a page can (but doesn't always) make the page unhidden. - * This happens implicitly and you won't get a separate change notification. + * Called whenever either the "real" title or the custom title of the page + * changed. BOTH TITLES ARE ALWAYS INCLUDED in this notification, even though + * only one will change at a time. Often, consumers will want to display the + * user title if it is available, and fall back to the page title (the one + * specified in the tag of the page). + * + * Note that there is a difference between an empty title and a NULL title. + * An empty string means that somebody specifically set the title to be + * nothing. NULL means nobody set it. From C++: use IsVoid() and SetIsVoid() + * to see whether an empty string is "null" or not (it will always be an + * empty string in either case). + * + * @param aUserTitleChanged Is true if the user title was the thing that was + * changed. If false, that means the "real" page + * title was changed instead. */ - void onAddURI(in nsIURI aURI, in PRTime aTime); + void onTitleChanged(in nsIURI aURI, in AString aPageTitle, + in AString aUserTitle, in PRBool aUserTitleChanged); /** * This page and all of its visits are being deleted. Note: the page may not @@ -369,9 +382,6 @@ interface nsINavHistoryObserver : nsISupports * A page has had some attribute on it changed. Note that for TYPED and * HIDDEN, the page may not necessarily have been added yet. */ - const PRUint32 ATTRIBUTE_TITLE = 0; // aString = new title - const PRUint32 ATTRIBUTE_HIDDEN = 1; // aString = empty - const PRUint32 ATTRIBUTE_TYPED = 2; // aString = empty const PRUint32 ATTRIBUTE_FAVICON = 3; // favicon updated, aString = favicon annotation URI void onPageChanged(in nsIURI aURI, in PRUint32 aWhat, in AString aValue); }; @@ -586,6 +596,29 @@ interface nsINavHistoryQueryOptions : nsISupports */ attribute boolean forceOriginalTitle; + /** + * Most items in history are marked "hidden." Only toplevel pages that the + * user sees in the URL bar are not hidden. Hidden things include the content + * of iframes and all images on web pages. Normally, you don't want these + * things. If you do, set this flag and you'll get all items, even hidden + * ones. + */ + attribute boolean includeHidden; + + /** + * This is the maximum number of results that you want. The query is exeucted, + * the results are sorted, and then the top 'maxResults' results are taken + * and returned. Set to 0 (the default) to get all results. + * + * THIS DOES NOT WORK IN CONJUNCTION WITH SORTING BY TITLE. This is because + * sorting by title requires us to sort after using locale-sensetive sorting + * (as opposed to letting the database do it for us). + * + * Instead, we get the result ordered by date, pick the maxResult most recent + * ones, and THEN sort by title. + */ + attribute PRUint32 maxResults; + /** * Creates a new options item with the same parameters of this one. */ diff --git a/browser/components/places/src/nsFaviconService.cpp b/browser/components/places/src/nsFaviconService.cpp index 11599c2d8fb3..106c2eff208b 100644 --- a/browser/components/places/src/nsFaviconService.cpp +++ b/browser/components/places/src/nsFaviconService.cpp @@ -358,6 +358,9 @@ nsFaviconService::SetAndLoadFaviconForPage(nsIURI* aPage, nsIURI* aFavicon, if (isDataURL) return NS_OK; + // This will associate the favicon URL with the page. It will not send favicon + // change notifications. That will happen from OnStopRequest so that we know + // we have data before wasting time sending out notifications. PRBool hasData; PRTime expiration; rv = SetFaviconUrlForPageInternal(aPage, aFavicon, &hasData, &expiration); @@ -685,6 +688,7 @@ FaviconLoadListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, if (mimeType.IsEmpty()) { // we can not handle favicons that do not have a recognisable MIME type + // FIXME: add to failed cache return NS_OK; } diff --git a/browser/components/places/src/nsNavBookmarks.cpp b/browser/components/places/src/nsNavBookmarks.cpp index 314ec48cf9f4..f04ba3d7ffed 100644 --- a/browser/components/places/src/nsNavBookmarks.cpp +++ b/browser/components/places/src/nsNavBookmarks.cpp @@ -838,6 +838,7 @@ nsNavBookmarks::RemoveFolderChildren(PRInt64 aFolder) buffer.AppendInt(aFolder); rv = dbConn->ExecuteSimpleSQL(buffer); NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; } @@ -1476,21 +1477,16 @@ nsNavBookmarks::OnEndUpdateBatch() } NS_IMETHODIMP -nsNavBookmarks::GetWantAllDetails(PRBool *aWant) -{ - *aWant = PR_FALSE; - return NS_OK; -} - -NS_IMETHODIMP -nsNavBookmarks::OnAddURI(nsIURI *aURI, PRTime aTime) +nsNavBookmarks::OnVisit(nsIURI *aURI, PRInt64 aVisitID, PRTime aTime, + PRInt64 aSessionID, PRInt64 aReferringID, + PRUint32 aTransitionType) { // If the page is bookmarked, we need to notify observers - PRBool bookmarked; + PRBool bookmarked = PR_FALSE; IsBookmarked(aURI, &bookmarked); if (bookmarked) { ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver, - OnItemChanged(aURI, NS_LITERAL_CSTRING("time"))) + OnItemVisited(aURI, aTime)) } return NS_OK; } @@ -1499,11 +1495,12 @@ NS_IMETHODIMP nsNavBookmarks::OnDeleteURI(nsIURI *aURI) { // If the page is bookmarked, we need to notify observers - PRBool bookmarked; + PRBool bookmarked = PR_FALSE; IsBookmarked(aURI, &bookmarked); if (bookmarked) { ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver, - OnItemChanged(aURI, NS_LITERAL_CSTRING("time"))) + OnItemChanged(aURI, NS_LITERAL_CSTRING("cleartime"), + EmptyString())) } return NS_OK; } @@ -1515,14 +1512,42 @@ nsNavBookmarks::OnClearHistory() return NS_OK; } +NS_IMETHODIMP +nsNavBookmarks::OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle, + const nsAString& aUserTitle, + PRBool aIsUserTitleChanged) +{ + PRBool bookmarked = PR_FALSE; + IsBookmarked(aURI, &bookmarked); + if (bookmarked) { + if (aUserTitle.IsVoid()) { + // use "real" title because the user title is NULL. Either the user title + // was "unset" or the page title changed. + ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver, + OnItemChanged(aURI, NS_LITERAL_CSTRING("title"), + aPageTitle)); + } else if (aIsUserTitleChanged) { + // there is a user title and it changed + ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver, + OnItemChanged(aURI, NS_LITERAL_CSTRING("title"), + aUserTitle)); + } + } + return NS_OK; +} + NS_IMETHODIMP nsNavBookmarks::OnPageChanged(nsIURI *aURI, PRUint32 aWhat, const nsAString &aValue) { - if (aWhat == ATTRIBUTE_TITLE) { - ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver, - OnItemChanged(aURI, NS_LITERAL_CSTRING("title"))) + PRBool bookmarked = PR_FALSE; + IsBookmarked(aURI, &bookmarked); + if (bookmarked) { + if (aWhat == nsINavHistoryObserver::ATTRIBUTE_FAVICON) { + ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver, + OnItemChanged(aURI, NS_LITERAL_CSTRING("favicon"), + aValue)); + } } - return NS_OK; } diff --git a/browser/components/places/src/nsNavBookmarks.h b/browser/components/places/src/nsNavBookmarks.h index 6570b4639f2d..4f60d97ca4f6 100644 --- a/browser/components/places/src/nsNavBookmarks.h +++ b/browser/components/places/src/nsNavBookmarks.h @@ -36,6 +36,9 @@ * * ***** END LICENSE BLOCK ***** */ +#ifndef nsNavBookmarks_h_ +#define nsNavBookmarks_h_ + #include "nsINavBookmarksService.h" #include "nsIStringBundle.h" #include "nsNavHistory.h" @@ -145,3 +148,5 @@ private: nsresult ImportBookmarksHTMLInternal(nsIURI* aURL, PRBool aAllowRootChanges); }; + +#endif // nsNavBookmarks_h_ diff --git a/browser/components/places/src/nsNavHistory.cpp b/browser/components/places/src/nsNavHistory.cpp index 05e28ce999f9..c90fd6312d8d 100644 --- a/browser/components/places/src/nsNavHistory.cpp +++ b/browser/components/places/src/nsNavHistory.cpp @@ -727,7 +727,9 @@ nsNavHistory::InternalAdd(nsIURI* aURI, nsIURI* aReferrer, PRInt64 aSessionID, NS_ENSURE_SUCCESS(rv, rv); } - rv = AddVisit(aReferrer, pageID, aVisitDate, aTransitionType); + PRInt64 visitID, referringID; + rv = AddVisit(aReferrer, pageID, aVisitDate, aTransitionType, + &visitID, &referringID); if (aPageID) *aPageID = pageID; @@ -748,7 +750,8 @@ nsNavHistory::InternalAdd(nsIURI* aURI, nsIURI* aReferrer, PRInt64 aSessionID, // case they need to use the DB transaction.Commit(); ENUMERATE_WEAKARRAY(mObservers, nsINavHistoryObserver, - OnAddURI(aURI, aVisitDate)) + OnVisit(aURI, visitID, aVisitDate, aSessionID, + referringID, aTransitionType)); return NS_OK; } @@ -832,9 +835,13 @@ nsNavHistory::InternalAddNewPage(nsIURI* aURI, const PRUnichar* aTitle, // page and use it as the parent. This will get messed up if one page is // open in more than one tab/window at once, but should be good enough for // most cases. +// +// The visit ID of the referrer that this function computes will be put +// into referringID. nsresult nsNavHistory::AddVisit(nsIURI* aReferrer, PRInt64 aPageID, - PRTime aTime, PRInt32 aTransitionType) + PRTime aTime, PRInt32 aTransitionType, + PRInt64* visitID, PRInt64 *referringID) { nsresult rv; PRInt64 fromStep = 0; @@ -858,6 +865,7 @@ nsresult nsNavHistory::AddVisit(nsIURI* aReferrer, PRInt64 aPageID, mLastSessionID ++; sessionID = mLastSessionID; } + *referringID = fromStep; mozStorageStatementScoper scoper(mDBInsertVisit); @@ -874,7 +882,8 @@ nsresult nsNavHistory::AddVisit(nsIURI* aReferrer, PRInt64 aPageID, rv = mDBInsertVisit->Execute(); NS_ENSURE_SUCCESS(rv, rv); - return NS_OK; + + return mDBConn->GetLastInsertRowID(visitID); } @@ -1121,16 +1130,7 @@ nsNavHistory::GetHasHistoryEntries(PRBool* aHasEntries) NS_IMETHODIMP nsNavHistory::SetPageUserTitle(nsIURI* aURI, const nsAString& aUserTitle) { - nsCOMPtr<mozIStorageStatement> statement; - nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( - "UPDATE moz_history SET user_title = ?2 WHERE url = ?1"), - getter_AddRefs(statement)); - NS_ENSURE_SUCCESS(rv, rv); - rv = BindStatementURI(statement, 0, aURI); - NS_ENSURE_SUCCESS(rv, rv); - rv = statement->BindStringParameter(1, aUserTitle); - NS_ENSURE_SUCCESS(rv, rv); - return statement->Execute(); + return SetPageTitleInternal(aURI, PR_TRUE, aUserTitle); } @@ -1311,7 +1311,7 @@ nsNavHistory::ExecuteQueries(nsINavHistoryQuery** aQueries, PRUint32 aQueryCount // conditions we want on all history queries, this just selects history // entries that are "active" NS_NAMED_LITERAL_CSTRING(commonConditions, - "h.visit_count > 0 AND h.hidden <> 1"); + "h.visit_count > 0 "); // Query string: Output parameters should be in order of kGetInfoIndex_* // WATCH OUT: nsNavBookmarks::Init also creates some statements that share @@ -1362,9 +1362,11 @@ nsNavHistory::ExecuteQueries(nsINavHistoryQuery** aQueries, PRUint32 aQueryCount } } queryString += commonConditions; + if (! options->IncludeHidden()) + queryString += NS_LITERAL_CSTRING("AND h.hidden <> 1 "); if (! conditions.IsEmpty()) { - queryString += NS_LITERAL_CSTRING(" AND (") + conditions + - NS_LITERAL_CSTRING(")"); + queryString += NS_LITERAL_CSTRING("AND (") + conditions + + NS_LITERAL_CSTRING(") "); } queryString += groupBy; @@ -1378,6 +1380,12 @@ nsNavHistory::ExecuteQueries(nsINavHistoryQuery** aQueries, PRUint32 aQueryCount case nsINavHistoryQueryOptions::SORT_BY_TITLE_DESCENDING: // the DB doesn't have indices on titles, and we need to do special // sorting for locales. This type of sorting is done only at the end. + // + // If the user wants few results, we limit them by date, necessitating + // a sort by date here (see the IDL definition for maxResults). We'll + // still do the official sort by title later. + if (options->MaxResults() > 0) + queryString += NS_LITERAL_CSTRING(" ORDER BY v.visit_date DESC"); break; case nsINavHistoryQueryOptions::SORT_BY_DATE_ASCENDING: queryString += NS_LITERAL_CSTRING(" ORDER BY v.visit_date ASC"); @@ -1400,6 +1408,14 @@ nsNavHistory::ExecuteQueries(nsINavHistoryQuery** aQueries, PRUint32 aQueryCount default: NS_NOTREACHED("Invalid sorting mode"); } + + // limit clause if there are 'maxResults' + if (options->MaxResults() > 0) { + queryString += NS_LITERAL_CSTRING(" LIMIT "); + queryString.AppendInt(options->MaxResults()); + queryString.AppendLiteral(" "); + } + printf("Constructed the query: %s\n", PromiseFlatCString(queryString).get()); // Put this in a transaction. Even though we are only reading, this will @@ -1728,20 +1744,6 @@ nsNavHistory::RemovePagesFromHost(const nsACString& aHost, PRBool aEntireDomain) revHostSlash.Truncate(revHostSlash.Length() - 1); revHostSlash.Append(NS_LITERAL_STRING("/")); - // see if we have to pass all deletes to the observers - PRBool hasObservers = PR_FALSE; - for (PRUint32 i = 0; i < mObservers.Length(); ++i) { - const nsCOMPtr<nsINavHistoryObserver> &obs = mObservers[i]; - if (obs) { - PRBool allDetails = PR_FALSE; - obs->GetWantAllDetails(&allDetails); - if (allDetails) { - hasObservers = PR_TRUE; - break; - } - } - } - // how we are selecting host names nsCAutoString conditionString; if (aEntireDomain) @@ -1756,31 +1758,31 @@ nsNavHistory::RemovePagesFromHost(const nsACString& aHost, PRBool aEntireDomain) // Note also that we *include* bookmarked items here. We generally want to // send out delete notifications for bookmarked items since in general, // deleting the visits (like we always do) will cause the item to disappear - // from history views. + // from history views. This will also cause all visit dates to be deleted, + // which affects many bookmark views nsCStringArray deletedURIs; nsCOMPtr<mozIStorageStatement> statement; - if (hasObservers) { - // create statement depending on delete type - rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( - "SELECT url FROM moz_history h ") + conditionString, - getter_AddRefs(statement)); - NS_ENSURE_SUCCESS(rv, rv); - rv = statement->BindStringParameter(0, revHostDot); - NS_ENSURE_SUCCESS(rv, rv); - if (aEntireDomain) { - rv = statement->BindStringParameter(1, revHostSlash); - NS_ENSURE_SUCCESS(rv, rv); - } - PRBool hasMore = PR_FALSE; - while ((statement->ExecuteStep(&hasMore) == NS_OK) && hasMore) { - nsCAutoString thisURIString; - if (NS_FAILED(statement->GetUTF8String(0, thisURIString)) || - thisURIString.IsEmpty()) - continue; // no URI - if (! deletedURIs.AppendCString(thisURIString)) - return NS_ERROR_OUT_OF_MEMORY; - } + // create statement depending on delete type + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "SELECT url FROM moz_history h ") + conditionString, + getter_AddRefs(statement)); + NS_ENSURE_SUCCESS(rv, rv); + rv = statement->BindStringParameter(0, revHostDot); + NS_ENSURE_SUCCESS(rv, rv); + if (aEntireDomain) { + rv = statement->BindStringParameter(1, revHostSlash); + NS_ENSURE_SUCCESS(rv, rv); + } + + PRBool hasMore = PR_FALSE; + while ((statement->ExecuteStep(&hasMore) == NS_OK) && hasMore) { + nsCAutoString thisURIString; + if (NS_FAILED(statement->GetUTF8String(0, thisURIString)) || + thisURIString.IsEmpty()) + continue; // no URI + if (! deletedURIs.AppendCString(thisURIString)) + return NS_ERROR_OUT_OF_MEMORY; } // first, delete all the visits @@ -1828,10 +1830,6 @@ nsNavHistory::RemovePagesFromHost(const nsACString& aHost, PRBool aEntireDomain) const nsCOMPtr<nsINavHistoryObserver> &obs = mObservers.ElementAt(observerIndex); if (! obs) continue; - PRBool allDetails = PR_FALSE; - obs->GetWantAllDetails(&allDetails); - if (! allDetails) - continue; // send it all the URIs for (PRInt32 i = 0; i < deletedURIs.Count(); i ++) { @@ -1872,6 +1870,8 @@ nsNavHistory::RemoveAllPages() NS_IMETHODIMP nsNavHistory::HidePage(nsIURI *aURI) { + return NS_ERROR_NOT_IMPLEMENTED; + /* // for speed to save disk accesses mozStorageTransaction transaction(mDBConn, PR_FALSE, mozIStorageConnection::TRANSACTION_EXCLUSIVE); @@ -1930,6 +1930,7 @@ nsNavHistory::HidePage(nsIURI *aURI) EmptyString())) return NS_OK; + */ } @@ -2041,45 +2042,33 @@ nsNavHistory::IsVisited(nsIURI *aURI, PRBool *_retval) // nsNavHistory::SetPageTitle +// +// This sets the page "real" title. Use nsINavHistory::SetPageUserTitle to +// set any user-defined title. NS_IMETHODIMP nsNavHistory::SetPageTitle(nsIURI *aURI, const nsAString & aTitle) { - nsresult rv; - - nsCOMPtr<mozIStorageStatement> dbModStatement; - rv = mDBConn->CreateStatement( - NS_LITERAL_CSTRING("UPDATE moz_history SET title = ?1 WHERE url = ?2"), - getter_AddRefs(dbModStatement)); - NS_ENSURE_SUCCESS(rv, rv); - - // title - dbModStatement->BindStringParameter(0, aTitle); - NS_ENSURE_SUCCESS(rv, rv); - - // url - rv = BindStatementURI(dbModStatement, 1, aURI); - NS_ENSURE_SUCCESS(rv, rv); - - rv = dbModStatement->Execute(); - NS_ENSURE_SUCCESS(rv, rv); - - // observers - ENUMERATE_WEAKARRAY(mObservers, nsINavHistoryObserver, - OnPageChanged(aURI, - nsINavHistoryObserver::ATTRIBUTE_TITLE, - aTitle)) - - return NS_OK; + return SetPageTitleInternal(aURI, PR_FALSE, aTitle); } + +// nsNavHistory::GetURIGeckoFlags +// +// FIXME: should we try to use annotations for this stuff? + NS_IMETHODIMP nsNavHistory::GetURIGeckoFlags(nsIURI* aURI, PRUint32* aResult) { return NS_ERROR_NOT_IMPLEMENTED; } + +// nsNavHistory::SetURIGeckoFlags +// +// FIXME: should we try to use annotations for this stuff? + NS_IMETHODIMP nsNavHistory::SetURIGeckoFlags(nsIURI* aURI, PRUint32 aFlags) { @@ -2687,6 +2676,111 @@ nsNavHistory::TitleForDomain(const nsString& domain, nsAString& aTitle) } +// nsNavHistory::SetPageTitleInternal +// +// Called to set either the user-defined title (aIsUserTitle=true) or the +// "real" page title (aIsUserTitle=false) for the given URI. Used as a +// backend for SetPageUserTitle and SetTitle +// +// Will fail for pages that are not in the DB. To clear the corresponding +// title, use aTitle.SetIsVoid(). Sending an empty string will save an +// empty string instead of clearing it. + +nsresult +nsNavHistory::SetPageTitleInternal(nsIURI* aURI, PRBool aIsUserTitle, + const nsAString& aTitle) +{ + nsresult rv; + + mozStorageTransaction transaction(mDBConn, PR_TRUE); + + // first, make sure the page exists, and fetch the old title (we need the one + // that isn't changing to send notifications) + nsAutoString title; + nsAutoString userTitle; + { // scope for statement + mozStorageStatementScoper infoScoper(mDBGetURLPageInfo); + rv = BindStatementURI(mDBGetURLPageInfo, 0, aURI); + NS_ENSURE_SUCCESS(rv, rv); + PRBool hasURL = PR_FALSE; + rv = mDBGetURLPageInfo->ExecuteStep(&hasURL); + NS_ENSURE_SUCCESS(rv, rv); + if (! hasURL) { + // we don't have the URL, give up + return NS_ERROR_NOT_AVAILABLE; + } + + // page title + PRInt32 titleType; + rv = mDBGetURLPageInfo->GetTypeOfIndex(kGetInfoIndex_Title, &titleType); + NS_ENSURE_SUCCESS(rv, rv); + if (titleType == mozIStorageValueArray::VALUE_TYPE_NULL) { + title.SetIsVoid(PR_TRUE); + } else { + rv = mDBGetURLPageInfo->GetString(kGetInfoIndex_Title, title); + NS_ENSURE_SUCCESS(rv, rv); + } + + // user title + rv = mDBGetURLPageInfo->GetTypeOfIndex(kGetInfoIndex_UserTitle, &titleType); + NS_ENSURE_SUCCESS(rv, rv); + if (titleType == mozIStorageValueArray::VALUE_TYPE_NULL) { + userTitle.SetIsVoid(PR_TRUE); + } else { + rv = mDBGetURLPageInfo->GetString(kGetInfoIndex_UserTitle, userTitle); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + // It is actually common to set the title to be the same thing it used to + // be. For example, going to any web page will always cause a title to be set, + // even though it will often be unchanged since the last visit. In these + // cases, we can avoid DB writing and (most significantly) observer overhead. + if (aIsUserTitle && aTitle.IsVoid() == userTitle.IsVoid() && + aTitle == userTitle) + return NS_OK; + if (! aIsUserTitle && aTitle.IsVoid() == title.IsVoid() && + aTitle == title) + return NS_OK; + + nsCOMPtr<mozIStorageStatement> dbModStatement; + if (aIsUserTitle) { + userTitle = aTitle; + rv = mDBConn->CreateStatement( + NS_LITERAL_CSTRING("UPDATE moz_history SET user_title = ?1 WHERE url = ?2"), + getter_AddRefs(dbModStatement)); + } else { + title = aTitle; + rv = mDBConn->CreateStatement( + NS_LITERAL_CSTRING("UPDATE moz_history SET title = ?1 WHERE url = ?2"), + getter_AddRefs(dbModStatement)); + } + NS_ENSURE_SUCCESS(rv, rv); + + // title + if (aTitle.IsVoid()) + dbModStatement->BindNullParameter(0); + else + dbModStatement->BindStringParameter(0, aTitle); + NS_ENSURE_SUCCESS(rv, rv); + + // url + rv = BindStatementURI(dbModStatement, 1, aURI); + NS_ENSURE_SUCCESS(rv, rv); + + rv = dbModStatement->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + transaction.Commit(); + + // observers (have to check first if it's bookmarked) + ENUMERATE_WEAKARRAY(mObservers, nsINavHistoryObserver, + OnTitleChanged(aURI, title, userTitle, aIsUserTitle)) + + return NS_OK; + +} + + // nsNavHistory::ImportFromMork // // FIXME: this is basically a hack, but it works. @@ -3499,6 +3593,34 @@ nsNavHistoryQueryOptions::SetForceOriginalTitle(PRBool aForce) return NS_OK; } +// includeHidden +NS_IMETHODIMP +nsNavHistoryQueryOptions::GetIncludeHidden(PRBool* aIncludeHidden) +{ + *aIncludeHidden = mIncludeHidden; + return NS_OK; +} +NS_IMETHODIMP +nsNavHistoryQueryOptions::SetIncludeHidden(PRBool aIncludeHidden) +{ + mIncludeHidden = aIncludeHidden; + return NS_OK; +} + +// maxResults +NS_IMETHODIMP +nsNavHistoryQueryOptions::GetMaxResults(PRUint32* aMaxResults) +{ + *aMaxResults = mMaxResults; + return NS_OK; +} +NS_IMETHODIMP +nsNavHistoryQueryOptions::SetMaxResults(PRUint32 aMaxResults) +{ + mMaxResults = aMaxResults; + return NS_OK; +} + NS_IMETHODIMP nsNavHistoryQueryOptions::Clone(nsINavHistoryQueryOptions** aResult) { diff --git a/browser/components/places/src/nsNavHistory.h b/browser/components/places/src/nsNavHistory.h index 919c9de345e2..b2461afcb44b 100644 --- a/browser/components/places/src/nsNavHistory.h +++ b/browser/components/places/src/nsNavHistory.h @@ -124,7 +124,9 @@ public: nsNavHistoryQueryOptions() : mSort(0), mResultType(0), mGroupCount(0), mGroupings(nsnull), mExpandPlaces(PR_FALSE), - mForceOriginalTitle(PR_FALSE) + mForceOriginalTitle(PR_FALSE), + mIncludeHidden(PR_FALSE), + mMaxResults(0) { } NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYQUERYOPTIONS_IID) @@ -139,6 +141,8 @@ public: } PRBool ExpandPlaces() const { return mExpandPlaces; } PRBool ForceOriginalTitle() const { return mForceOriginalTitle; } + PRBool IncludeHidden() const { return mIncludeHidden; } + PRUint32 MaxResults() const { return mMaxResults; } nsresult Clone(nsNavHistoryQueryOptions **aResult); @@ -153,6 +157,8 @@ private: PRInt32 *mGroupings; PRBool mExpandPlaces; PRBool mForceOriginalTitle; + PRBool mIncludeHidden; + PRUint32 mMaxResults; }; @@ -162,11 +168,16 @@ private: {0x54b61d38, 0x57c1, 0x11da, {0x95, 0xb8, 0x00, 0x13, 0x21, 0xc9, 0xf6, 0x9e}} // Declare methods for implementing nsINavBookmarkObserver -// and nsINavHistoryObserver (some methods overlap) +// and nsINavHistoryObserver (some methods, such as BeginUpdateBatch overlap) #define NS_DECL_BOOKMARK_HISTORY_OBSERVER \ NS_DECL_NSINAVBOOKMARKOBSERVER \ - NS_IMETHOD OnAddURI(nsIURI *aURI, PRTime aTime); \ + NS_IMETHOD OnVisit(nsIURI* aURI, PRInt64 aVisitID, PRTime aTime, \ + PRInt64 aSessionID, PRInt64 aReferringID, \ + PRUint32 aTransitionType); \ + NS_IMETHOD OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle, \ + const nsAString& aUserTitle, \ + PRBool aIsUserTitleChanged); \ NS_IMETHOD OnDeleteURI(nsIURI *aURI); \ NS_IMETHOD OnClearHistory(); \ NS_IMETHOD OnPageChanged(nsIURI *aURI, PRUint32 aWhat, \ @@ -201,7 +212,7 @@ public: // Non-XPCOM member accessors PRInt32 Type() const { return mType; } const nsCString& URL() const { return mUrl; } - virtual PRInt64 GetFolderId() const { return 0; } + virtual PRInt64 FolderId() const { return 0; } PRInt32 VisibleIndex() const { return mVisibleIndex; } void SetVisibleIndex(PRInt32 aIndex) { mVisibleIndex = aIndex; } PRInt32 IndentLevel() const { return mIndentLevel; } @@ -260,7 +271,7 @@ public: // nsINavHistoryResultNode methods NS_IMETHOD GetFolderId(PRInt64 *aId) - { *aId = nsNavHistoryQueryNode::GetFolderId(); return NS_OK; } + { *aId = nsNavHistoryQueryNode::FolderId(); return NS_OK; } NS_IMETHOD GetFolderType(nsAString& aFolderType); NS_IMETHOD GetQueries(PRUint32 *aQueryCount, nsINavHistoryQuery ***aQueries); @@ -271,7 +282,7 @@ public: // nsNavHistoryResultNode methods virtual nsresult BuildChildren(PRBool *aBuilt); - virtual PRInt64 GetFolderId() const; + virtual PRInt64 FolderId() const; virtual nsresult Rebuild(); protected: @@ -343,12 +354,20 @@ public: NS_DECL_NSINAVHISTORYRESULT NS_DECL_NSITREEVIEW NS_FORWARD_NSINAVBOOKMARKOBSERVER(nsNavHistoryQueryNode::) - NS_IMETHOD OnAddURI(nsIURI *aURI, PRTime aTime) - { return nsNavHistoryQueryNode::OnAddURI(aURI, aTime); } + NS_IMETHOD OnVisit(nsIURI* aURI, PRInt64 aVisitID, PRTime aTime, + PRInt64 aSessionID, PRInt64 aReferringID, + PRUint32 aTransitionType) + { return nsNavHistoryQueryNode::OnVisit(aURI, aVisitID, aTime, aSessionID, + aReferringID, aTransitionType); } NS_IMETHOD OnDeleteURI(nsIURI *aURI) { return nsNavHistoryQueryNode::OnDeleteURI(aURI); } NS_IMETHOD OnClearHistory() { return nsNavHistoryQueryNode::OnClearHistory(); } + NS_IMETHOD OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle, + const nsAString& aUserTitle, + PRBool aIsUserTitleChanged) + { return nsNavHistoryQueryNode::OnTitleChanged(aURI, aPageTitle, aUserTitle, + aIsUserTitleChanged); } NS_IMETHOD OnPageChanged(nsIURI *aURI, PRUint32 aWhat, const nsAString &aValue) { return nsNavHistoryQueryNode::OnPageChanged(aURI, aWhat, aValue); } @@ -613,7 +632,8 @@ protected: PRBool aHidden, PRBool aTyped, PRInt32 aVisitCount, PRInt64* aPageID); nsresult AddVisit(nsIURI* aReferrer, PRInt64 aPageID, PRTime aTime, - PRInt32 aTransitionType); + PRInt32 aTransitionType, PRInt64* aVisitID, + PRInt64* aReferringID); PRBool IsURIStringVisited(const nsACString& url); nsresult VacuumDB(PRTime aTimeAgo, PRBool aCompress); nsresult LoadPrefs(); @@ -640,6 +660,8 @@ protected: nsCOMArray<nsNavHistoryResultNode>* aResults); void TitleForDomain(const nsString& domain, nsAString& aTitle); + nsresult SetPageTitleInternal(nsIURI* aURI, PRBool aIsUserTitle, + const nsAString& aTitle); nsresult RecursiveGroup(const nsCOMArray<nsNavHistoryResultNode>& aSource, const PRInt32* aGroupingMode, PRUint32 aGroupCount, diff --git a/browser/components/places/src/nsNavHistoryQuery.cpp b/browser/components/places/src/nsNavHistoryQuery.cpp index 86b5a25f7a21..263fe40ee053 100644 --- a/browser/components/places/src/nsNavHistoryQuery.cpp +++ b/browser/components/places/src/nsNavHistoryQuery.cpp @@ -66,6 +66,8 @@ static nsresult ParseQueryTimeString(const nsCString& aString, #define QUERYKEY_RESULT_TYPE "type" #define QUERYKEY_EXPAND_PLACES "expandplaces" #define QUERYKEY_FORCE_ORIGINAL_TITLE "originalTitle" +#define QUERYKEY_INCLUDE_HIDDEN "includeHidden" +#define QUERYKEY_MAX_RESULTS "maxResults" inline void AppendAmpersandIfNonempty(nsACString& aString) { @@ -303,6 +305,19 @@ nsNavHistory::QueriesToQueryString(nsINavHistoryQuery **aQueries, aQueryString.AppendLiteral("=1"); } + // include hidden + if (options->IncludeHidden()) { + AppendAmpersandIfNonempty(aQueryString); + aQueryString += NS_LITERAL_CSTRING(QUERYKEY_INCLUDE_HIDDEN "=1"); + } + + // max results + if (options->MaxResults()) { + AppendAmpersandIfNonempty(aQueryString); + aQueryString += NS_LITERAL_CSTRING(QUERYKEY_MAX_RESULTS "="); + AppendInt32(aQueryString, options->MaxResults()); + } + return NS_OK; } @@ -615,6 +630,27 @@ nsNavHistory::TokensToQueries(const nsVoidArray& aTokens, NS_WARNING("Invalid value for forceOriginal"); } + } else if (kvp->key.EqualsLiteral(QUERYKEY_INCLUDE_HIDDEN)) { + + // include hidden + PRBool includeHidden; + rv = ParseQueryBooleanString(kvp->value, &includeHidden); + if (NS_SUCCEEDED(rv)) { + aOptions->SetIncludeHidden(includeHidden); + } else { + NS_WARNING("Invalid value for includeHidden"); + } + + } else if (kvp->key.EqualsLiteral(QUERYKEY_MAX_RESULTS)) { + + // max results + PRUint32 max = kvp->value.ToInteger((PRInt32*)&rv); + if (NS_SUCCEEDED(rv)) { + aOptions->SetMaxResults(max); + } else { + NS_WARNING("Max number of results is not a valid number, ignoring"); + } + } else { // unknown key diff --git a/browser/components/places/src/nsNavHistoryResult.cpp b/browser/components/places/src/nsNavHistoryResult.cpp index 7d19769a9578..cfb00ec002a7 100755 --- a/browser/components/places/src/nsNavHistoryResult.cpp +++ b/browser/components/places/src/nsNavHistoryResult.cpp @@ -87,8 +87,12 @@ inline PRInt32 CompareIntegers(PRUint32 a, PRUint32 b) NS_IMPL_ISUPPORTS2(nsNavHistoryResultNode, nsNavHistoryResultNode, nsINavHistoryResultNode) -nsNavHistoryResultNode::nsNavHistoryResultNode() : mID(0), mExpanded(PR_FALSE), - mParent(nsnull), mAccessCount(0), mTime(0) +nsNavHistoryResultNode::nsNavHistoryResultNode() : + mParent(nsnull), + mID(0), + mAccessCount(0), + mTime(0), + mExpanded(PR_FALSE) { } @@ -252,15 +256,23 @@ nsNavHistoryResultNode::OnItemMoved(nsIURI *aBookmark, PRInt64 aFolder, } -/* void onItemChanged(in nsIURI bookmark, in ACString property); */ +/* void onItemChanged(in nsIURI bookmark, in ACString property, in AString value); */ NS_IMETHODIMP nsNavHistoryResultNode::OnItemChanged(nsIURI *aBookmark, - const nsACString &aProperty) + const nsACString &aProperty, + const nsAString &aValue) { // We let OnPageChanged handle this case return NS_OK; } +/* void onItemVisited(in nsIURI bookmark, in PRTime time); */ +NS_IMETHODIMP +nsNavHistoryResultNode::OnItemVisited(nsIURI* aBookmark, PRTime aVisitTime) +{ + return NS_OK; +} + /* void onItemReplaced(in PRInt64 folder, in nsIURI item, in nsIURI newItem); */ NS_IMETHODIMP nsNavHistoryResultNode::OnItemReplaced(PRInt64 aFolder, @@ -306,9 +318,23 @@ nsNavHistoryResultNode::OnFolderChanged(PRInt64 aFolder, // nsINavHistoryObserver implementation -/* void onAddURI(in nsiURI aURI, in PRTime aTime); */ +/* void onVisit(in nsIURI aURI, in PRInt64 aVisitID, in PRTime aTime, + in PRInt64 aSessionID, in PRInt64 aReferringID, + in PRUint32 aTransitionType); */ NS_IMETHODIMP -nsNavHistoryResultNode::OnAddURI(nsIURI *aURI, PRTime aTime) +nsNavHistoryResultNode::OnVisit(nsIURI* aURI, PRInt64 aVisitID, PRTime aTime, + PRInt64 aSessionID, PRInt64 aReferringID, + PRUint32 aTransitionType) +{ + return NS_OK; +} + +/* void onTitleChanged(in nsIURI aURI, in AString aPageTitle, + in AString aUserTitle, in PRBool aUserTitleChanged); */ +NS_IMETHODIMP +nsNavHistoryResultNode::OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle, + const nsAString& aUserTitle, + PRBool aIsUserTitleChanged) { return NS_OK; } @@ -336,10 +362,17 @@ nsNavHistoryResultNode::OnPageChanged(nsIURI *aURI, // matches ours, and rebuild the row if so. nsCAutoString spec; aURI->GetSpec(spec); - if (spec.Equals(mUrl)) { - // TODO(bryner): only rebuild if aProperty is being shown - Rebuild(); + if (! spec.Equals(mUrl)) + return NS_OK; // not ours + + // TODO(bryner): only rebuild if aProperty is being shown + + if (aWhat == nsINavHistoryObserver::ATTRIBUTE_FAVICON) { + mFaviconURL = NS_ConvertUTF16toUTF8(aValue); + return NS_OK; } + + Rebuild(); return NS_OK; } @@ -408,7 +441,7 @@ nsNavHistoryQueryNode::ParseQueries() } PRInt64 -nsNavHistoryQueryNode::GetFolderId() const +nsNavHistoryQueryNode::FolderId() const { PRInt64 id; if (mQueryCount > 0) { @@ -540,7 +573,7 @@ nsNavHistoryQueryNode::GetWantAllDetails(PRBool *aResult) NS_IMETHODIMP nsNavHistoryQueryNode::GetChildrenReadOnly(PRBool *aResult) { - PRInt64 folderId = GetFolderId(); + PRInt64 folderId = FolderId(); if (folderId == 0) { *aResult = PR_TRUE; return NS_OK; @@ -588,7 +621,7 @@ nsNavHistoryQueryNode::OnItemAdded(nsIURI *aBookmark, PRInt64 aFolder, PRInt32 aIndex) { nsresult rv; - if (GetFolderId() == aFolder) { + if (FolderId() == aFolder) { // If we're not expanded, we can just invalidate our child list // and rebuild it the next time we're opened. if (!mExpanded) { @@ -625,7 +658,7 @@ NS_IMETHODIMP nsNavHistoryQueryNode::OnItemRemoved(nsIURI *aBookmark, PRInt64 aFolder, PRInt32 aIndex) { - if (GetFolderId() == aFolder) { + if (FolderId() == aFolder) { // If we're not expanded, we can just invalidate our child list // and rebuild it the next time we're opened. if (!mExpanded) { @@ -658,7 +691,7 @@ NS_IMETHODIMP nsNavHistoryQueryNode::OnItemMoved(nsIURI *aBookmark, PRInt64 aFolder, PRInt32 aOldIndex, PRInt32 aNewIndex) { - if (GetFolderId() == aFolder) { + if (FolderId() == aFolder) { // If we're not expanded, we can just invalidate our child list // and rebuild it the next time we're opened. if (!mExpanded) { @@ -690,12 +723,22 @@ nsNavHistoryQueryNode::OnItemMoved(nsIURI *aBookmark, PRInt64 aFolder, return NS_OK; } -/* void onItemChanged(in nsIURI bookmark, in ACString property); */ +/* void onItemChanged(in nsIURI bookmark, in ACString property, in AStirng value); */ NS_IMETHODIMP nsNavHistoryQueryNode::OnItemChanged(nsIURI *aBookmark, - const nsACString &aProperty) + const nsACString &aProperty, + const nsAString &aValue) +{ + // We let OnPageChanged handle this case. FIXME: This should be able to do + // all the work necessary from bookmark callbacks, so this needs to handle + // all bookmark cases. + return NS_OK; +} + +/* void onItemVisited(in nsIURI bookmark, in PRTime time); */ +NS_IMETHODIMP +nsNavHistoryQueryNode::OnItemVisited(nsIURI* aBookmark, PRTime aVisitTime) { - // We let OnPageChanged handle this case. return NS_OK; } @@ -705,7 +748,7 @@ nsNavHistoryQueryNode::OnItemReplaced(PRInt64 aFolder, nsIURI *aItem, nsIURI *aNewItem) { nsresult rv; - if (GetFolderId() == aFolder) { + if (FolderId() == aFolder) { // If we're not expanded, we can just invalidate our child list // and rebuild it the next time we're opened. if (!mExpanded) { @@ -750,7 +793,7 @@ nsNavHistoryQueryNode::OnFolderAdded(PRInt64 aFolder, PRInt64 aParent, PRInt32 aIndex) { nsresult rv; - if (GetFolderId() == aParent) { + if (FolderId() == aParent) { // If we're not expanded, we can just invalidate our child list // and rebuild it the next time we're opened. if (!mExpanded) { @@ -788,7 +831,7 @@ NS_IMETHODIMP nsNavHistoryQueryNode::OnFolderRemoved(PRInt64 aFolder, PRInt64 aParent, PRInt32 aIndex) { - if (GetFolderId() == aParent) { + if (FolderId() == aParent) { // If we're not expanded, we can just invalidate our child list // and rebuild it the next time we're opened. if (!mExpanded) { @@ -824,7 +867,7 @@ nsNavHistoryQueryNode::OnFolderMoved(PRInt64 aFolder, PRInt64 aNewParent, PRInt32 aNewIndex) { nsresult rv; - PRInt64 nodeFolder = GetFolderId(); + PRInt64 nodeFolder = FolderId(); if (aOldParent == aNewParent && aOldParent == nodeFolder) { // If we're not expanded, we can just invalidate our child list @@ -868,7 +911,7 @@ NS_IMETHODIMP nsNavHistoryQueryNode::OnFolderChanged(PRInt64 aFolder, const nsACString &aProperty) { - if (GetFolderId() == aFolder) { + if (FolderId() == aFolder) { // TODO(bryner): only rebuild if aProperty is being shown Rebuild(); } else { @@ -883,17 +926,30 @@ nsNavHistoryQueryNode::OnFolderChanged(PRInt64 aFolder, // nsINavHistoryObserver implementation -/* void onAddURI(in nsiURI aURI, in PRTime aTime); */ +/* void onVisit(in nsIURI aURI, in PRInt64 aVisitID, in PRTime aTime, + in PRInt64 aSessionID, in PRInt64 aReferringID, + in PRUint32 aTransitionType); */ NS_IMETHODIMP -nsNavHistoryQueryNode::OnAddURI(nsIURI *aURI, PRTime aTime) +nsNavHistoryQueryNode::OnVisit(nsIURI* aURI, PRInt64 aVisitID, PRTime aTime, + PRInt64 aSessionID, PRInt64 aReferringID, + PRUint32 aTransitionType) { nsresult rv; - if (GetFolderId() == 0) { + + // embedded transitions are not visible in queries unless you want to include + // hidden ones, so we can ignore these notifications (which comprise the bulk + // of history) + if (aTransitionType == nsINavHistoryService::TRANSITION_EMBED && + ! mOptions->IncludeHidden()) + return NS_OK; + + if (FolderId() == 0) { // We're a non-folder query, so we need to requery. return UpdateQuery(); } else { for (PRInt32 i = 0; i < mChildren.Count(); ++i) { - rv = mChildren[i]->OnAddURI(aURI, aTime); + rv = mChildren[i]->OnVisit(aURI, aVisitID, aTime, aSessionID, + aReferringID, aTransitionType); NS_ENSURE_SUCCESS(rv, rv); } } @@ -901,12 +957,37 @@ nsNavHistoryQueryNode::OnAddURI(nsIURI *aURI, PRTime aTime) return NS_OK; } +/* void onTitleChange */ +NS_IMETHODIMP +nsNavHistoryQueryNode::OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle, + const nsAString& aUserTitle, + PRBool aIsUserTitleChanged) +{ + nsresult rv; + PRInt64 folder = nsNavHistoryQueryNode::FolderId(); + if (folder == 0) { + // If we're a query node (other than a folder), we need to re-execute + // our queries in case aBookmark should be added/removed from the + // results. + return UpdateQuery(); + } else { + // We're a bookmark folder. Run through our children and notify them. + for (PRInt32 i = 0; i < mChildren.Count(); ++i) { + rv = mChildren[i]->OnTitleChanged(aURI, aPageTitle, aUserTitle, aIsUserTitleChanged); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + return NS_OK; +} + + /* void onDeleteURI(in nsIURI aURI); */ NS_IMETHODIMP nsNavHistoryQueryNode::OnDeleteURI(nsIURI *aURI) { nsresult rv; - if (GetFolderId() == 0) { + if (FolderId() == 0) { // We're a non-folder query, so we need to requery. return UpdateQuery(); } else { @@ -924,7 +1005,7 @@ NS_IMETHODIMP nsNavHistoryQueryNode::OnClearHistory() { nsresult rv; - if (GetFolderId() == 0) { + if (FolderId() == 0) { // We're a non-folder query, so we need to requery. return UpdateQuery(); } else { @@ -943,7 +1024,7 @@ nsNavHistoryQueryNode::OnPageChanged(nsIURI *aURI, PRUint32 aWhat, const nsAString &aValue) { nsresult rv; - PRInt64 folder = nsNavHistoryQueryNode::GetFolderId(); + PRInt64 folder = nsNavHistoryQueryNode::FolderId(); if (folder == 0) { // If we're a query node (other than a folder), we need to re-execute // our queries in case aBookmark should be added/removed from the @@ -963,7 +1044,7 @@ nsNavHistoryQueryNode::OnPageChanged(nsIURI *aURI, nsresult nsNavHistoryQueryNode::Rebuild() { - PRInt64 folderId = GetFolderId(); + PRInt64 folderId = FolderId(); if (folderId != 0) { nsNavBookmarks *bookmarks = nsNavBookmarks::GetBookmarksService(); return bookmarks->FillFolderNode(folderId, this); @@ -1773,7 +1854,7 @@ NS_IMETHODIMP nsNavHistoryResult::IsContainer(PRInt32 index, PRBool *_retval) nsNavHistoryResultNode *node = VisibleElementAt(index); *_retval = (node->mChildren.Count() > 0 || (node->mType == nsINavHistoryResult::RESULT_TYPE_QUERY && - (node->GetFolderId() > 0 || + (node->FolderId() > 0 || (mOptions && mOptions->ExpandPlaces())))); return NS_OK; }