1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/places/nsNavBookmarks.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,461 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef nsNavBookmarks_h_ 1.10 +#define nsNavBookmarks_h_ 1.11 + 1.12 +#include "nsINavBookmarksService.h" 1.13 +#include "nsIAnnotationService.h" 1.14 +#include "nsITransaction.h" 1.15 +#include "nsNavHistory.h" 1.16 +#include "nsToolkitCompsCID.h" 1.17 +#include "nsCategoryCache.h" 1.18 +#include "nsTHashtable.h" 1.19 +#include "nsWeakReference.h" 1.20 +#include "mozilla/Attributes.h" 1.21 +#include "prtime.h" 1.22 + 1.23 +class nsNavBookmarks; 1.24 +class nsIOutputStream; 1.25 + 1.26 +namespace mozilla { 1.27 +namespace places { 1.28 + 1.29 + enum BookmarkStatementId { 1.30 + DB_FIND_REDIRECTED_BOOKMARK = 0 1.31 + , DB_GET_BOOKMARKS_FOR_URI 1.32 + }; 1.33 + 1.34 + struct BookmarkData { 1.35 + int64_t id; 1.36 + nsCString url; 1.37 + nsCString title; 1.38 + int32_t position; 1.39 + int64_t placeId; 1.40 + int64_t parentId; 1.41 + int64_t grandParentId; 1.42 + int32_t type; 1.43 + nsCString serviceCID; 1.44 + PRTime dateAdded; 1.45 + PRTime lastModified; 1.46 + nsCString guid; 1.47 + nsCString parentGuid; 1.48 + }; 1.49 + 1.50 + struct ItemVisitData { 1.51 + BookmarkData bookmark; 1.52 + int64_t visitId; 1.53 + uint32_t transitionType; 1.54 + PRTime time; 1.55 + }; 1.56 + 1.57 + struct ItemChangeData { 1.58 + BookmarkData bookmark; 1.59 + nsCString property; 1.60 + bool isAnnotation; 1.61 + nsCString newValue; 1.62 + }; 1.63 + 1.64 + typedef void (nsNavBookmarks::*ItemVisitMethod)(const ItemVisitData&); 1.65 + typedef void (nsNavBookmarks::*ItemChangeMethod)(const ItemChangeData&); 1.66 + 1.67 + class BookmarkKeyClass : public nsTrimInt64HashKey 1.68 + { 1.69 + public: 1.70 + BookmarkKeyClass(const int64_t* aItemId) 1.71 + : nsTrimInt64HashKey(aItemId) 1.72 + , creationTime(PR_Now()) 1.73 + { 1.74 + } 1.75 + BookmarkKeyClass(const BookmarkKeyClass& aOther) 1.76 + : nsTrimInt64HashKey(aOther) 1.77 + , creationTime(PR_Now()) 1.78 + { 1.79 + NS_NOTREACHED("Do not call me!"); 1.80 + } 1.81 + BookmarkData bookmark; 1.82 + PRTime creationTime; 1.83 + }; 1.84 + 1.85 + enum BookmarkDate { 1.86 + DATE_ADDED = 0 1.87 + , LAST_MODIFIED 1.88 + }; 1.89 + 1.90 +} // namespace places 1.91 +} // namespace mozilla 1.92 + 1.93 +class nsNavBookmarks MOZ_FINAL : public nsINavBookmarksService 1.94 + , public nsINavHistoryObserver 1.95 + , public nsIAnnotationObserver 1.96 + , public nsIObserver 1.97 + , public nsSupportsWeakReference 1.98 +{ 1.99 +public: 1.100 + NS_DECL_ISUPPORTS 1.101 + NS_DECL_NSINAVBOOKMARKSSERVICE 1.102 + NS_DECL_NSINAVHISTORYOBSERVER 1.103 + NS_DECL_NSIANNOTATIONOBSERVER 1.104 + NS_DECL_NSIOBSERVER 1.105 + 1.106 + nsNavBookmarks(); 1.107 + 1.108 + /** 1.109 + * Obtains the service's object. 1.110 + */ 1.111 + static already_AddRefed<nsNavBookmarks> GetSingleton(); 1.112 + 1.113 + /** 1.114 + * Initializes the service's object. This should only be called once. 1.115 + */ 1.116 + nsresult Init(); 1.117 + 1.118 + static nsNavBookmarks* GetBookmarksService() { 1.119 + if (!gBookmarksService) { 1.120 + nsCOMPtr<nsINavBookmarksService> serv = 1.121 + do_GetService(NS_NAVBOOKMARKSSERVICE_CONTRACTID); 1.122 + NS_ENSURE_TRUE(serv, nullptr); 1.123 + NS_ASSERTION(gBookmarksService, 1.124 + "Should have static instance pointer now"); 1.125 + } 1.126 + return gBookmarksService; 1.127 + } 1.128 + 1.129 + typedef mozilla::places::BookmarkData BookmarkData; 1.130 + typedef mozilla::places::BookmarkKeyClass BookmarkKeyClass; 1.131 + typedef mozilla::places::ItemVisitData ItemVisitData; 1.132 + typedef mozilla::places::ItemChangeData ItemChangeData; 1.133 + typedef mozilla::places::BookmarkStatementId BookmarkStatementId; 1.134 + 1.135 + nsresult ResultNodeForContainer(int64_t aID, 1.136 + nsNavHistoryQueryOptions* aOptions, 1.137 + nsNavHistoryResultNode** aNode); 1.138 + 1.139 + // Find all the children of a folder, using the given query and options. 1.140 + // For each child, a ResultNode is created and added to |children|. 1.141 + // The results are ordered by folder position. 1.142 + nsresult QueryFolderChildren(int64_t aFolderId, 1.143 + nsNavHistoryQueryOptions* aOptions, 1.144 + nsCOMArray<nsNavHistoryResultNode>* children); 1.145 + 1.146 + /** 1.147 + * Turns aRow into a node and appends it to aChildren if it is appropriate to 1.148 + * do so. 1.149 + * 1.150 + * @param aRow 1.151 + * A Storage statement (in the case of synchronous execution) or row of 1.152 + * a result set (in the case of asynchronous execution). 1.153 + * @param aOptions 1.154 + * The options of the parent folder node. 1.155 + * @param aChildren 1.156 + * The children of the parent folder node. 1.157 + * @param aCurrentIndex 1.158 + * The index of aRow within the results. When called on the first row, 1.159 + * this should be set to -1. 1.160 + */ 1.161 + nsresult ProcessFolderNodeRow(mozIStorageValueArray* aRow, 1.162 + nsNavHistoryQueryOptions* aOptions, 1.163 + nsCOMArray<nsNavHistoryResultNode>* aChildren, 1.164 + int32_t& aCurrentIndex); 1.165 + 1.166 + /** 1.167 + * The async version of QueryFolderChildren. 1.168 + * 1.169 + * @param aNode 1.170 + * The folder node that will receive the children. 1.171 + * @param _pendingStmt 1.172 + * The Storage pending statement that will be used to control async 1.173 + * execution. 1.174 + */ 1.175 + nsresult QueryFolderChildrenAsync(nsNavHistoryFolderResultNode* aNode, 1.176 + int64_t aFolderId, 1.177 + mozIStoragePendingStatement** _pendingStmt); 1.178 + 1.179 + /** 1.180 + * @return index of the new folder in aIndex, whether it was passed in or 1.181 + * generated by autoincrement. 1.182 + * 1.183 + * @note If aFolder is -1, uses the autoincrement id for folder index. 1.184 + * @note aTitle will be truncated to TITLE_LENGTH_MAX 1.185 + */ 1.186 + nsresult CreateContainerWithID(int64_t aId, int64_t aParent, 1.187 + const nsACString& aTitle, 1.188 + bool aIsBookmarkFolder, 1.189 + int32_t* aIndex, 1.190 + const nsACString& aGUID, 1.191 + int64_t* aNewFolder); 1.192 + 1.193 + /** 1.194 + * Fetches information about the specified id from the database. 1.195 + * 1.196 + * @param aItemId 1.197 + * Id of the item to fetch information for. 1.198 + * @param aBookmark 1.199 + * BookmarkData to store the information. 1.200 + */ 1.201 + nsresult FetchItemInfo(int64_t aItemId, 1.202 + BookmarkData& _bookmark); 1.203 + 1.204 + /** 1.205 + * Notifies that a bookmark has been visited. 1.206 + * 1.207 + * @param aItemId 1.208 + * The visited item id. 1.209 + * @param aData 1.210 + * Details about the new visit. 1.211 + */ 1.212 + void NotifyItemVisited(const ItemVisitData& aData); 1.213 + 1.214 + /** 1.215 + * Notifies that a bookmark has changed. 1.216 + * 1.217 + * @param aItemId 1.218 + * The changed item id. 1.219 + * @param aData 1.220 + * Details about the change. 1.221 + */ 1.222 + void NotifyItemChanged(const ItemChangeData& aData); 1.223 + 1.224 + /** 1.225 + * Recursively builds an array of descendant folders inside a given folder. 1.226 + * 1.227 + * @param aFolderId 1.228 + * The folder to fetch descendants from. 1.229 + * @param aDescendantFoldersArray 1.230 + * Output array to put descendant folders id. 1.231 + */ 1.232 + nsresult GetDescendantFolders(int64_t aFolderId, 1.233 + nsTArray<int64_t>& aDescendantFoldersArray); 1.234 + 1.235 +private: 1.236 + static nsNavBookmarks* gBookmarksService; 1.237 + 1.238 + ~nsNavBookmarks(); 1.239 + 1.240 + /** 1.241 + * Locates the root items in the bookmarks folder hierarchy assigning folder 1.242 + * ids to the root properties that are exposed through the service interface. 1.243 + */ 1.244 + nsresult ReadRoots(); 1.245 + 1.246 + nsresult AdjustIndices(int64_t aFolder, 1.247 + int32_t aStartIndex, 1.248 + int32_t aEndIndex, 1.249 + int32_t aDelta); 1.250 + 1.251 + /** 1.252 + * Fetches properties of a folder. 1.253 + * 1.254 + * @param aFolderId 1.255 + * Folder to count children for. 1.256 + * @param _folderCount 1.257 + * Number of children in the folder. 1.258 + * @param _guid 1.259 + * Unique id of the folder. 1.260 + * @param _parentId 1.261 + * Id of the parent of the folder. 1.262 + * 1.263 + * @throws If folder does not exist. 1.264 + */ 1.265 + nsresult FetchFolderInfo(int64_t aFolderId, 1.266 + int32_t* _folderCount, 1.267 + nsACString& _guid, 1.268 + int64_t* _parentId); 1.269 + 1.270 + nsresult GetLastChildId(int64_t aFolder, int64_t* aItemId); 1.271 + 1.272 + /** 1.273 + * This is an handle to the Places database. 1.274 + */ 1.275 + nsRefPtr<mozilla::places::Database> mDB; 1.276 + 1.277 + int32_t mItemCount; 1.278 + 1.279 + nsMaybeWeakPtrArray<nsINavBookmarkObserver> mObservers; 1.280 + 1.281 + int64_t mRoot; 1.282 + int64_t mMenuRoot; 1.283 + int64_t mTagsRoot; 1.284 + int64_t mUnfiledRoot; 1.285 + int64_t mToolbarRoot; 1.286 + 1.287 + inline bool IsRoot(int64_t aFolderId) { 1.288 + return aFolderId == mRoot || aFolderId == mMenuRoot || 1.289 + aFolderId == mTagsRoot || aFolderId == mUnfiledRoot || 1.290 + aFolderId == mToolbarRoot; 1.291 + } 1.292 + 1.293 + nsresult IsBookmarkedInDatabase(int64_t aBookmarkID, bool* aIsBookmarked); 1.294 + 1.295 + nsresult SetItemDateInternal(enum mozilla::places::BookmarkDate aDateType, 1.296 + int64_t aItemId, 1.297 + PRTime aValue); 1.298 + 1.299 + // Recursive method to build an array of folder's children 1.300 + nsresult GetDescendantChildren(int64_t aFolderId, 1.301 + const nsACString& aFolderGuid, 1.302 + int64_t aGrandParentId, 1.303 + nsTArray<BookmarkData>& aFolderChildrenArray); 1.304 + 1.305 + enum ItemType { 1.306 + BOOKMARK = TYPE_BOOKMARK, 1.307 + FOLDER = TYPE_FOLDER, 1.308 + SEPARATOR = TYPE_SEPARATOR, 1.309 + }; 1.310 + 1.311 + /** 1.312 + * Helper to insert a bookmark in the database. 1.313 + * 1.314 + * @param aItemId 1.315 + * The itemId to insert, pass -1 to generate a new one. 1.316 + * @param aPlaceId 1.317 + * The placeId to which this bookmark refers to, pass nullptr for 1.318 + * items that don't refer to an URI (eg. folders, separators, ...). 1.319 + * @param aItemType 1.320 + * The type of the new bookmark, see TYPE_* constants. 1.321 + * @param aParentId 1.322 + * The itemId of the parent folder. 1.323 + * @param aIndex 1.324 + * The position inside the parent folder. 1.325 + * @param aTitle 1.326 + * The title for the new bookmark. 1.327 + * Pass a void string to set a NULL title. 1.328 + * @param aDateAdded 1.329 + * The date for the insertion. 1.330 + * @param [optional] aLastModified 1.331 + * The last modified date for the insertion. 1.332 + * It defaults to aDateAdded. 1.333 + * 1.334 + * @return The new item id that has been inserted. 1.335 + * 1.336 + * @note This will also update last modified date of the parent folder. 1.337 + */ 1.338 + nsresult InsertBookmarkInDB(int64_t aPlaceId, 1.339 + enum ItemType aItemType, 1.340 + int64_t aParentId, 1.341 + int32_t aIndex, 1.342 + const nsACString& aTitle, 1.343 + PRTime aDateAdded, 1.344 + PRTime aLastModified, 1.345 + const nsACString& aParentGuid, 1.346 + int64_t aGrandParentId, 1.347 + nsIURI* aURI, 1.348 + int64_t* _itemId, 1.349 + nsACString& _guid); 1.350 + 1.351 + /** 1.352 + * TArray version of getBookmarksIdForURI for ease of use in C++ code. 1.353 + * Pass in a reference to a TArray; it will get filled with the 1.354 + * resulting list of bookmark IDs. 1.355 + * 1.356 + * @param aURI 1.357 + * URI to get bookmarks for. 1.358 + * @param aResult 1.359 + * Array of bookmark ids. 1.360 + * @param aSkipTags 1.361 + * If true ids of tags-as-bookmarks entries will be excluded. 1.362 + */ 1.363 + nsresult GetBookmarkIdsForURITArray(nsIURI* aURI, 1.364 + nsTArray<int64_t>& aResult, 1.365 + bool aSkipTags); 1.366 + 1.367 + nsresult GetBookmarksForURI(nsIURI* aURI, 1.368 + nsTArray<BookmarkData>& _bookmarks); 1.369 + 1.370 + int64_t RecursiveFindRedirectedBookmark(int64_t aPlaceId); 1.371 + 1.372 + static const int32_t kGetChildrenIndex_Position; 1.373 + static const int32_t kGetChildrenIndex_Type; 1.374 + static const int32_t kGetChildrenIndex_PlaceID; 1.375 + static const int32_t kGetChildrenIndex_Guid; 1.376 + 1.377 + class RemoveFolderTransaction MOZ_FINAL : public nsITransaction { 1.378 + public: 1.379 + RemoveFolderTransaction(int64_t aID) : mID(aID) {} 1.380 + 1.381 + NS_DECL_ISUPPORTS 1.382 + 1.383 + NS_IMETHOD DoTransaction() { 1.384 + nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService(); 1.385 + NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY); 1.386 + BookmarkData folder; 1.387 + nsresult rv = bookmarks->FetchItemInfo(mID, folder); 1.388 + // TODO (Bug 656935): store the BookmarkData struct instead. 1.389 + mParent = folder.parentId; 1.390 + mIndex = folder.position; 1.391 + 1.392 + rv = bookmarks->GetItemTitle(mID, mTitle); 1.393 + NS_ENSURE_SUCCESS(rv, rv); 1.394 + 1.395 + return bookmarks->RemoveItem(mID); 1.396 + } 1.397 + 1.398 + NS_IMETHOD UndoTransaction() { 1.399 + nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService(); 1.400 + NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY); 1.401 + int64_t newFolder; 1.402 + return bookmarks->CreateContainerWithID(mID, mParent, mTitle, true, 1.403 + &mIndex, EmptyCString(), &newFolder); 1.404 + } 1.405 + 1.406 + NS_IMETHOD RedoTransaction() { 1.407 + return DoTransaction(); 1.408 + } 1.409 + 1.410 + NS_IMETHOD GetIsTransient(bool* aResult) { 1.411 + *aResult = false; 1.412 + return NS_OK; 1.413 + } 1.414 + 1.415 + NS_IMETHOD Merge(nsITransaction* aTransaction, bool* aResult) { 1.416 + *aResult = false; 1.417 + return NS_OK; 1.418 + } 1.419 + 1.420 + private: 1.421 + int64_t mID; 1.422 + int64_t mParent; 1.423 + nsCString mTitle; 1.424 + int32_t mIndex; 1.425 + }; 1.426 + 1.427 + // Used to enable and disable the observer notifications. 1.428 + bool mCanNotify; 1.429 + nsCategoryCache<nsINavBookmarkObserver> mCacheObservers; 1.430 + 1.431 + // Tracks whether we are in batch mode. 1.432 + // Note: this is only tracking bookmarks batches, not history ones. 1.433 + bool mBatching; 1.434 + 1.435 + /** 1.436 + * Always call EnsureKeywordsHash() and check it for errors before actually 1.437 + * using the hash. Internal keyword methods are already doing that. 1.438 + */ 1.439 + nsresult EnsureKeywordsHash(); 1.440 + nsDataHashtable<nsTrimInt64HashKey, nsString> mBookmarkToKeywordHash; 1.441 + bool mBookmarkToKeywordHashInitialized; 1.442 + 1.443 + /** 1.444 + * This function must be called every time a bookmark is removed. 1.445 + * 1.446 + * @param aURI 1.447 + * Uri to test. 1.448 + */ 1.449 + nsresult UpdateKeywordsHashForRemovedBookmark(int64_t aItemId); 1.450 + 1.451 + /** 1.452 + * Cache for the last fetched BookmarkData entries. 1.453 + * This is used to speed up repeated requests to the same item id. 1.454 + */ 1.455 + nsTHashtable<BookmarkKeyClass> mRecentBookmarksCache; 1.456 + 1.457 + /** 1.458 + * Tracks bookmarks in the cache critical path. Items should not be 1.459 + * added to the cache till they are removed from this hash. 1.460 + */ 1.461 + nsTHashtable<nsTrimInt64HashKey> mUncachableBookmarks; 1.462 +}; 1.463 + 1.464 +#endif // nsNavBookmarks_h_