|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef nsNavBookmarks_h_ |
|
7 #define nsNavBookmarks_h_ |
|
8 |
|
9 #include "nsINavBookmarksService.h" |
|
10 #include "nsIAnnotationService.h" |
|
11 #include "nsITransaction.h" |
|
12 #include "nsNavHistory.h" |
|
13 #include "nsToolkitCompsCID.h" |
|
14 #include "nsCategoryCache.h" |
|
15 #include "nsTHashtable.h" |
|
16 #include "nsWeakReference.h" |
|
17 #include "mozilla/Attributes.h" |
|
18 #include "prtime.h" |
|
19 |
|
20 class nsNavBookmarks; |
|
21 class nsIOutputStream; |
|
22 |
|
23 namespace mozilla { |
|
24 namespace places { |
|
25 |
|
26 enum BookmarkStatementId { |
|
27 DB_FIND_REDIRECTED_BOOKMARK = 0 |
|
28 , DB_GET_BOOKMARKS_FOR_URI |
|
29 }; |
|
30 |
|
31 struct BookmarkData { |
|
32 int64_t id; |
|
33 nsCString url; |
|
34 nsCString title; |
|
35 int32_t position; |
|
36 int64_t placeId; |
|
37 int64_t parentId; |
|
38 int64_t grandParentId; |
|
39 int32_t type; |
|
40 nsCString serviceCID; |
|
41 PRTime dateAdded; |
|
42 PRTime lastModified; |
|
43 nsCString guid; |
|
44 nsCString parentGuid; |
|
45 }; |
|
46 |
|
47 struct ItemVisitData { |
|
48 BookmarkData bookmark; |
|
49 int64_t visitId; |
|
50 uint32_t transitionType; |
|
51 PRTime time; |
|
52 }; |
|
53 |
|
54 struct ItemChangeData { |
|
55 BookmarkData bookmark; |
|
56 nsCString property; |
|
57 bool isAnnotation; |
|
58 nsCString newValue; |
|
59 }; |
|
60 |
|
61 typedef void (nsNavBookmarks::*ItemVisitMethod)(const ItemVisitData&); |
|
62 typedef void (nsNavBookmarks::*ItemChangeMethod)(const ItemChangeData&); |
|
63 |
|
64 class BookmarkKeyClass : public nsTrimInt64HashKey |
|
65 { |
|
66 public: |
|
67 BookmarkKeyClass(const int64_t* aItemId) |
|
68 : nsTrimInt64HashKey(aItemId) |
|
69 , creationTime(PR_Now()) |
|
70 { |
|
71 } |
|
72 BookmarkKeyClass(const BookmarkKeyClass& aOther) |
|
73 : nsTrimInt64HashKey(aOther) |
|
74 , creationTime(PR_Now()) |
|
75 { |
|
76 NS_NOTREACHED("Do not call me!"); |
|
77 } |
|
78 BookmarkData bookmark; |
|
79 PRTime creationTime; |
|
80 }; |
|
81 |
|
82 enum BookmarkDate { |
|
83 DATE_ADDED = 0 |
|
84 , LAST_MODIFIED |
|
85 }; |
|
86 |
|
87 } // namespace places |
|
88 } // namespace mozilla |
|
89 |
|
90 class nsNavBookmarks MOZ_FINAL : public nsINavBookmarksService |
|
91 , public nsINavHistoryObserver |
|
92 , public nsIAnnotationObserver |
|
93 , public nsIObserver |
|
94 , public nsSupportsWeakReference |
|
95 { |
|
96 public: |
|
97 NS_DECL_ISUPPORTS |
|
98 NS_DECL_NSINAVBOOKMARKSSERVICE |
|
99 NS_DECL_NSINAVHISTORYOBSERVER |
|
100 NS_DECL_NSIANNOTATIONOBSERVER |
|
101 NS_DECL_NSIOBSERVER |
|
102 |
|
103 nsNavBookmarks(); |
|
104 |
|
105 /** |
|
106 * Obtains the service's object. |
|
107 */ |
|
108 static already_AddRefed<nsNavBookmarks> GetSingleton(); |
|
109 |
|
110 /** |
|
111 * Initializes the service's object. This should only be called once. |
|
112 */ |
|
113 nsresult Init(); |
|
114 |
|
115 static nsNavBookmarks* GetBookmarksService() { |
|
116 if (!gBookmarksService) { |
|
117 nsCOMPtr<nsINavBookmarksService> serv = |
|
118 do_GetService(NS_NAVBOOKMARKSSERVICE_CONTRACTID); |
|
119 NS_ENSURE_TRUE(serv, nullptr); |
|
120 NS_ASSERTION(gBookmarksService, |
|
121 "Should have static instance pointer now"); |
|
122 } |
|
123 return gBookmarksService; |
|
124 } |
|
125 |
|
126 typedef mozilla::places::BookmarkData BookmarkData; |
|
127 typedef mozilla::places::BookmarkKeyClass BookmarkKeyClass; |
|
128 typedef mozilla::places::ItemVisitData ItemVisitData; |
|
129 typedef mozilla::places::ItemChangeData ItemChangeData; |
|
130 typedef mozilla::places::BookmarkStatementId BookmarkStatementId; |
|
131 |
|
132 nsresult ResultNodeForContainer(int64_t aID, |
|
133 nsNavHistoryQueryOptions* aOptions, |
|
134 nsNavHistoryResultNode** aNode); |
|
135 |
|
136 // Find all the children of a folder, using the given query and options. |
|
137 // For each child, a ResultNode is created and added to |children|. |
|
138 // The results are ordered by folder position. |
|
139 nsresult QueryFolderChildren(int64_t aFolderId, |
|
140 nsNavHistoryQueryOptions* aOptions, |
|
141 nsCOMArray<nsNavHistoryResultNode>* children); |
|
142 |
|
143 /** |
|
144 * Turns aRow into a node and appends it to aChildren if it is appropriate to |
|
145 * do so. |
|
146 * |
|
147 * @param aRow |
|
148 * A Storage statement (in the case of synchronous execution) or row of |
|
149 * a result set (in the case of asynchronous execution). |
|
150 * @param aOptions |
|
151 * The options of the parent folder node. |
|
152 * @param aChildren |
|
153 * The children of the parent folder node. |
|
154 * @param aCurrentIndex |
|
155 * The index of aRow within the results. When called on the first row, |
|
156 * this should be set to -1. |
|
157 */ |
|
158 nsresult ProcessFolderNodeRow(mozIStorageValueArray* aRow, |
|
159 nsNavHistoryQueryOptions* aOptions, |
|
160 nsCOMArray<nsNavHistoryResultNode>* aChildren, |
|
161 int32_t& aCurrentIndex); |
|
162 |
|
163 /** |
|
164 * The async version of QueryFolderChildren. |
|
165 * |
|
166 * @param aNode |
|
167 * The folder node that will receive the children. |
|
168 * @param _pendingStmt |
|
169 * The Storage pending statement that will be used to control async |
|
170 * execution. |
|
171 */ |
|
172 nsresult QueryFolderChildrenAsync(nsNavHistoryFolderResultNode* aNode, |
|
173 int64_t aFolderId, |
|
174 mozIStoragePendingStatement** _pendingStmt); |
|
175 |
|
176 /** |
|
177 * @return index of the new folder in aIndex, whether it was passed in or |
|
178 * generated by autoincrement. |
|
179 * |
|
180 * @note If aFolder is -1, uses the autoincrement id for folder index. |
|
181 * @note aTitle will be truncated to TITLE_LENGTH_MAX |
|
182 */ |
|
183 nsresult CreateContainerWithID(int64_t aId, int64_t aParent, |
|
184 const nsACString& aTitle, |
|
185 bool aIsBookmarkFolder, |
|
186 int32_t* aIndex, |
|
187 const nsACString& aGUID, |
|
188 int64_t* aNewFolder); |
|
189 |
|
190 /** |
|
191 * Fetches information about the specified id from the database. |
|
192 * |
|
193 * @param aItemId |
|
194 * Id of the item to fetch information for. |
|
195 * @param aBookmark |
|
196 * BookmarkData to store the information. |
|
197 */ |
|
198 nsresult FetchItemInfo(int64_t aItemId, |
|
199 BookmarkData& _bookmark); |
|
200 |
|
201 /** |
|
202 * Notifies that a bookmark has been visited. |
|
203 * |
|
204 * @param aItemId |
|
205 * The visited item id. |
|
206 * @param aData |
|
207 * Details about the new visit. |
|
208 */ |
|
209 void NotifyItemVisited(const ItemVisitData& aData); |
|
210 |
|
211 /** |
|
212 * Notifies that a bookmark has changed. |
|
213 * |
|
214 * @param aItemId |
|
215 * The changed item id. |
|
216 * @param aData |
|
217 * Details about the change. |
|
218 */ |
|
219 void NotifyItemChanged(const ItemChangeData& aData); |
|
220 |
|
221 /** |
|
222 * Recursively builds an array of descendant folders inside a given folder. |
|
223 * |
|
224 * @param aFolderId |
|
225 * The folder to fetch descendants from. |
|
226 * @param aDescendantFoldersArray |
|
227 * Output array to put descendant folders id. |
|
228 */ |
|
229 nsresult GetDescendantFolders(int64_t aFolderId, |
|
230 nsTArray<int64_t>& aDescendantFoldersArray); |
|
231 |
|
232 private: |
|
233 static nsNavBookmarks* gBookmarksService; |
|
234 |
|
235 ~nsNavBookmarks(); |
|
236 |
|
237 /** |
|
238 * Locates the root items in the bookmarks folder hierarchy assigning folder |
|
239 * ids to the root properties that are exposed through the service interface. |
|
240 */ |
|
241 nsresult ReadRoots(); |
|
242 |
|
243 nsresult AdjustIndices(int64_t aFolder, |
|
244 int32_t aStartIndex, |
|
245 int32_t aEndIndex, |
|
246 int32_t aDelta); |
|
247 |
|
248 /** |
|
249 * Fetches properties of a folder. |
|
250 * |
|
251 * @param aFolderId |
|
252 * Folder to count children for. |
|
253 * @param _folderCount |
|
254 * Number of children in the folder. |
|
255 * @param _guid |
|
256 * Unique id of the folder. |
|
257 * @param _parentId |
|
258 * Id of the parent of the folder. |
|
259 * |
|
260 * @throws If folder does not exist. |
|
261 */ |
|
262 nsresult FetchFolderInfo(int64_t aFolderId, |
|
263 int32_t* _folderCount, |
|
264 nsACString& _guid, |
|
265 int64_t* _parentId); |
|
266 |
|
267 nsresult GetLastChildId(int64_t aFolder, int64_t* aItemId); |
|
268 |
|
269 /** |
|
270 * This is an handle to the Places database. |
|
271 */ |
|
272 nsRefPtr<mozilla::places::Database> mDB; |
|
273 |
|
274 int32_t mItemCount; |
|
275 |
|
276 nsMaybeWeakPtrArray<nsINavBookmarkObserver> mObservers; |
|
277 |
|
278 int64_t mRoot; |
|
279 int64_t mMenuRoot; |
|
280 int64_t mTagsRoot; |
|
281 int64_t mUnfiledRoot; |
|
282 int64_t mToolbarRoot; |
|
283 |
|
284 inline bool IsRoot(int64_t aFolderId) { |
|
285 return aFolderId == mRoot || aFolderId == mMenuRoot || |
|
286 aFolderId == mTagsRoot || aFolderId == mUnfiledRoot || |
|
287 aFolderId == mToolbarRoot; |
|
288 } |
|
289 |
|
290 nsresult IsBookmarkedInDatabase(int64_t aBookmarkID, bool* aIsBookmarked); |
|
291 |
|
292 nsresult SetItemDateInternal(enum mozilla::places::BookmarkDate aDateType, |
|
293 int64_t aItemId, |
|
294 PRTime aValue); |
|
295 |
|
296 // Recursive method to build an array of folder's children |
|
297 nsresult GetDescendantChildren(int64_t aFolderId, |
|
298 const nsACString& aFolderGuid, |
|
299 int64_t aGrandParentId, |
|
300 nsTArray<BookmarkData>& aFolderChildrenArray); |
|
301 |
|
302 enum ItemType { |
|
303 BOOKMARK = TYPE_BOOKMARK, |
|
304 FOLDER = TYPE_FOLDER, |
|
305 SEPARATOR = TYPE_SEPARATOR, |
|
306 }; |
|
307 |
|
308 /** |
|
309 * Helper to insert a bookmark in the database. |
|
310 * |
|
311 * @param aItemId |
|
312 * The itemId to insert, pass -1 to generate a new one. |
|
313 * @param aPlaceId |
|
314 * The placeId to which this bookmark refers to, pass nullptr for |
|
315 * items that don't refer to an URI (eg. folders, separators, ...). |
|
316 * @param aItemType |
|
317 * The type of the new bookmark, see TYPE_* constants. |
|
318 * @param aParentId |
|
319 * The itemId of the parent folder. |
|
320 * @param aIndex |
|
321 * The position inside the parent folder. |
|
322 * @param aTitle |
|
323 * The title for the new bookmark. |
|
324 * Pass a void string to set a NULL title. |
|
325 * @param aDateAdded |
|
326 * The date for the insertion. |
|
327 * @param [optional] aLastModified |
|
328 * The last modified date for the insertion. |
|
329 * It defaults to aDateAdded. |
|
330 * |
|
331 * @return The new item id that has been inserted. |
|
332 * |
|
333 * @note This will also update last modified date of the parent folder. |
|
334 */ |
|
335 nsresult InsertBookmarkInDB(int64_t aPlaceId, |
|
336 enum ItemType aItemType, |
|
337 int64_t aParentId, |
|
338 int32_t aIndex, |
|
339 const nsACString& aTitle, |
|
340 PRTime aDateAdded, |
|
341 PRTime aLastModified, |
|
342 const nsACString& aParentGuid, |
|
343 int64_t aGrandParentId, |
|
344 nsIURI* aURI, |
|
345 int64_t* _itemId, |
|
346 nsACString& _guid); |
|
347 |
|
348 /** |
|
349 * TArray version of getBookmarksIdForURI for ease of use in C++ code. |
|
350 * Pass in a reference to a TArray; it will get filled with the |
|
351 * resulting list of bookmark IDs. |
|
352 * |
|
353 * @param aURI |
|
354 * URI to get bookmarks for. |
|
355 * @param aResult |
|
356 * Array of bookmark ids. |
|
357 * @param aSkipTags |
|
358 * If true ids of tags-as-bookmarks entries will be excluded. |
|
359 */ |
|
360 nsresult GetBookmarkIdsForURITArray(nsIURI* aURI, |
|
361 nsTArray<int64_t>& aResult, |
|
362 bool aSkipTags); |
|
363 |
|
364 nsresult GetBookmarksForURI(nsIURI* aURI, |
|
365 nsTArray<BookmarkData>& _bookmarks); |
|
366 |
|
367 int64_t RecursiveFindRedirectedBookmark(int64_t aPlaceId); |
|
368 |
|
369 static const int32_t kGetChildrenIndex_Position; |
|
370 static const int32_t kGetChildrenIndex_Type; |
|
371 static const int32_t kGetChildrenIndex_PlaceID; |
|
372 static const int32_t kGetChildrenIndex_Guid; |
|
373 |
|
374 class RemoveFolderTransaction MOZ_FINAL : public nsITransaction { |
|
375 public: |
|
376 RemoveFolderTransaction(int64_t aID) : mID(aID) {} |
|
377 |
|
378 NS_DECL_ISUPPORTS |
|
379 |
|
380 NS_IMETHOD DoTransaction() { |
|
381 nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService(); |
|
382 NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY); |
|
383 BookmarkData folder; |
|
384 nsresult rv = bookmarks->FetchItemInfo(mID, folder); |
|
385 // TODO (Bug 656935): store the BookmarkData struct instead. |
|
386 mParent = folder.parentId; |
|
387 mIndex = folder.position; |
|
388 |
|
389 rv = bookmarks->GetItemTitle(mID, mTitle); |
|
390 NS_ENSURE_SUCCESS(rv, rv); |
|
391 |
|
392 return bookmarks->RemoveItem(mID); |
|
393 } |
|
394 |
|
395 NS_IMETHOD UndoTransaction() { |
|
396 nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService(); |
|
397 NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY); |
|
398 int64_t newFolder; |
|
399 return bookmarks->CreateContainerWithID(mID, mParent, mTitle, true, |
|
400 &mIndex, EmptyCString(), &newFolder); |
|
401 } |
|
402 |
|
403 NS_IMETHOD RedoTransaction() { |
|
404 return DoTransaction(); |
|
405 } |
|
406 |
|
407 NS_IMETHOD GetIsTransient(bool* aResult) { |
|
408 *aResult = false; |
|
409 return NS_OK; |
|
410 } |
|
411 |
|
412 NS_IMETHOD Merge(nsITransaction* aTransaction, bool* aResult) { |
|
413 *aResult = false; |
|
414 return NS_OK; |
|
415 } |
|
416 |
|
417 private: |
|
418 int64_t mID; |
|
419 int64_t mParent; |
|
420 nsCString mTitle; |
|
421 int32_t mIndex; |
|
422 }; |
|
423 |
|
424 // Used to enable and disable the observer notifications. |
|
425 bool mCanNotify; |
|
426 nsCategoryCache<nsINavBookmarkObserver> mCacheObservers; |
|
427 |
|
428 // Tracks whether we are in batch mode. |
|
429 // Note: this is only tracking bookmarks batches, not history ones. |
|
430 bool mBatching; |
|
431 |
|
432 /** |
|
433 * Always call EnsureKeywordsHash() and check it for errors before actually |
|
434 * using the hash. Internal keyword methods are already doing that. |
|
435 */ |
|
436 nsresult EnsureKeywordsHash(); |
|
437 nsDataHashtable<nsTrimInt64HashKey, nsString> mBookmarkToKeywordHash; |
|
438 bool mBookmarkToKeywordHashInitialized; |
|
439 |
|
440 /** |
|
441 * This function must be called every time a bookmark is removed. |
|
442 * |
|
443 * @param aURI |
|
444 * Uri to test. |
|
445 */ |
|
446 nsresult UpdateKeywordsHashForRemovedBookmark(int64_t aItemId); |
|
447 |
|
448 /** |
|
449 * Cache for the last fetched BookmarkData entries. |
|
450 * This is used to speed up repeated requests to the same item id. |
|
451 */ |
|
452 nsTHashtable<BookmarkKeyClass> mRecentBookmarksCache; |
|
453 |
|
454 /** |
|
455 * Tracks bookmarks in the cache critical path. Items should not be |
|
456 * added to the cache till they are removed from this hash. |
|
457 */ |
|
458 nsTHashtable<nsTrimInt64HashKey> mUncachableBookmarks; |
|
459 }; |
|
460 |
|
461 #endif // nsNavBookmarks_h_ |