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