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
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/
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
15 * The Original Code is Places.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2005
20 * the Initial Developer. All Rights Reserved.
23 * Brian Ryner <bryner@brianryner.com> (original author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsAppDirectoryServiceDefs.h"
40 #include "nsNavBookmarks.h"
41 #include "nsNavHistory.h"
42 #include "mozStorageHelper.h"
43 #include "nsIServiceManager.h"
44 #include "nsNetUtil.h"
45 #include "nsIDynamicContainer.h"
46 #include "nsUnicharUtils.h"
47 #include "nsFaviconService.h"
48 #include "nsAnnotationService.h"
49 #include "nsPrintfCString.h"
50 #include "nsIUUIDGenerator.h"
52 #include "nsILivemarkService.h"
53 #include "nsPlacesTriggers.h"
54 #include "nsPlacesTables.h"
56 const PRInt32
nsNavBookmarks::kFindBookmarksIndex_ID
= 0;
57 const PRInt32
nsNavBookmarks::kFindBookmarksIndex_Type
= 1;
58 const PRInt32
nsNavBookmarks::kFindBookmarksIndex_PlaceID
= 2;
59 const PRInt32
nsNavBookmarks::kFindBookmarksIndex_Parent
= 3;
60 const PRInt32
nsNavBookmarks::kFindBookmarksIndex_Position
= 4;
61 const PRInt32
nsNavBookmarks::kFindBookmarksIndex_Title
= 5;
63 // These columns sit to the right of the kGetInfoIndex_* columns.
64 const PRInt32
nsNavBookmarks::kGetChildrenIndex_Position
= 11;
65 const PRInt32
nsNavBookmarks::kGetChildrenIndex_Type
= 12;
66 const PRInt32
nsNavBookmarks::kGetChildrenIndex_PlaceID
= 13;
67 const PRInt32
nsNavBookmarks::kGetChildrenIndex_ServiceContractId
= 14;
69 const PRInt32
nsNavBookmarks::kGetItemPropertiesIndex_ID
= 0;
70 const PRInt32
nsNavBookmarks::kGetItemPropertiesIndex_URI
= 1;
71 const PRInt32
nsNavBookmarks::kGetItemPropertiesIndex_Title
= 2;
72 const PRInt32
nsNavBookmarks::kGetItemPropertiesIndex_Position
= 3;
73 const PRInt32
nsNavBookmarks::kGetItemPropertiesIndex_PlaceID
= 4;
74 const PRInt32
nsNavBookmarks::kGetItemPropertiesIndex_Parent
= 5;
75 const PRInt32
nsNavBookmarks::kGetItemPropertiesIndex_Type
= 6;
76 const PRInt32
nsNavBookmarks::kGetItemPropertiesIndex_ServiceContractId
= 7;
77 const PRInt32
nsNavBookmarks::kGetItemPropertiesIndex_DateAdded
= 8;
78 const PRInt32
nsNavBookmarks::kGetItemPropertiesIndex_LastModified
= 9;
80 nsNavBookmarks
* nsNavBookmarks::sInstance
= nsnull
;
82 #define BOOKMARKS_ANNO_PREFIX "bookmarks/"
83 #define BOOKMARKS_TOOLBAR_FOLDER_ANNO NS_LITERAL_CSTRING(BOOKMARKS_ANNO_PREFIX "toolbarFolder")
84 #define GUID_ANNO NS_LITERAL_CSTRING("placesInternal/GUID")
85 #define READ_ONLY_ANNO NS_LITERAL_CSTRING("placesInternal/READ_ONLY")
87 nsNavBookmarks::nsNavBookmarks()
88 : mItemCount(0), mRoot(0), mBookmarksRoot(0), mTagRoot(0), mToolbarFolder(0), mBatchLevel(0),
89 mBatchHasTransaction(PR_FALSE
)
91 NS_ASSERTION(!sInstance
, "Multiple nsNavBookmarks instances!");
95 nsNavBookmarks::~nsNavBookmarks()
97 NS_ASSERTION(sInstance
== this, "Expected sInstance == this");
101 NS_IMPL_ISUPPORTS3(nsNavBookmarks
,
102 nsINavBookmarksService
,
103 nsINavHistoryObserver
,
104 nsIAnnotationObserver
)
107 nsNavBookmarks::Init()
109 nsNavHistory
*history
= History();
110 NS_ENSURE_TRUE(history
, NS_ERROR_OUT_OF_MEMORY
);
111 mDBConn
= history
->GetStorageConnection();
112 mozStorageTransaction
transaction(mDBConn
, PR_FALSE
);
114 nsresult rv
= InitStatements();
115 NS_ENSURE_SUCCESS(rv
, rv
);
117 rv
= FillBookmarksHash();
118 NS_ENSURE_SUCCESS(rv
, rv
);
121 NS_ENSURE_SUCCESS(rv
, rv
);
123 rv
= transaction
.Commit();
124 NS_ENSURE_SUCCESS(rv
, rv
);
127 nsAnnotationService
* annosvc
= nsAnnotationService::GetAnnotationService();
128 NS_ENSURE_TRUE(annosvc
, NS_ERROR_OUT_OF_MEMORY
);
129 annosvc
->AddObserver(this);
131 // allows us to notify on title changes. MUST BE LAST so it is impossible
132 // to fail after this call, or the history service will have a reference to
133 // us and we won't go away.
134 history
->AddObserver(this, PR_FALSE
);
136 // DO NOT PUT STUFF HERE that can fail. See observer comment above.
141 // nsNavBookmarks::InitTables
143 // All commands that initialize the schema of the DB go in here. This is
144 // called from history init before the dummy DB connection is started that
145 // will prevent us from modifying the schema.
148 nsNavBookmarks::InitTables(mozIStorageConnection
* aDBConn
)
151 nsresult rv
= aDBConn
->TableExists(NS_LITERAL_CSTRING("moz_bookmarks"), &exists
);
152 NS_ENSURE_SUCCESS(rv
, rv
);
154 rv
= aDBConn
->ExecuteSimpleSQL(CREATE_MOZ_BOOKMARKS
);
155 NS_ENSURE_SUCCESS(rv
, rv
);
157 // This index will make it faster to determine if a given item is
158 // bookmarked (used by history queries and vacuuming, for example).
159 // Making it compound with "type" speeds up type-differentiation
160 // queries, such as expiration and search.
161 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
162 "CREATE INDEX moz_bookmarks_itemindex ON moz_bookmarks (fk, type)"));
163 NS_ENSURE_SUCCESS(rv
, rv
);
165 // The most common operation is to find the children given a parent and position.
166 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
167 "CREATE INDEX moz_bookmarks_parentindex "
168 "ON moz_bookmarks (parent, position)"));
169 NS_ENSURE_SUCCESS(rv
, rv
);
171 // fast access to lastModified is useful during sync and to get
172 // last modified bookmark title for tags container's children.
173 rv
= aDBConn
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
174 "CREATE INDEX moz_bookmarks_itemlastmodifiedindex "
175 "ON moz_bookmarks (fk, lastModified)"));
176 NS_ENSURE_SUCCESS(rv
, rv
);
179 // moz_bookmarks_roots
180 rv
= aDBConn
->TableExists(NS_LITERAL_CSTRING("moz_bookmarks_roots"), &exists
);
181 NS_ENSURE_SUCCESS(rv
, rv
);
183 rv
= aDBConn
->ExecuteSimpleSQL(CREATE_MOZ_BOOKMARKS_ROOTS
);
184 NS_ENSURE_SUCCESS(rv
, rv
);
188 rv
= aDBConn
->TableExists(NS_LITERAL_CSTRING("moz_keywords"), &exists
);
189 NS_ENSURE_SUCCESS(rv
, rv
);
191 rv
= aDBConn
->ExecuteSimpleSQL(CREATE_MOZ_KEYWORDS
);
192 NS_ENSURE_SUCCESS(rv
, rv
);
194 // Create trigger to update as well
195 rv
= aDBConn
->ExecuteSimpleSQL(CREATE_KEYWORD_VALIDITY_TRIGGER
);
196 NS_ENSURE_SUCCESS(rv
, rv
);
203 // nsNavBookmarks::InitStatements
205 // Create common statements to query the database
207 nsNavBookmarks::InitStatements()
209 // mDBFindURIBookmarks
210 // NOTE: Do not modify the ORDER BY segment of the query, as certain
211 // features depend on it. See bug 398914 for an example.
212 nsresult rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
214 "FROM moz_bookmarks b "
216 "SELECT id FROM moz_places_temp "
219 "SELECT id FROM moz_places "
221 "AND +id NOT IN (SELECT id FROM moz_places_temp) "
222 ") AS h ON b.fk = h.id "
224 "ORDER BY MAX(IFNULL(b.lastModified, 0), b.dateAdded) DESC, b.id DESC"),
225 getter_AddRefs(mDBFindURIBookmarks
));
226 NS_ENSURE_SUCCESS(rv
, rv
);
228 // Construct a result where the first columns exactly match those returned by
229 // mDBGetURLPageInfo, and additionally contains columns for position,
230 // item_child, and folder_child from moz_bookmarks.
231 // Results are kGetInfoIndex_*
233 // mDBGetChildren: select all children of a given folder, sorted by position
234 // This is a LEFT OUTER JOIN with moz_places since folders does not have
235 // a reference into that table.
236 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
238 "SELECT h.id, h.url, COALESCE(b.title, h.title), "
239 "h.rev_host, h.visit_count, "
240 SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
241 ", f.url, null, b.id, b.dateAdded, b.lastModified, "
242 "b.position, b.type, b.fk, b.folder_type "
243 "FROM moz_bookmarks b "
244 "JOIN moz_places_temp h ON b.fk = h.id "
245 "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
246 "WHERE b.parent = ?1 "
248 "SELECT h.id, h.url, COALESCE(b.title, h.title), "
249 "h.rev_host, h.visit_count, "
250 SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
251 ", f.url, null, b.id, b.dateAdded, b.lastModified, "
252 "b.position, b.type, b.fk, b.folder_type "
253 "FROM moz_bookmarks b "
254 "LEFT JOIN moz_places h ON b.fk = h.id "
255 "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
256 "WHERE b.parent = ?1 "
257 "AND (b.fk ISNULL OR b.fk NOT IN (select id FROM moz_places_temp)) "
259 "ORDER BY 12 ASC"), /* position */
260 getter_AddRefs(mDBGetChildren
));
261 NS_ENSURE_SUCCESS(rv
, rv
);
263 // mDBFolderCount: count all of the children of a given folder
264 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
265 "SELECT COUNT(*) FROM moz_bookmarks WHERE parent = ?1"),
266 getter_AddRefs(mDBFolderCount
));
267 NS_ENSURE_SUCCESS(rv
, rv
);
269 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
270 "SELECT position FROM moz_bookmarks WHERE id = ?1"),
271 getter_AddRefs(mDBGetItemIndex
));
272 NS_ENSURE_SUCCESS(rv
, rv
);
274 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
275 "SELECT id, fk, type FROM moz_bookmarks WHERE parent = ?1 AND position = ?2"),
276 getter_AddRefs(mDBGetChildAt
));
277 NS_ENSURE_SUCCESS(rv
, rv
);
279 // get bookmark/folder/separator properties
280 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
283 "(SELECT url FROM moz_places_temp "
284 "WHERE id = (SELECT fk FROM moz_bookmarks WHERE id = ?1)) "
286 "(SELECT url FROM moz_places "
287 "WHERE id = (SELECT fk FROM moz_bookmarks WHERE id = ?1)) "
288 "), b.title, b.position, b.fk, b.parent, b.type, b.folder_type, "
289 "b.dateAdded, b.lastModified "
290 "FROM moz_bookmarks b "
292 getter_AddRefs(mDBGetItemProperties
));
293 NS_ENSURE_SUCCESS(rv
, rv
);
295 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
296 "SELECT item_id FROM moz_items_annos "
297 "WHERE content = ?1 "
299 getter_AddRefs(mDBGetItemIdForGUID
));
300 NS_ENSURE_SUCCESS(rv
, rv
);
302 // mDBGetRedirectDestinations
303 // input = page ID, time threshold; output = unique ID input has redirected to
304 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
305 "SELECT DISTINCT dest_v.place_id "
306 "FROM moz_historyvisits_temp source_v "
307 "JOIN moz_historyvisits_temp dest_v ON dest_v.from_visit = source_v.id "
308 "WHERE source_v.place_id = ?1 "
309 "AND source_v.visit_date >= ?2 "
310 "AND dest_v.visit_type IN (") +
311 nsPrintfCString("%d,%d",
312 nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT
,
313 nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY
) +
314 NS_LITERAL_CSTRING(") "
316 "SELECT DISTINCT dest_v.place_id "
317 "FROM moz_historyvisits_temp source_v "
318 "JOIN moz_historyvisits dest_v ON dest_v.from_visit = source_v.id "
319 "WHERE source_v.place_id = ?1 "
320 "AND source_v.visit_date >= ?2 "
321 "AND dest_v.visit_type IN (") +
322 nsPrintfCString("%d,%d",
323 nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT
,
324 nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY
) +
325 NS_LITERAL_CSTRING(") "
327 "SELECT DISTINCT dest_v.place_id "
328 "FROM moz_historyvisits source_v "
329 "JOIN moz_historyvisits_temp dest_v ON dest_v.from_visit = source_v.id "
330 "WHERE source_v.place_id = ?1 "
331 "AND source_v.visit_date >= ?2 "
332 "AND dest_v.visit_type IN (") +
333 nsPrintfCString("%d,%d",
334 nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT
,
335 nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY
) +
336 NS_LITERAL_CSTRING(") "
338 "SELECT DISTINCT dest_v.place_id "
339 "FROM moz_historyvisits source_v "
340 "JOIN moz_historyvisits dest_v ON dest_v.from_visit = source_v.id "
341 "WHERE source_v.place_id = ?1 "
342 "AND source_v.visit_date >= ?2 "
343 "AND dest_v.visit_type IN (") +
344 nsPrintfCString("%d,%d",
345 nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT
,
346 nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY
) +
347 NS_LITERAL_CSTRING(") "),
348 getter_AddRefs(mDBGetRedirectDestinations
));
349 NS_ENSURE_SUCCESS(rv
, rv
);
352 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
353 "INSERT INTO moz_bookmarks "
354 "(fk, type, parent, position, title, dateAdded) "
355 "VALUES (?1, ?2, ?3, ?4, ?5, ?6)"),
356 getter_AddRefs(mDBInsertBookmark
));
357 NS_ENSURE_SUCCESS(rv
, rv
);
359 // mDBIsBookmarkedInDatabase
360 // Just select position since it's just an int32 and may be faster.
361 // We don't actually care about the data, just whether there is any.
362 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
363 "SELECT position FROM moz_bookmarks WHERE fk = ?1 AND type = ?2"),
364 getter_AddRefs(mDBIsBookmarkedInDatabase
));
365 NS_ENSURE_SUCCESS(rv
, rv
);
367 // mDBGetLastBookmarkID
368 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
370 "FROM moz_bookmarks "
371 "ORDER BY ROWID DESC "
373 getter_AddRefs(mDBGetLastBookmarkID
));
374 NS_ENSURE_SUCCESS(rv
, rv
);
376 // mDBSetItemDateAdded
377 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
378 "UPDATE moz_bookmarks SET dateAdded = ?1 WHERE id = ?2"),
379 getter_AddRefs(mDBSetItemDateAdded
));
380 NS_ENSURE_SUCCESS(rv
, rv
);
382 // mDBSetItemLastModified
383 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
384 "UPDATE moz_bookmarks SET lastModified = ?1 WHERE id = ?2"),
385 getter_AddRefs(mDBSetItemLastModified
));
386 NS_ENSURE_SUCCESS(rv
, rv
);
389 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
390 "UPDATE moz_bookmarks SET position = ?2 WHERE id = ?1"),
391 getter_AddRefs(mDBSetItemIndex
));
392 NS_ENSURE_SUCCESS(rv
, rv
);
394 // get keyword text for bookmark id
395 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
396 "SELECT k.keyword FROM moz_bookmarks b "
397 "JOIN moz_keywords k ON k.id = b.keyword_id "
399 getter_AddRefs(mDBGetKeywordForBookmark
));
400 NS_ENSURE_SUCCESS(rv
, rv
);
401 // get keyword text for URI (must be a bookmarked URI)
402 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
405 "SELECT id FROM moz_places_temp "
408 "SELECT id FROM moz_places "
409 "WHERE +id NOT IN (SELECT id FROM moz_places_temp) "
412 "JOIN moz_bookmarks b ON b.fk = h.id "
413 "JOIN moz_keywords k ON k.id = b.keyword_id"),
414 getter_AddRefs(mDBGetKeywordForURI
));
415 NS_ENSURE_SUCCESS(rv
, rv
);
417 // get URI for keyword
418 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
419 "SELECT url FROM moz_keywords k "
420 "JOIN moz_bookmarks b ON b.keyword_id = k.id "
421 "JOIN moz_places_temp h ON b.fk = h.id "
422 "WHERE k.keyword = ?1 "
424 "SELECT url FROM moz_keywords k "
425 "JOIN moz_bookmarks b ON b.keyword_id = k.id "
426 "JOIN moz_places h ON b.fk = h.id "
427 "WHERE k.keyword = ?1 "
428 "AND h.id NOT IN (SELECT id FROM moz_places_temp)"),
429 getter_AddRefs(mDBGetURIForKeyword
));
430 NS_ENSURE_SUCCESS(rv
, rv
);
436 // nsNavBookmarks::InitRoots
438 // This locates and creates if necessary the root items in the bookmarks
439 // folder hierarchy. These items are stored in a special roots table that
440 // maps short predefined names to folder IDs.
442 // Normally, these folders will exist already and we will save their IDs
443 // which are exposed through the bookmark service interface.
445 // If the root does not exist, a folder is created for it and the ID is
446 // saved in the root table. No user-visible name is given to these folders
447 // and they have no parent or other attributes.
449 // These attributes are set when the default_places.html file is imported.
450 // It defines the hierarchy, and has special attributes that tell us when
451 // a folder is one of our well-known roots. We then insert the root in the
452 // defined point in the hierarchy and set its attributes from this.
454 // This should be called as the last part of the init process so that
455 // all of the statements are set up and the service is ready to use.
458 nsNavBookmarks::InitRoots()
460 nsCOMPtr
<mozIStorageStatement
> getRootStatement
;
461 nsresult rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
462 "SELECT folder_id FROM moz_bookmarks_roots WHERE root_name = ?1"),
463 getter_AddRefs(getRootStatement
));
464 NS_ENSURE_SUCCESS(rv
, rv
);
466 PRBool createdPlacesRoot
= PR_FALSE
;
467 rv
= CreateRoot(getRootStatement
, NS_LITERAL_CSTRING("places"), &mRoot
, 0, &createdPlacesRoot
);
468 NS_ENSURE_SUCCESS(rv
, rv
);
470 getRootStatement
->Reset();
471 rv
= CreateRoot(getRootStatement
, NS_LITERAL_CSTRING("menu"), &mBookmarksRoot
, mRoot
, nsnull
);
472 NS_ENSURE_SUCCESS(rv
, rv
);
474 PRBool createdToolbarFolder
;
475 getRootStatement
->Reset();
476 rv
= CreateRoot(getRootStatement
, NS_LITERAL_CSTRING("toolbar"), &mToolbarFolder
, mRoot
, &createdToolbarFolder
);
477 NS_ENSURE_SUCCESS(rv
, rv
);
479 // Once toolbar was not a root, we may need to move over the items and
480 // delete the custom folder
481 if (!createdPlacesRoot
&& createdToolbarFolder
) {
482 nsAnnotationService
* annosvc
= nsAnnotationService::GetAnnotationService();
483 NS_ENSURE_TRUE(annosvc
, NS_ERROR_OUT_OF_MEMORY
);
485 nsTArray
<PRInt64
> folders
;
486 annosvc
->GetItemsWithAnnotationTArray(BOOKMARKS_TOOLBAR_FOLDER_ANNO
,
488 if (folders
.Length() > 0) {
489 nsCOMPtr
<mozIStorageStatement
> moveItems
;
490 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
491 "UPDATE moz_bookmarks SET parent = ?1 WHERE parent=?2"),
492 getter_AddRefs(moveItems
));
493 rv
= moveItems
->BindInt64Parameter(0, mToolbarFolder
);
494 NS_ENSURE_SUCCESS(rv
, rv
);
495 rv
= moveItems
->BindInt64Parameter(1, folders
[0]);
496 NS_ENSURE_SUCCESS(rv
, rv
);
497 rv
= moveItems
->Execute();
498 NS_ENSURE_SUCCESS(rv
, rv
);
499 rv
= RemoveFolder(folders
[0]);
500 NS_ENSURE_SUCCESS(rv
, rv
);
504 getRootStatement
->Reset();
505 rv
= CreateRoot(getRootStatement
, NS_LITERAL_CSTRING("tags"), &mTagRoot
, mRoot
, nsnull
);
506 NS_ENSURE_SUCCESS(rv
, rv
);
508 getRootStatement
->Reset();
509 rv
= CreateRoot(getRootStatement
, NS_LITERAL_CSTRING("unfiled"), &mUnfiledRoot
, mRoot
, nsnull
);
510 NS_ENSURE_SUCCESS(rv
, rv
);
512 // Set titles for special folders
513 // We cannot rely on createdPlacesRoot due to Fx3beta->final migration path
514 nsCOMPtr
<nsIPrefService
> prefService
=
515 do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
);
516 NS_ENSURE_SUCCESS(rv
, rv
);
518 nsCOMPtr
<nsIPrefBranch
> prefBranch
;
519 rv
= prefService
->GetBranch("", getter_AddRefs(prefBranch
));
520 NS_ENSURE_SUCCESS(rv
, rv
);
522 PRUint16 databaseStatus
= nsINavHistoryService::DATABASE_STATUS_OK
;
523 rv
= History()->GetDatabaseStatus(&databaseStatus
);
524 NS_ENSURE_SUCCESS(rv
, rv
);
527 databaseStatus
!= nsINavHistoryService::DATABASE_STATUS_OK
) {
529 NS_ENSURE_SUCCESS(rv
, rv
);
535 // nsNavBookmarks::InitDefaults
537 // Initializes default bookmarks and containers.
538 // Pulls from places.propertes for l10n.
539 // Replaces the old default_places.html file.
541 nsNavBookmarks::InitDefaults()
543 nsIStringBundle
*bundle
= History()->GetBundle();
544 NS_ENSURE_TRUE(bundle
, NS_ERROR_OUT_OF_MEMORY
);
547 nsXPIDLString bookmarksTitle
;
548 nsresult rv
= bundle
->GetStringFromName(NS_LITERAL_STRING("BookmarksMenuFolderTitle").get(),
549 getter_Copies(bookmarksTitle
));
550 NS_ENSURE_SUCCESS(rv
, rv
);
551 rv
= SetItemTitle(mBookmarksRoot
, NS_ConvertUTF16toUTF8(bookmarksTitle
));
552 NS_ENSURE_SUCCESS(rv
, rv
);
555 nsXPIDLString toolbarTitle
;
556 rv
= bundle
->GetStringFromName(NS_LITERAL_STRING("BookmarksToolbarFolderTitle").get(),
557 getter_Copies(toolbarTitle
));
558 NS_ENSURE_SUCCESS(rv
, rv
);
559 rv
= SetItemTitle(mToolbarFolder
, NS_ConvertUTF16toUTF8(toolbarTitle
));
560 NS_ENSURE_SUCCESS(rv
, rv
);
562 // Unsorted Bookmarks
563 nsXPIDLString unfiledTitle
;
564 rv
= bundle
->GetStringFromName(NS_LITERAL_STRING("UnsortedBookmarksFolderTitle").get(),
565 getter_Copies(unfiledTitle
));
566 NS_ENSURE_SUCCESS(rv
, rv
);
567 rv
= SetItemTitle(mUnfiledRoot
, NS_ConvertUTF16toUTF8(unfiledTitle
));
568 NS_ENSURE_SUCCESS(rv
, rv
);
571 nsXPIDLString tagsTitle
;
572 rv
= bundle
->GetStringFromName(NS_LITERAL_STRING("TagsFolderTitle").get(),
573 getter_Copies(tagsTitle
));
574 NS_ENSURE_SUCCESS(rv
, rv
);
575 rv
= SetItemTitle(mTagRoot
, NS_ConvertUTF16toUTF8(tagsTitle
));
576 NS_ENSURE_SUCCESS(rv
, rv
);
581 // nsNavBookmarks::CreateRoot
583 // This gets or creates a root folder of the given type. aWasCreated
584 // (optional) is true if the folder had to be created, false if we just used
585 // an old one. The statement that gets a folder ID from a root name is
586 // passed in so the DB only needs to parse the statement once, and we don't
587 // have to have a global for this. Creation is less optimized because it
591 nsNavBookmarks::CreateRoot(mozIStorageStatement
* aGetRootStatement
,
592 const nsCString
& name
, PRInt64
* aID
,
593 PRInt64 aParentID
, PRBool
* aWasCreated
)
595 PRBool hasResult
= PR_FALSE
;
596 nsresult rv
= aGetRootStatement
->BindUTF8StringParameter(0, name
);
597 NS_ENSURE_SUCCESS(rv
, rv
);
598 rv
= aGetRootStatement
->ExecuteStep(&hasResult
);
599 NS_ENSURE_SUCCESS(rv
, rv
);
602 *aWasCreated
= PR_FALSE
;
603 rv
= aGetRootStatement
->GetInt64(0, aID
);
604 NS_ENSURE_SUCCESS(rv
, rv
);
605 NS_ASSERTION(*aID
!= 0, "Root is 0 for some reason, folders can't have 0 ID");
609 *aWasCreated
= PR_TRUE
;
611 // create folder with no name or attributes
612 nsCOMPtr
<mozIStorageStatement
> insertStatement
;
613 rv
= CreateFolder(aParentID
, EmptyCString(), nsINavBookmarksService::DEFAULT_INDEX
, aID
);
614 NS_ENSURE_SUCCESS(rv
, rv
);
617 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
618 "INSERT INTO moz_bookmarks_roots (root_name, folder_id) VALUES (?1, ?2)"),
619 getter_AddRefs(insertStatement
));
620 NS_ENSURE_SUCCESS(rv
, rv
);
621 rv
= insertStatement
->BindUTF8StringParameter(0, name
);
622 NS_ENSURE_SUCCESS(rv
, rv
);
623 rv
= insertStatement
->BindInt64Parameter(1, *aID
);
624 NS_ENSURE_SUCCESS(rv
, rv
);
625 rv
= insertStatement
->Execute();
626 NS_ENSURE_SUCCESS(rv
, rv
);
632 // nsNavBookmarks::FillBookmarksHash
634 // This initializes the bookmarks hashtable that tells us which bookmark
635 // a given URI redirects to. This hashtable includes all URIs that
636 // redirect to bookmarks.
638 // This is called from the bookmark init function and so is wrapped
639 // in that transaction (for better performance).
642 nsNavBookmarks::FillBookmarksHash()
646 // first init the hashtable
647 NS_ENSURE_TRUE(mBookmarksHash
.Init(1024), NS_ERROR_OUT_OF_MEMORY
);
649 // first populate the table with all bookmarks
650 nsCOMPtr
<mozIStorageStatement
> statement
;
651 nsresult rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
653 "FROM moz_bookmarks b "
654 "LEFT JOIN moz_places h ON b.fk = h.id where b.type = ?1"),
655 getter_AddRefs(statement
));
656 NS_ENSURE_SUCCESS(rv
, rv
);
657 rv
= statement
->BindInt32Parameter(0, TYPE_BOOKMARK
);
658 NS_ENSURE_SUCCESS(rv
, rv
);
659 while (NS_SUCCEEDED(statement
->ExecuteStep(&hasMore
)) && hasMore
) {
661 rv
= statement
->GetInt64(0, &pageID
);
662 NS_ENSURE_TRUE(mBookmarksHash
.Put(pageID
, pageID
), NS_ERROR_OUT_OF_MEMORY
);
665 // Find all pages h2 that have been redirected to from a bookmarked URI:
666 // bookmarked -> url (h1) url (h2)
669 // visit (v1) -> destination visit (v2)
670 // This should catch most redirects, which are only one level. More levels of
671 // redirection will be handled separately.
672 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
673 "SELECT v1.place_id, v2.place_id "
674 "FROM moz_bookmarks b "
675 "LEFT JOIN moz_historyvisits_temp v1 on b.fk = v1.place_id "
676 "LEFT JOIN moz_historyvisits v2 on v2.from_visit = v1.id "
677 "WHERE b.fk IS NOT NULL AND b.type = ?1 "
678 "AND v2.visit_type IN (") +
679 nsPrintfCString("%d,%d",
680 nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT
,
681 nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY
) +
682 NS_LITERAL_CSTRING(") GROUP BY v2.place_id "
684 "SELECT v1.place_id, v2.place_id "
685 "FROM moz_bookmarks b "
686 "LEFT JOIN moz_historyvisits v1 on b.fk = v1.place_id "
687 "LEFT JOIN moz_historyvisits_temp v2 on v2.from_visit = v1.id "
688 "WHERE b.fk IS NOT NULL AND b.type = ?1 "
689 "AND v2.visit_type IN (") +
690 nsPrintfCString("%d,%d",
691 nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT
,
692 nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY
) +
693 NS_LITERAL_CSTRING(") GROUP BY v2.place_id "
695 "SELECT v1.place_id, v2.place_id "
696 "FROM moz_bookmarks b "
697 "LEFT JOIN moz_historyvisits v1 on b.fk = v1.place_id "
698 "LEFT JOIN moz_historyvisits v2 on v2.from_visit = v1.id "
699 "WHERE b.fk IS NOT NULL AND b.type = ?1 "
700 "AND v2.visit_type IN (") +
701 nsPrintfCString("%d,%d",
702 nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT
,
703 nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY
) +
704 NS_LITERAL_CSTRING(") GROUP BY v2.place_id "
706 "SELECT v1.place_id, v2.place_id "
707 "FROM moz_bookmarks b "
708 "LEFT JOIN moz_historyvisits_temp v1 on b.fk = v1.place_id "
709 "LEFT JOIN moz_historyvisits_temp v2 on v2.from_visit = v1.id "
710 "WHERE b.fk IS NOT NULL AND b.type = ?1 "
711 "AND v2.visit_type IN (") +
712 nsPrintfCString("%d,%d",
713 nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT
,
714 nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY
) +
715 NS_LITERAL_CSTRING(") GROUP BY v2.place_id "),
716 getter_AddRefs(statement
));
717 NS_ENSURE_SUCCESS(rv
, rv
);
718 rv
= statement
->BindInt64Parameter(0, TYPE_BOOKMARK
);
719 NS_ENSURE_SUCCESS(rv
, rv
);
720 while (NS_SUCCEEDED(statement
->ExecuteStep(&hasMore
)) && hasMore
) {
721 PRInt64 fromId
, toId
;
722 statement
->GetInt64(0, &fromId
);
723 statement
->GetInt64(1, &toId
);
725 NS_ENSURE_TRUE(mBookmarksHash
.Put(toId
, fromId
), NS_ERROR_OUT_OF_MEMORY
);
727 // handle redirects deeper than one level
728 rv
= RecursiveAddBookmarkHash(fromId
, toId
, 0);
729 NS_ENSURE_SUCCESS(rv
, rv
);
736 // nsNavBookmarks::AddBookmarkToHash
738 // Given a bookmark that was potentially added, this goes through all
739 // redirects that this page may have resulted in and adds them to our hash.
740 // Note that this takes the ID of the URL in the history system, which we
741 // generally have when calling this function and which makes it faster.
743 // For better performance, this call should be in a DB transaction.
745 // @see RecursiveAddBookmarkHash
748 nsNavBookmarks::AddBookmarkToHash(PRInt64 aPlaceId
, PRTime aMinTime
)
750 // this function might be called before our hashtable is initialized (for
751 // example, on history import), just ignore these, we'll pick up the add when
752 // the hashtable is initialized later
753 if (! mBookmarksHash
.IsInitialized())
755 if (! mBookmarksHash
.Put(aPlaceId
, aPlaceId
))
756 return NS_ERROR_OUT_OF_MEMORY
;
757 return RecursiveAddBookmarkHash(aPlaceId
, aPlaceId
, aMinTime
);
761 // nsNavBookmkars::RecursiveAddBookmarkHash
763 // Used to add a new level of redirect information to the bookmark hash.
764 // Given a source bookmark 'aBookmark' and 'aCurrentSource' that has already
765 // been added to the hashtable, this will add all redirect destinations of
766 // 'aCurrentSource'. Will call itself recursively to walk down the chain.
768 // 'aMinTime' is the minimum time to consider visits from. Visits previous
769 // to this will not be considered. This allows the search to be much more
770 // efficient if you know something happened recently. Use 0 for the min time
771 // to search all history for redirects.
774 nsNavBookmarks::RecursiveAddBookmarkHash(PRInt64 aPlaceID
,
775 PRInt64 aCurrentSource
,
779 nsTArray
<PRInt64
> found
;
781 // scope for the DB statement. The statement must be reset by the time we
782 // recursively call ourselves again, because our recursive call will use the
785 mozStorageStatementScoper
scoper(mDBGetRedirectDestinations
);
786 rv
= mDBGetRedirectDestinations
->BindInt64Parameter(0, aCurrentSource
);
787 NS_ENSURE_SUCCESS(rv
, rv
);
788 rv
= mDBGetRedirectDestinations
->BindInt64Parameter(1, aMinTime
);
789 NS_ENSURE_SUCCESS(rv
, rv
);
792 while (NS_SUCCEEDED(mDBGetRedirectDestinations
->ExecuteStep(&hasMore
)) &&
795 // add this newly found redirect destination to the hashtable
797 rv
= mDBGetRedirectDestinations
->GetInt64(0, &curID
);
798 NS_ENSURE_SUCCESS(rv
, rv
);
800 // It is very important we ignore anything already in our hashtable. It
801 // is actually pretty common to get loops of redirects. For example,
802 // a restricted page will redirect you to a login page, which will
803 // redirect you to the restricted page again with the proper cookie.
804 PRInt64 alreadyExistingOne
;
805 if (mBookmarksHash
.Get(curID
, &alreadyExistingOne
))
808 if (! mBookmarksHash
.Put(curID
, aPlaceID
))
809 return NS_ERROR_OUT_OF_MEMORY
;
811 // save for recursion later
812 found
.AppendElement(curID
);
816 // recurse on each found item now that we're done with the statement
817 for (PRUint32 i
= 0; i
< found
.Length(); i
++) {
818 rv
= RecursiveAddBookmarkHash(aPlaceID
, found
[i
], aMinTime
);
819 NS_ENSURE_SUCCESS(rv
, rv
);
826 // nsNavBookmarks::UpdateBookmarkHashOnRemove
828 // Call this when a bookmark is removed. It will see if the bookmark still
829 // exists anywhere in the system, and, if not, remove all references to it
830 // in the bookmark hashtable.
832 // The callback takes a pointer to what bookmark is being removed (as
833 // an Int64 history page ID) as the userArg and removes all redirect
834 // destinations that reference it.
836 static PLDHashOperator
837 RemoveBookmarkHashCallback(nsTrimInt64HashKey::KeyType aKey
,
838 PRInt64
& aPlaceId
, void* aUserArg
)
840 const PRInt64
* removeThisOne
= reinterpret_cast<const PRInt64
*>(aUserArg
);
841 if (aPlaceId
== *removeThisOne
)
842 return PL_DHASH_REMOVE
;
843 return PL_DHASH_NEXT
;
846 nsNavBookmarks::UpdateBookmarkHashOnRemove(PRInt64 aPlaceId
)
848 // note we have to use the DB version here since the hashtable may be
851 nsresult rv
= IsBookmarkedInDatabase(aPlaceId
, &inDB
);
852 NS_ENSURE_SUCCESS(rv
, rv
);
854 return NS_OK
; // bookmark still exists, don't need to update hashtable
857 mBookmarksHash
.Enumerate(RemoveBookmarkHashCallback
,
858 reinterpret_cast<void*>(&aPlaceId
));
863 // nsNavBookmarks::IsBookmarkedInDatabase
865 // This checks to see if the specified URI is actually bookmarked, bypassing
866 // our hashtable. Normal IsBookmarked checks just use the hashtable.
869 nsNavBookmarks::IsBookmarkedInDatabase(PRInt64 aPlaceId
,
870 PRBool
*aIsBookmarked
)
872 mozStorageStatementScoper
scope(mDBIsBookmarkedInDatabase
);
873 nsresult rv
= mDBIsBookmarkedInDatabase
->BindInt64Parameter(0, aPlaceId
);
874 NS_ENSURE_SUCCESS(rv
, rv
);
876 rv
= mDBIsBookmarkedInDatabase
->BindInt32Parameter(1, TYPE_BOOKMARK
);
877 NS_ENSURE_SUCCESS(rv
, rv
);
879 return mDBIsBookmarkedInDatabase
->ExecuteStep(aIsBookmarked
);
884 nsNavBookmarks::AdjustIndices(PRInt64 aFolder
,
885 PRInt32 aStartIndex
, PRInt32 aEndIndex
,
888 NS_ASSERTION(aStartIndex
<= aEndIndex
, "start index must be <= end index");
890 nsCAutoString buffer
;
891 buffer
.AssignLiteral("UPDATE moz_bookmarks SET position = position + ");
892 buffer
.AppendInt(aDelta
);
893 buffer
.AppendLiteral(" WHERE parent = ");
894 buffer
.AppendInt(aFolder
);
896 if (aStartIndex
!= 0) {
897 buffer
.AppendLiteral(" AND position >= ");
898 buffer
.AppendInt(aStartIndex
);
900 if (aEndIndex
!= PR_INT32_MAX
) {
901 buffer
.AppendLiteral(" AND position <= ");
902 buffer
.AppendInt(aEndIndex
);
905 nsresult rv
= mDBConn
->ExecuteSimpleSQL(buffer
);
906 NS_ENSURE_SUCCESS(rv
, rv
);
912 nsNavBookmarks::GetPlacesRoot(PRInt64
*aRoot
)
919 nsNavBookmarks::GetBookmarksMenuFolder(PRInt64
*aRoot
)
921 *aRoot
= mBookmarksRoot
;
926 nsNavBookmarks::GetToolbarFolder(PRInt64
*aFolderId
)
928 *aFolderId
= mToolbarFolder
;
933 nsNavBookmarks::GetTagsFolder(PRInt64
*aRoot
)
940 nsNavBookmarks::GetUnfiledBookmarksFolder(PRInt64
*aRoot
)
942 *aRoot
= mUnfiledRoot
;
947 nsNavBookmarks::InsertBookmark(PRInt64 aFolder
, nsIURI
*aItem
, PRInt32 aIndex
,
948 const nsACString
& aTitle
,
949 PRInt64
*aNewBookmarkId
)
951 // You can pass -1 to indicate append, but no other negative number is allowed
952 if (aIndex
< nsINavBookmarksService::DEFAULT_INDEX
)
953 return NS_ERROR_INVALID_ARG
;
954 NS_ENSURE_ARG_POINTER(aNewBookmarkId
);
956 mozStorageTransaction
transaction(mDBConn
, PR_FALSE
);
958 // This is really a place ID
960 nsresult rv
= History()->GetUrlIdFor(aItem
, &childID
, PR_TRUE
);
961 NS_ENSURE_SUCCESS(rv
, rv
);
964 if (aIndex
== nsINavBookmarksService::DEFAULT_INDEX
) {
965 index
= FolderCount(aFolder
);
968 rv
= AdjustIndices(aFolder
, index
, PR_INT32_MAX
, 1);
969 NS_ENSURE_SUCCESS(rv
, rv
);
973 mozStorageStatementScoper
scope(mDBInsertBookmark
);
974 rv
= mDBInsertBookmark
->BindInt64Parameter(0, childID
);
975 NS_ENSURE_SUCCESS(rv
, rv
);
976 rv
= mDBInsertBookmark
->BindInt32Parameter(1, TYPE_BOOKMARK
);
977 NS_ENSURE_SUCCESS(rv
, rv
);
978 rv
= mDBInsertBookmark
->BindInt64Parameter(2, aFolder
);
979 NS_ENSURE_SUCCESS(rv
, rv
);
980 rv
= mDBInsertBookmark
->BindInt32Parameter(3, index
);
981 NS_ENSURE_SUCCESS(rv
, rv
);
984 rv
= mDBInsertBookmark
->BindNullParameter(4);
986 rv
= mDBInsertBookmark
->BindUTF8StringParameter(4, aTitle
);
987 NS_ENSURE_SUCCESS(rv
, rv
);
989 rv
= mDBInsertBookmark
->BindInt64Parameter(5, PR_Now());
990 NS_ENSURE_SUCCESS(rv
, rv
);
992 rv
= mDBInsertBookmark
->Execute();
993 NS_ENSURE_SUCCESS(rv
, rv
);
996 // get row id of the new bookmark
999 mozStorageStatementScoper
scoper(mDBGetLastBookmarkID
);
1002 rv
= mDBGetLastBookmarkID
->ExecuteStep(&hasResult
);
1003 NS_ENSURE_SUCCESS(rv
, rv
);
1004 NS_ASSERTION(hasResult
, "hasResult is false but the call succeeded?");
1005 rowId
= *aNewBookmarkId
= mDBGetLastBookmarkID
->AsInt64(0);
1009 // 0n import / fx 2 migration, is the frecency work going to slow us down?
1010 // We might want to skip this stuff, as well as the frecency work
1011 // caused by GetUrlIdFor() which calls InternalAddNewPage().
1012 // If we do skip this, after import, we will
1013 // need to call FixInvalidFrecenciesForExcludedPlaces().
1014 // We might need to call it anyways, if items aren't properly annotated
1015 // as livemarks feeds yet.
1018 rv
= aItem
->GetSpec(url
);
1019 NS_ENSURE_SUCCESS(rv
, rv
);
1021 // prevent place: queries from showing up in the URL bar autocomplete results
1022 PRBool isBookmark
= !IsQueryURI(url
);
1025 // if it is a livemark item (the parent is a livemark),
1026 // we pass in false for isBookmark. otherwise, unvisited livemark
1027 // items will appear in URL autocomplete before we visit them.
1028 PRBool parentIsLivemark
;
1029 nsCOMPtr
<nsILivemarkService
> lms
=
1030 do_GetService(NS_LIVEMARKSERVICE_CONTRACTID
, &rv
);
1031 NS_ENSURE_SUCCESS(rv
, rv
);
1033 rv
= lms
->IsLivemark(aFolder
, &parentIsLivemark
);
1034 NS_ENSURE_SUCCESS(rv
, rv
);
1036 isBookmark
= !parentIsLivemark
;
1039 // when we created the moz_place entry for the new bookmark
1040 // (a side effect of calling GetUrlIdFor()) frecency -1;
1041 // now we re-calculate the frecency for this moz_place entry.
1042 rv
= History()->UpdateFrecency(childID
, isBookmark
);
1043 NS_ENSURE_SUCCESS(rv
, rv
);
1045 rv
= SetItemDateInternal(mDBSetItemLastModified
, aFolder
, PR_Now());
1046 NS_ENSURE_SUCCESS(rv
, rv
);
1048 rv
= transaction
.Commit();
1049 NS_ENSURE_SUCCESS(rv
, rv
);
1051 AddBookmarkToHash(childID
, 0);
1053 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
1054 OnItemAdded(rowId
, aFolder
, index
))
1056 // If the bookmark has been added to a tag container, notify all
1057 // bookmark-folder result nodes which contain a bookmark for the new
1059 PRInt64 grandParentId
;
1060 rv
= GetFolderIdForItem(aFolder
, &grandParentId
);
1061 NS_ENSURE_SUCCESS(rv
, rv
);
1062 if (grandParentId
== mTagRoot
) {
1063 // query for all bookmarks for that URI, notify for each
1064 nsTArray
<PRInt64
> bookmarks
;
1066 rv
= GetBookmarkIdsForURITArray(aItem
, &bookmarks
);
1067 NS_ENSURE_SUCCESS(rv
, rv
);
1069 if (bookmarks
.Length()) {
1070 for (PRUint32 i
= 0; i
< bookmarks
.Length(); i
++) {
1071 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
1072 OnItemChanged(bookmarks
[i
], NS_LITERAL_CSTRING("tags"),
1073 PR_FALSE
, EmptyCString()))
1081 nsNavBookmarks::RemoveItem(PRInt64 aItemId
)
1085 PRInt64 placeId
, folderId
;
1087 nsCAutoString buffer
;
1090 { // scoping to ensure the statement gets reset
1091 mozStorageStatementScoper
scope(mDBGetItemProperties
);
1092 mDBGetItemProperties
->BindInt64Parameter(0, aItemId
);
1095 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
1096 NS_ENSURE_SUCCESS(rv
, rv
);
1099 return NS_ERROR_INVALID_ARG
; // invalid bookmark id
1101 childIndex
= mDBGetItemProperties
->AsInt32(kGetItemPropertiesIndex_Position
);
1102 placeId
= mDBGetItemProperties
->AsInt64(kGetItemPropertiesIndex_PlaceID
);
1103 folderId
= mDBGetItemProperties
->AsInt64(kGetItemPropertiesIndex_Parent
);
1104 itemType
= (PRUint16
) mDBGetItemProperties
->AsInt32(kGetItemPropertiesIndex_Type
);
1105 if (itemType
== TYPE_BOOKMARK
) {
1106 rv
= mDBGetItemProperties
->GetUTF8String(kGetItemPropertiesIndex_URI
, spec
);
1107 NS_ENSURE_SUCCESS(rv
, rv
);
1111 if (itemType
== TYPE_FOLDER
) {
1112 rv
= RemoveFolder(aItemId
);
1113 NS_ENSURE_SUCCESS(rv
, rv
);
1117 mozStorageTransaction
transaction(mDBConn
, PR_FALSE
);
1119 // First, remove item annotations
1120 nsAnnotationService
* annosvc
= nsAnnotationService::GetAnnotationService();
1121 NS_ENSURE_TRUE(annosvc
, NS_ERROR_OUT_OF_MEMORY
);
1122 rv
= annosvc
->RemoveItemAnnotations(aItemId
);
1123 NS_ENSURE_SUCCESS(rv
, rv
);
1125 buffer
.AssignLiteral("DELETE FROM moz_bookmarks WHERE id = ");
1126 buffer
.AppendInt(aItemId
);
1128 rv
= mDBConn
->ExecuteSimpleSQL(buffer
);
1129 NS_ENSURE_SUCCESS(rv
, rv
);
1131 if (childIndex
!= -1) {
1132 rv
= AdjustIndices(folderId
, childIndex
+ 1, PR_INT32_MAX
, -1);
1133 NS_ENSURE_SUCCESS(rv
, rv
);
1136 rv
= SetItemDateInternal(mDBSetItemLastModified
, folderId
, PR_Now());
1137 NS_ENSURE_SUCCESS(rv
, rv
);
1139 rv
= transaction
.Commit();
1140 NS_ENSURE_SUCCESS(rv
, rv
);
1142 rv
= UpdateBookmarkHashOnRemove(placeId
);
1143 NS_ENSURE_SUCCESS(rv
, rv
);
1145 // XXX is this too expensive when updating livemarks?
1146 // UpdateBookmarkHashOnRemove() does a sanity check using
1147 // IsBookmarkedInDatabase(), so it might not have actually
1148 // removed the bookmark. should we have a boolean out param
1149 // for if we actually removed it, and use that to decide if we call
1150 // UpdateFrecency() and the rest of this code?
1151 if (itemType
== TYPE_BOOKMARK
) {
1152 rv
= History()->UpdateFrecency(placeId
, PR_FALSE
/* isBookmark */);
1153 NS_ENSURE_SUCCESS(rv
, rv
);
1156 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
1157 OnItemRemoved(aItemId
, folderId
, childIndex
))
1159 if (itemType
== TYPE_BOOKMARK
) {
1160 // If the removed bookmark was a child of a tag container, notify all
1161 // bookmark-folder result nodes which contain a bookmark for the removed
1163 PRInt64 grandParentId
;
1164 rv
= GetFolderIdForItem(folderId
, &grandParentId
);
1165 NS_ENSURE_SUCCESS(rv
, rv
);
1166 if (grandParentId
== mTagRoot
) {
1167 nsCOMPtr
<nsIURI
> uri
;
1168 rv
= NS_NewURI(getter_AddRefs(uri
), spec
);
1169 NS_ENSURE_SUCCESS(rv
, rv
);
1170 nsTArray
<PRInt64
> bookmarks
;
1172 rv
= GetBookmarkIdsForURITArray(uri
, &bookmarks
);
1173 NS_ENSURE_SUCCESS(rv
, rv
);
1175 if (bookmarks
.Length()) {
1176 for (PRUint32 i
= 0; i
< bookmarks
.Length(); i
++) {
1177 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
1178 OnItemChanged(bookmarks
[i
], NS_LITERAL_CSTRING("tags"),
1179 PR_FALSE
, EmptyCString()))
1189 nsNavBookmarks::CreateFolder(PRInt64 aParent
, const nsACString
&aName
,
1190 PRInt32 aIndex
, PRInt64
*aNewFolder
)
1192 // CreateContainerWithID returns the index of the new folder, but that's not
1193 // used here. To avoid any risk of corrupting data should this function
1194 // be changed, we'll use a local variable to hold it. The PR_TRUE argument
1195 // will cause notifications to be sent to bookmark observers.
1196 PRInt32 localIndex
= aIndex
;
1197 return CreateContainerWithID(-1, aParent
, aName
, EmptyString(), PR_TRUE
,
1198 &localIndex
, aNewFolder
);
1202 nsNavBookmarks::CreateDynamicContainer(PRInt64 aParent
, const nsACString
&aName
,
1203 const nsAString
&aContractId
,
1205 PRInt64
*aNewFolder
)
1207 if (aContractId
.IsEmpty())
1208 return NS_ERROR_INVALID_ARG
;
1210 return CreateContainerWithID(-1, aParent
, aName
, aContractId
, PR_FALSE
,
1211 &aIndex
, aNewFolder
);
1215 nsNavBookmarks::GetFolderReadonly(PRInt64 aFolder
, PRBool
*aResult
)
1217 nsAnnotationService
* annosvc
= nsAnnotationService::GetAnnotationService();
1218 NS_ENSURE_TRUE(annosvc
, NS_ERROR_OUT_OF_MEMORY
);
1219 return annosvc
->ItemHasAnnotation(aFolder
, READ_ONLY_ANNO
, aResult
);
1223 nsNavBookmarks::SetFolderReadonly(PRInt64 aFolder
, PRBool aReadOnly
)
1225 nsAnnotationService
* annosvc
= nsAnnotationService::GetAnnotationService();
1226 NS_ENSURE_TRUE(annosvc
, NS_ERROR_OUT_OF_MEMORY
);
1228 return annosvc
->SetItemAnnotationInt32(aFolder
, READ_ONLY_ANNO
, 1,
1230 nsAnnotationService::EXPIRE_NEVER
);
1234 nsresult rv
= annosvc
->ItemHasAnnotation(aFolder
, READ_ONLY_ANNO
, &hasAnno
);
1235 NS_ENSURE_SUCCESS(rv
, rv
);
1237 return annosvc
->RemoveItemAnnotation(aFolder
, READ_ONLY_ANNO
);
1243 nsNavBookmarks::CreateContainerWithID(PRInt64 aItemId
, PRInt64 aParent
,
1244 const nsACString
& aName
,
1245 const nsAString
& aContractId
,
1246 PRBool aIsBookmarkFolder
,
1247 PRInt32
* aIndex
, PRInt64
* aNewFolder
)
1249 // You can pass -1 to indicate append, but no other negative number is allowed
1251 return NS_ERROR_INVALID_ARG
;
1253 mozStorageTransaction
transaction(mDBConn
, PR_FALSE
);
1257 if (*aIndex
== nsINavBookmarksService::DEFAULT_INDEX
) {
1258 index
= FolderCount(aParent
);
1261 rv
= AdjustIndices(aParent
, index
, PR_INT32_MAX
, 1);
1262 NS_ENSURE_SUCCESS(rv
, rv
);
1265 nsCOMPtr
<mozIStorageStatement
> statement
;
1266 if (aItemId
== -1) {
1267 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
1268 "INSERT INTO moz_bookmarks "
1269 "(title, type, parent, position, folder_type, dateAdded) "
1270 "VALUES (?1, ?2, ?3, ?4, ?5, ?6)"),
1271 getter_AddRefs(statement
));
1272 NS_ENSURE_SUCCESS(rv
, rv
);
1275 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
1276 "INSERT INTO moz_bookmarks "
1277 "(id, title, type, parent, position, folder_type, dateAdded) "
1278 "VALUES (?7, ?1, ?2, ?3, ?4, ?5, ?6)"),
1279 getter_AddRefs(statement
));
1280 NS_ENSURE_SUCCESS(rv
, rv
);
1282 rv
= statement
->BindInt64Parameter(6, aItemId
);
1283 NS_ENSURE_SUCCESS(rv
, rv
);
1286 rv
= statement
->BindUTF8StringParameter(0, aName
);
1287 NS_ENSURE_SUCCESS(rv
, rv
);
1289 PRInt32 containerType
=
1290 aIsBookmarkFolder
? TYPE_FOLDER
: TYPE_DYNAMIC_CONTAINER
;
1292 rv
= statement
->BindInt32Parameter(1, containerType
);
1293 NS_ENSURE_SUCCESS(rv
, rv
);
1294 rv
= statement
->BindInt64Parameter(2, aParent
);
1295 NS_ENSURE_SUCCESS(rv
, rv
);
1296 rv
= statement
->BindInt32Parameter(3, index
);
1297 NS_ENSURE_SUCCESS(rv
, rv
);
1298 rv
= statement
->BindStringParameter(4, aContractId
);
1299 NS_ENSURE_SUCCESS(rv
, rv
);
1300 rv
= statement
->BindInt64Parameter(5, PR_Now());
1301 NS_ENSURE_SUCCESS(rv
, rv
);
1303 rv
= statement
->Execute();
1304 NS_ENSURE_SUCCESS(rv
, rv
);
1307 if (aItemId
== -1) {
1308 mozStorageStatementScoper
scoper(mDBGetLastBookmarkID
);
1311 rv
= mDBGetLastBookmarkID
->ExecuteStep(&hasResult
);
1312 NS_ENSURE_SUCCESS(rv
, rv
);
1313 NS_ASSERTION(hasResult
, "hasResult is false but the call succeeded?");
1314 id
= mDBGetLastBookmarkID
->AsInt64(0);
1320 rv
= SetItemDateInternal(mDBSetItemLastModified
, aParent
, PR_Now());
1321 NS_ENSURE_SUCCESS(rv
, rv
);
1323 rv
= transaction
.Commit();
1324 NS_ENSURE_SUCCESS(rv
, rv
);
1326 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
1327 OnItemAdded(id
, aParent
, index
))
1335 nsNavBookmarks::InsertSeparator(PRInt64 aParent
, PRInt32 aIndex
,
1336 PRInt64
* aNewItemId
)
1338 // You can pass -1 to indicate append, but no other negative number is
1341 return NS_ERROR_INVALID_ARG
;
1343 mozStorageTransaction
transaction(mDBConn
, PR_FALSE
);
1347 if (aIndex
== nsINavBookmarksService::DEFAULT_INDEX
) {
1348 index
= FolderCount(aParent
);
1351 rv
= AdjustIndices(aParent
, index
, PR_INT32_MAX
, 1);
1352 NS_ENSURE_SUCCESS(rv
, rv
);
1355 nsCOMPtr
<mozIStorageStatement
> statement
;
1356 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
1357 "INSERT INTO moz_bookmarks "
1358 "(type, parent, position, dateAdded) VALUES (?1, ?2, ?3, ?4)"),
1359 getter_AddRefs(statement
));
1360 NS_ENSURE_SUCCESS(rv
, rv
);
1362 rv
= statement
->BindInt64Parameter(0, TYPE_SEPARATOR
);
1363 NS_ENSURE_SUCCESS(rv
, rv
);
1364 rv
= statement
->BindInt64Parameter(1, aParent
);
1365 NS_ENSURE_SUCCESS(rv
, rv
);
1366 rv
= statement
->BindInt32Parameter(2, index
);
1367 NS_ENSURE_SUCCESS(rv
, rv
);
1368 rv
= statement
->BindInt64Parameter(3, PR_Now());
1369 NS_ENSURE_SUCCESS(rv
, rv
);
1371 rv
= statement
->Execute();
1372 NS_ENSURE_SUCCESS(rv
, rv
);
1376 mozStorageStatementScoper
scoper(mDBGetLastBookmarkID
);
1379 rv
= mDBGetLastBookmarkID
->ExecuteStep(&hasResult
);
1380 NS_ENSURE_SUCCESS(rv
, rv
);
1381 NS_ASSERTION(hasResult
, "hasResult is false but the call succeeded?");
1382 rowId
= *aNewItemId
= mDBGetLastBookmarkID
->AsInt64(0);
1385 rv
= SetItemDateInternal(mDBSetItemLastModified
, aParent
, PR_Now());
1386 NS_ENSURE_SUCCESS(rv
, rv
);
1388 rv
= transaction
.Commit();
1389 NS_ENSURE_SUCCESS(rv
, rv
);
1391 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
1392 OnItemAdded(rowId
, aParent
, index
))
1398 nsNavBookmarks::GetLastChildId(PRInt64 aFolder
, PRInt64
* aItemId
)
1400 nsCOMPtr
<mozIStorageStatement
> statement
;
1401 nsresult rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
1402 "SELECT id FROM moz_bookmarks WHERE parent = ?1 "
1403 "ORDER BY position DESC LIMIT 1"), getter_AddRefs(statement
));
1404 NS_ENSURE_SUCCESS(rv
, rv
);
1406 rv
= statement
->BindInt64Parameter(0, aFolder
);
1407 NS_ENSURE_SUCCESS(rv
, rv
);
1410 rv
= statement
->ExecuteStep(&hasMore
);
1411 NS_ENSURE_SUCCESS(rv
, rv
);
1413 // Item doesn't exist
1414 return NS_ERROR_INVALID_ARG
;
1417 *aItemId
= statement
->AsInt64(0);
1422 nsNavBookmarks::GetIdForItemAt(PRInt64 aFolder
, PRInt32 aIndex
, PRInt64
* aItemId
)
1425 if (aIndex
== nsINavBookmarksService::DEFAULT_INDEX
) {
1426 // we want the last item within aFolder
1427 return GetLastChildId(aFolder
, aItemId
);
1430 // get the item in aFolder with position aIndex
1431 mozStorageStatementScoper
scope(mDBGetChildAt
);
1433 rv
= mDBGetChildAt
->BindInt64Parameter(0, aFolder
);
1434 NS_ENSURE_SUCCESS(rv
, rv
);
1435 rv
= mDBGetChildAt
->BindInt32Parameter(1, aIndex
);
1436 NS_ENSURE_SUCCESS(rv
, rv
);
1439 rv
= mDBGetChildAt
->ExecuteStep(&hasMore
);
1440 NS_ENSURE_SUCCESS(rv
, rv
);
1442 // Item doesn't exist
1443 return NS_ERROR_INVALID_ARG
;
1445 // actually found an item
1446 *aItemId
= mDBGetChildAt
->AsInt64(0);
1453 nsNavBookmarks::RemoveChildAt(PRInt64 aParent
, PRInt32 aIndex
)
1455 mozStorageTransaction
transaction(mDBConn
, PR_FALSE
);
1461 mozStorageStatementScoper
scope(mDBGetChildAt
);
1462 rv
= mDBGetChildAt
->BindInt64Parameter(0, aParent
);
1463 NS_ENSURE_SUCCESS(rv
, rv
);
1464 rv
= mDBGetChildAt
->BindInt32Parameter(1, aIndex
);
1465 NS_ENSURE_SUCCESS(rv
, rv
);
1468 rv
= mDBGetChildAt
->ExecuteStep(&hasMore
);
1469 NS_ENSURE_SUCCESS(rv
, rv
);
1471 // Child doesn't exist
1472 return NS_ERROR_INVALID_ARG
;
1475 id
= mDBGetChildAt
->AsInt64(0);
1476 type
= mDBGetChildAt
->AsInt32(2);
1479 if (type
== TYPE_BOOKMARK
|| type
== TYPE_SEPARATOR
) {
1480 // Commit this transaction so that we don't notify observers mid-tranaction
1481 rv
= transaction
.Commit();
1482 NS_ENSURE_SUCCESS(rv
, rv
);
1484 return RemoveItem(id
);
1486 else if (type
== TYPE_FOLDER
) {
1487 // Commit this transaction so that we don't notify observers mid-tranaction
1488 rv
= transaction
.Commit();
1489 NS_ENSURE_SUCCESS(rv
, rv
);
1491 return RemoveFolder(id
);
1493 return NS_ERROR_INVALID_ARG
;
1497 nsNavBookmarks::GetParentAndIndexOfFolder(PRInt64 aFolder
, PRInt64
* aParent
,
1500 nsCAutoString buffer
;
1501 buffer
.AssignLiteral("SELECT parent, position FROM moz_bookmarks WHERE id = ");
1502 buffer
.AppendInt(aFolder
);
1504 nsCOMPtr
<mozIStorageStatement
> statement
;
1505 nsresult rv
= mDBConn
->CreateStatement(buffer
, getter_AddRefs(statement
));
1506 NS_ENSURE_SUCCESS(rv
, rv
);
1509 rv
= statement
->ExecuteStep(&results
);
1510 NS_ENSURE_SUCCESS(rv
, rv
);
1512 return NS_ERROR_INVALID_ARG
; // folder is not in the hierarchy
1515 *aParent
= statement
->AsInt64(0);
1516 *aIndex
= statement
->AsInt32(1);
1522 nsNavBookmarks::RemoveFolder(PRInt64 aFolderId
)
1524 mozStorageTransaction
transaction(mDBConn
, PR_FALSE
);
1529 PRInt32 index
, type
;
1530 nsCAutoString folderType
;
1532 mozStorageStatementScoper
scope(mDBGetItemProperties
);
1533 rv
= mDBGetItemProperties
->BindInt64Parameter(0, aFolderId
);
1534 NS_ENSURE_SUCCESS(rv
, rv
);
1537 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
1538 NS_ENSURE_SUCCESS(rv
, rv
);
1540 return NS_ERROR_INVALID_ARG
; // folder is not in the hierarchy
1543 type
= mDBGetItemProperties
->AsInt32(kGetItemPropertiesIndex_Type
);
1544 parent
= mDBGetItemProperties
->AsInt64(kGetItemPropertiesIndex_Parent
);
1545 index
= mDBGetItemProperties
->AsInt32(kGetItemPropertiesIndex_Position
);
1546 rv
= mDBGetItemProperties
->GetUTF8String(kGetItemPropertiesIndex_ServiceContractId
, folderType
);
1547 NS_ENSURE_SUCCESS(rv
, rv
);
1550 if (type
!= TYPE_FOLDER
) {
1551 NS_WARNING("RemoveFolder(): aFolderId is not a folder!");
1552 return NS_ERROR_INVALID_ARG
; // aFolderId is not a folder!
1555 // First, remove item annotations
1556 nsAnnotationService
* annosvc
= nsAnnotationService::GetAnnotationService();
1557 NS_ENSURE_TRUE(annosvc
, NS_ERROR_OUT_OF_MEMORY
);
1558 rv
= annosvc
->RemoveItemAnnotations(aFolderId
);
1559 NS_ENSURE_SUCCESS(rv
, rv
);
1561 // If this is a container bookmark, try to notify its service.
1562 if (folderType
.Length() > 0) {
1563 // There is a type associated with this folder.
1564 nsCOMPtr
<nsIDynamicContainer
> bmcServ
= do_GetService(folderType
.get());
1566 rv
= bmcServ
->OnContainerRemoving(aFolderId
);
1568 NS_WARNING("Remove folder container notification failed.");
1572 // Remove all of the folder's children
1573 rv
= RemoveFolderChildren(aFolderId
);
1574 NS_ENSURE_SUCCESS(rv
, rv
);
1576 // Remove the folder from its parent
1577 nsCAutoString buffer
;
1578 buffer
.AssignLiteral("DELETE FROM moz_bookmarks WHERE id = ");
1579 buffer
.AppendInt(aFolderId
);
1580 rv
= mDBConn
->ExecuteSimpleSQL(buffer
);
1581 NS_ENSURE_SUCCESS(rv
, rv
);
1583 rv
= AdjustIndices(parent
, index
+ 1, PR_INT32_MAX
, -1);
1584 NS_ENSURE_SUCCESS(rv
, rv
);
1586 rv
= SetItemDateInternal(mDBSetItemLastModified
, parent
, PR_Now());
1587 NS_ENSURE_SUCCESS(rv
, rv
);
1589 rv
= transaction
.Commit();
1590 NS_ENSURE_SUCCESS(rv
, rv
);
1592 if (aFolderId
== mToolbarFolder
) {
1596 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
1597 OnItemRemoved(aFolderId
, parent
, index
))
1602 NS_IMPL_ISUPPORTS1(nsNavBookmarks::RemoveFolderTransaction
, nsITransaction
)
1605 nsNavBookmarks::GetRemoveFolderTransaction(PRInt64 aFolder
, nsITransaction
** aResult
)
1607 // Create and initialize a RemoveFolderTransaction object that can be used to
1608 // recreate the folder safely later.
1610 RemoveFolderTransaction
* rft
=
1611 new RemoveFolderTransaction(aFolder
);
1613 return NS_ERROR_OUT_OF_MEMORY
;
1615 NS_ADDREF(*aResult
= rft
);
1620 nsNavBookmarks::GetDescendantChildren(PRInt64 aFolderId
,
1621 PRInt64 aGrandParentId
,
1622 nsTArray
<folderChildrenInfo
>& aFolderChildrenArray
) {
1623 // New children will be added from this index on.
1624 PRUint32 startIndex
= aFolderChildrenArray
.Length();
1627 // Collect children informations.
1628 mozStorageStatementScoper
scope(mDBGetChildren
);
1629 rv
= mDBGetChildren
->BindInt64Parameter(0, aFolderId
);
1630 NS_ENSURE_SUCCESS(rv
, rv
);
1633 while (NS_SUCCEEDED(mDBGetChildren
->ExecuteStep(&hasMore
)) && hasMore
) {
1634 folderChildrenInfo child
;
1635 child
.itemId
= mDBGetChildren
->AsInt64(nsNavHistory::kGetInfoIndex_ItemId
);
1636 child
.parentId
= aFolderId
;
1637 child
.grandParentId
= aGrandParentId
;
1638 child
.itemType
= (PRUint16
) mDBGetChildren
->AsInt32(kGetChildrenIndex_Type
);
1639 child
.placeId
= mDBGetChildren
->AsInt64(kGetChildrenIndex_PlaceID
);
1640 child
.index
= mDBGetChildren
->AsInt32(kGetChildrenIndex_Position
);
1642 if (child
.itemType
== TYPE_BOOKMARK
) {
1643 nsCAutoString URIString
;
1644 rv
= mDBGetChildren
->GetUTF8String(nsNavHistory::kGetInfoIndex_URL
,
1646 NS_ENSURE_SUCCESS(rv
, rv
);
1647 child
.url
= URIString
;
1649 else if (child
.itemType
== TYPE_FOLDER
) {
1650 nsCAutoString folderType
;
1651 rv
= mDBGetChildren
->GetUTF8String(kGetChildrenIndex_ServiceContractId
,
1653 NS_ENSURE_SUCCESS(rv
, rv
);
1654 child
.folderType
= folderType
;
1656 // Append item to children's array.
1657 aFolderChildrenArray
.AppendElement(child
);
1661 // Recursively call GetDescendantChildren for added folders.
1662 // We start at startIndex since previous folders are checked
1663 // by previous calls to this method.
1664 PRUint32 childCount
= aFolderChildrenArray
.Length();
1665 for (PRUint32 i
= startIndex
; i
< childCount
; i
++) {
1666 if (aFolderChildrenArray
[i
].itemType
== TYPE_FOLDER
) {
1667 GetDescendantChildren(aFolderChildrenArray
[i
].itemId
,
1669 aFolderChildrenArray
);
1677 nsNavBookmarks::RemoveFolderChildren(PRInt64 aFolderId
)
1681 PRInt64 grandParentId
;
1683 mozStorageStatementScoper
scope(mDBGetItemProperties
);
1684 rv
= mDBGetItemProperties
->BindInt64Parameter(0, aFolderId
);
1685 NS_ENSURE_SUCCESS(rv
, rv
);
1687 // Sanity check: ensure that item exists.
1688 PRBool folderExists
;
1689 if (NS_FAILED(mDBGetItemProperties
->ExecuteStep(&folderExists
)) || !folderExists
)
1690 return NS_ERROR_INVALID_ARG
;
1692 // Sanity check: ensure that this is a folder.
1693 itemType
= (PRUint16
) mDBGetItemProperties
->AsInt32(kGetItemPropertiesIndex_Type
);
1694 if (itemType
!= TYPE_FOLDER
)
1695 return NS_ERROR_INVALID_ARG
;
1697 // Get the grandParent.
1698 // We have to do this only once since recursion will give us other
1699 // grandParents without the need of additional queries.
1700 grandParentId
= mDBGetItemProperties
->AsInt64(kGetItemPropertiesIndex_Parent
);
1703 // Fill folder children array recursively.
1704 nsTArray
<folderChildrenInfo
> folderChildrenArray
;
1705 rv
= GetDescendantChildren(aFolderId
, grandParentId
, folderChildrenArray
);
1706 NS_ENSURE_SUCCESS(rv
, rv
);
1708 // Build a string of folders whose children will be removed.
1709 nsCString foldersToRemove
;
1710 for (PRUint32 i
= 0; i
< folderChildrenArray
.Length(); i
++) {
1711 folderChildrenInfo child
= folderChildrenArray
[i
];
1712 if (child
.itemType
== TYPE_FOLDER
) {
1713 foldersToRemove
.AppendLiteral(",");
1714 foldersToRemove
.AppendInt(child
.itemId
);
1716 // If this is a dynamic container, try to notify its service that we
1717 // are going to remove it.
1718 if (child
.folderType
.Length() > 0) {
1719 nsCOMPtr
<nsIDynamicContainer
> bmcServ
=
1720 do_GetService(child
.folderType
.get());
1722 rv
= bmcServ
->OnContainerRemoving(child
.itemId
);
1724 NS_WARNING("Remove folder container notification failed.");
1730 // Delete items from the database now.
1731 mozStorageTransaction
transaction(mDBConn
, PR_FALSE
);
1733 rv
= mDBConn
->ExecuteSimpleSQL(
1735 "DELETE FROM moz_bookmarks "
1736 "WHERE parent IN (") +
1737 nsPrintfCString("%d", aFolderId
) +
1739 NS_LITERAL_CSTRING(")"));
1740 NS_ENSURE_SUCCESS(rv
, rv
);
1742 // Clean up orphan items annotations.
1743 rv
= mDBConn
->ExecuteSimpleSQL(
1745 "DELETE FROM moz_items_annos "
1747 "SELECT a.id from moz_items_annos a "
1748 "LEFT JOIN moz_bookmarks b ON a.item_id = b.id "
1749 "WHERE b.id ISNULL)"));
1750 NS_ENSURE_SUCCESS(rv
, rv
);
1752 // Set the lastModified date.
1753 rv
= SetItemDateInternal(mDBSetItemLastModified
, aFolderId
, PR_Now());
1754 NS_ENSURE_SUCCESS(rv
, rv
);
1756 for (PRUint32 i
= 0; i
< folderChildrenArray
.Length(); i
++) {
1757 folderChildrenInfo child
= folderChildrenArray
[i
];
1758 if (child
.itemType
== TYPE_BOOKMARK
) {
1759 PRInt64 placeId
= child
.placeId
;
1760 UpdateBookmarkHashOnRemove(placeId
);
1762 // XXX is this too expensive when updating livemarks?
1763 // UpdateBookmarkHashOnRemove() does a sanity check using
1764 // IsBookmarkedInDatabase(), so it might not have actually
1765 // removed the bookmark. should we have a boolean out param
1766 // for if we actually removed it, and use that to decide if we call
1767 // UpdateFrecency() and the rest of this code?
1768 rv
= History()->UpdateFrecency(placeId
, PR_FALSE
/* isBookmark */);
1769 NS_ENSURE_SUCCESS(rv
, rv
);
1773 rv
= transaction
.Commit();
1774 NS_ENSURE_SUCCESS(rv
, rv
);
1776 // Call observers in reverse order to serve children before their parent.
1777 for (PRInt32 i
= folderChildrenArray
.Length() - 1; i
>= 0 ; i
--) {
1778 folderChildrenInfo child
= folderChildrenArray
[i
];
1780 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
1781 OnItemRemoved(child
.itemId
,
1785 if (child
.itemType
== TYPE_BOOKMARK
) {
1786 // If the removed bookmark was a child of a tag container, notify all
1787 // bookmark-folder result nodes which contain a bookmark for the removed
1790 if (child
.grandParentId
== mTagRoot
) {
1791 nsCOMPtr
<nsIURI
> uri
;
1792 rv
= NS_NewURI(getter_AddRefs(uri
), child
.url
);
1793 NS_ENSURE_SUCCESS(rv
, rv
);
1795 nsTArray
<PRInt64
> bookmarks
;
1796 rv
= GetBookmarkIdsForURITArray(uri
, &bookmarks
);
1797 NS_ENSURE_SUCCESS(rv
, rv
);
1799 if (bookmarks
.Length()) {
1800 for (PRUint32 i
= 0; i
< bookmarks
.Length(); i
++) {
1801 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
1802 OnItemChanged(bookmarks
[i
], NS_LITERAL_CSTRING("tags"),
1803 PR_FALSE
, EmptyCString()))
1814 nsNavBookmarks::MoveItem(PRInt64 aItemId
, PRInt64 aNewParent
, PRInt32 aIndex
)
1816 // You can pass -1 to indicate append, but no other negative number is allowed
1818 return NS_ERROR_INVALID_ARG
;
1820 // Disallow making an item its own parent.
1821 if (aItemId
== aNewParent
)
1822 return NS_ERROR_INVALID_ARG
;
1824 mozStorageTransaction
transaction(mDBConn
, PR_FALSE
);
1826 // get item properties
1831 nsCAutoString folderType
;
1833 mozStorageStatementScoper
scope(mDBGetItemProperties
);
1834 rv
= mDBGetItemProperties
->BindInt64Parameter(0, aItemId
);
1835 NS_ENSURE_SUCCESS(rv
, rv
);
1838 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
1839 NS_ENSURE_SUCCESS(rv
, rv
);
1841 return NS_ERROR_INVALID_ARG
; // folder is not in the hierarchy
1844 oldParent
= mDBGetItemProperties
->AsInt64(kGetItemPropertiesIndex_Parent
);
1845 oldIndex
= mDBGetItemProperties
->AsInt32(kGetItemPropertiesIndex_Position
);
1846 itemType
= (PRUint16
) mDBGetItemProperties
->AsInt32(kGetItemPropertiesIndex_Type
);
1847 if (itemType
== TYPE_FOLDER
) {
1848 rv
= mDBGetItemProperties
->GetUTF8String(kGetItemPropertiesIndex_ServiceContractId
,
1850 NS_ENSURE_SUCCESS(rv
, rv
);
1854 // if parent and index are the same, nothing to do
1855 if (oldParent
== aNewParent
&& oldIndex
== aIndex
)
1858 // Make sure aNewParent is not aFolder or a subfolder of aFolder
1859 if (itemType
== TYPE_FOLDER
) {
1860 PRInt64 p
= aNewParent
;
1863 mozStorageStatementScoper
scope(mDBGetItemProperties
);
1865 return NS_ERROR_INVALID_ARG
;
1868 rv
= mDBGetItemProperties
->BindInt64Parameter(0, p
);
1869 NS_ENSURE_SUCCESS(rv
, rv
);
1872 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
1873 NS_ENSURE_SUCCESS(rv
, rv
);
1874 p
= results
? mDBGetItemProperties
->AsInt64(kGetItemPropertiesIndex_Parent
) : 0;
1878 // calculate new index
1880 if (aIndex
== nsINavBookmarksService::DEFAULT_INDEX
) {
1881 newIndex
= FolderCount(aNewParent
);
1882 // If the parent remains the same, then the folder is really being moved
1883 // to count - 1 (since it's being removed from the old position)
1884 if (oldParent
== aNewParent
) {
1890 if (oldParent
== aNewParent
&& newIndex
> oldIndex
) {
1891 // when an item is being moved lower in the same folder, the new index
1892 // refers to the index before it was removed. Removal causes everything
1898 // this is like the previous check, except this covers if
1899 // the specified index was -1 (append), and the calculated
1900 // new index is the same as the existing index
1901 if (aNewParent
== oldParent
&& newIndex
== oldIndex
) {
1906 // adjust indices to account for the move
1907 // do this before we update the parent/index fields
1908 // or we'll re-adjust the index for the item we are moving
1909 if (oldParent
== aNewParent
) {
1910 // We can optimize the updates if moving within the same container.
1911 // We only shift the items between the old and new positions, since the
1912 // insertion will offset the deletion.
1913 if (oldIndex
> newIndex
) {
1914 rv
= AdjustIndices(oldParent
, newIndex
, oldIndex
- 1, 1);
1916 rv
= AdjustIndices(oldParent
, oldIndex
+ 1, newIndex
, -1);
1919 // We're moving between containers, so this happens in two steps.
1920 // First, fill the hole from the removal from the old parent.
1921 rv
= AdjustIndices(oldParent
, oldIndex
+ 1, PR_INT32_MAX
, -1);
1922 NS_ENSURE_SUCCESS(rv
, rv
);
1923 // Now, make room in the new parent for the insertion.
1924 rv
= AdjustIndices(aNewParent
, newIndex
, PR_INT32_MAX
, 1);
1926 NS_ENSURE_SUCCESS(rv
, rv
);
1928 // update parent/index fields
1929 nsCAutoString buffer
;
1930 buffer
.AssignLiteral("UPDATE moz_bookmarks SET ");
1931 if (aNewParent
!= oldParent
) {
1932 buffer
.AppendLiteral(" parent = ");
1933 buffer
.AppendInt(aNewParent
);
1935 if (newIndex
!= oldIndex
) {
1936 if (aNewParent
!= oldParent
)
1937 buffer
.AppendLiteral(", ");
1938 buffer
.AppendLiteral(" position = ");
1939 buffer
.AppendInt(newIndex
);
1941 buffer
.AppendLiteral(" WHERE id = ");
1942 buffer
.AppendInt(aItemId
);
1943 rv
= mDBConn
->ExecuteSimpleSQL(buffer
);
1944 NS_ENSURE_SUCCESS(rv
, rv
);
1946 PRTime now
= PR_Now();
1947 rv
= SetItemDateInternal(mDBSetItemLastModified
, oldParent
, now
);
1948 NS_ENSURE_SUCCESS(rv
, rv
);
1949 rv
= SetItemDateInternal(mDBSetItemLastModified
, aNewParent
, now
);
1950 NS_ENSURE_SUCCESS(rv
, rv
);
1952 rv
= transaction
.Commit();
1953 NS_ENSURE_SUCCESS(rv
, rv
);
1955 // notify bookmark observers
1956 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
1957 OnItemMoved(aItemId
, oldParent
, oldIndex
, aNewParent
,
1960 // notify dynamic container provider if there is one
1961 if (!folderType
.IsEmpty()) {
1962 nsCOMPtr
<nsIDynamicContainer
> container
=
1963 do_GetService(folderType
.get(), &rv
);
1964 if (NS_SUCCEEDED(rv
)) {
1965 rv
= container
->OnContainerMoved(aItemId
, aNewParent
, newIndex
);
1966 NS_ENSURE_SUCCESS(rv
, rv
);
1973 nsNavBookmarks::GetChildFolder(PRInt64 aFolder
, const nsAString
& aSubFolder
,
1976 // note: we allow empty folder names
1979 return NS_ERROR_INVALID_ARG
;
1981 // If this gets used a lot, we'll want a precompiled statement
1982 nsCAutoString getChildFolderQuery
=
1983 NS_LITERAL_CSTRING("SELECT id "
1984 "FROM moz_bookmarks "
1985 "WHERE parent = ?1 AND type = ") +
1986 nsPrintfCString("%d", TYPE_FOLDER
) +
1987 NS_LITERAL_CSTRING(" AND title = ?2");
1988 nsCOMPtr
<mozIStorageStatement
> statement
;
1989 rv
= mDBConn
->CreateStatement(getChildFolderQuery
, getter_AddRefs(statement
));
1990 NS_ENSURE_SUCCESS(rv
, rv
);
1991 statement
->BindInt64Parameter(0, aFolder
);
1992 statement
->BindStringParameter(1, aSubFolder
);
1994 PRBool hasResult
= PR_FALSE
;
1995 rv
= statement
->ExecuteStep(&hasResult
);
1996 NS_ENSURE_SUCCESS(rv
, rv
);
2004 return statement
->GetInt64(0, _result
);
2008 nsNavBookmarks::SetItemDateInternal(mozIStorageStatement
* aStatement
, PRInt64 aItemId
, PRTime aValue
)
2010 mozStorageStatementScoper
scope(aStatement
);
2011 nsresult rv
= aStatement
->BindInt64Parameter(0, aValue
);
2012 NS_ENSURE_SUCCESS(rv
, rv
);
2013 rv
= aStatement
->BindInt64Parameter(1, aItemId
);
2014 NS_ENSURE_SUCCESS(rv
, rv
);
2016 rv
= aStatement
->Execute();
2017 NS_ENSURE_SUCCESS(rv
, rv
);
2019 // note, we are not notifying the observers
2020 // that the item has changed.
2026 nsNavBookmarks::SetItemDateAdded(PRInt64 aItemId
, PRTime aDateAdded
)
2028 nsresult rv
= SetItemDateInternal(mDBSetItemDateAdded
, aItemId
, aDateAdded
);
2029 NS_ENSURE_SUCCESS(rv
, rv
);
2031 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2032 OnItemChanged(aItemId
, NS_LITERAL_CSTRING("dateAdded"),
2033 PR_FALSE
, nsPrintfCString(16, "%lld", aDateAdded
)));
2038 nsNavBookmarks::GetItemDateAdded(PRInt64 aItemId
, PRTime
*aDateAdded
)
2040 NS_ENSURE_ARG_POINTER(aDateAdded
);
2042 mozStorageStatementScoper
scope(mDBGetItemProperties
);
2043 nsresult rv
= mDBGetItemProperties
->BindInt64Parameter(0, aItemId
);
2044 NS_ENSURE_SUCCESS(rv
, rv
);
2047 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
2048 NS_ENSURE_SUCCESS(rv
, rv
);
2051 return NS_ERROR_INVALID_ARG
; // invalid item id
2053 return mDBGetItemProperties
->GetInt64(kGetItemPropertiesIndex_DateAdded
, aDateAdded
);
2057 nsNavBookmarks::SetItemLastModified(PRInt64 aItemId
, PRTime aLastModified
)
2059 nsresult rv
= SetItemDateInternal(mDBSetItemLastModified
, aItemId
, aLastModified
);
2060 NS_ENSURE_SUCCESS(rv
, rv
);
2062 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2063 OnItemChanged(aItemId
, NS_LITERAL_CSTRING("lastModified"),
2064 PR_FALSE
, nsPrintfCString(16, "%lld", aLastModified
)));
2069 nsNavBookmarks::GetItemLastModified(PRInt64 aItemId
, PRTime
*aLastModified
)
2071 NS_ENSURE_ARG_POINTER(aLastModified
);
2073 mozStorageStatementScoper
scope(mDBGetItemProperties
);
2074 nsresult rv
= mDBGetItemProperties
->BindInt64Parameter(0, aItemId
);
2075 NS_ENSURE_SUCCESS(rv
, rv
);
2078 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
2079 NS_ENSURE_SUCCESS(rv
, rv
);
2082 return NS_ERROR_INVALID_ARG
; // invalid item id
2084 return mDBGetItemProperties
->GetInt64(kGetItemPropertiesIndex_LastModified
, aLastModified
);
2088 nsNavBookmarks::GetGUIDBase(nsAString
&aGUIDBase
)
2090 if (!mGUIDBase
.IsEmpty()) {
2091 aGUIDBase
= mGUIDBase
;
2095 // generate a new GUID base for this session
2096 nsCOMPtr
<nsIUUIDGenerator
> uuidgen
=
2097 do_GetService("@mozilla.org/uuid-generator;1");
2098 NS_ENSURE_TRUE(uuidgen
, NS_ERROR_OUT_OF_MEMORY
);
2100 nsresult rv
= uuidgen
->GenerateUUIDInPlace(&GUID
);
2101 NS_ENSURE_SUCCESS(rv
, rv
);
2102 char GUIDChars
[NSID_LENGTH
];
2103 GUID
.ToProvidedString(GUIDChars
);
2104 CopyASCIItoUTF16(GUIDChars
, mGUIDBase
);
2105 aGUIDBase
= mGUIDBase
;
2110 nsNavBookmarks::GetItemGUID(PRInt64 aItemId
, nsAString
&aGUID
)
2112 nsAnnotationService
* annosvc
= nsAnnotationService::GetAnnotationService();
2113 NS_ENSURE_TRUE(annosvc
, NS_ERROR_OUT_OF_MEMORY
);
2114 nsresult rv
= annosvc
->GetItemAnnotationString(aItemId
, GUID_ANNO
, aGUID
);
2116 if (NS_SUCCEEDED(rv
) || rv
!= NS_ERROR_NOT_AVAILABLE
)
2120 tmp
.AppendInt(mItemCount
++);
2121 aGUID
.SetCapacity(NSID_LENGTH
- 1 + tmp
.Length());
2123 rv
= GetGUIDBase(GUIDBase
);
2124 NS_ENSURE_SUCCESS(rv
, rv
);
2125 aGUID
.Assign(GUIDBase
);
2128 return SetItemGUID(aItemId
, aGUID
);
2132 nsNavBookmarks::SetItemGUID(PRInt64 aItemId
, const nsAString
&aGUID
)
2135 GetItemIdForGUID(aGUID
, &checkId
);
2137 return NS_ERROR_INVALID_ARG
; // invalid GUID, already exists
2139 nsAnnotationService
* annosvc
= nsAnnotationService::GetAnnotationService();
2140 NS_ENSURE_TRUE(annosvc
, NS_ERROR_OUT_OF_MEMORY
);
2141 return annosvc
->SetItemAnnotationString(aItemId
, GUID_ANNO
, aGUID
, 0,
2142 nsIAnnotationService::EXPIRE_NEVER
);
2146 nsNavBookmarks::GetItemIdForGUID(const nsAString
&aGUID
, PRInt64
*aItemId
)
2148 mozStorageStatementScoper
scoper(mDBGetItemIdForGUID
);
2149 nsresult rv
= mDBGetItemIdForGUID
->BindStringParameter(0, aGUID
);
2150 NS_ENSURE_SUCCESS(rv
, rv
);
2152 PRBool hasMore
= PR_FALSE
;
2153 rv
= mDBGetItemIdForGUID
->ExecuteStep(&hasMore
);
2154 if (NS_FAILED(rv
) || ! hasMore
) {
2156 return NS_OK
; // not found: return -1
2159 // found, get the itemId
2160 return mDBGetItemIdForGUID
->GetInt64(0, aItemId
);
2164 nsNavBookmarks::SetItemTitle(PRInt64 aItemId
, const nsACString
&aTitle
)
2166 nsCOMPtr
<mozIStorageStatement
> statement
;
2167 nsresult rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
2168 "UPDATE moz_bookmarks SET title = ?1, lastModified = ?2 WHERE id = ?3"),
2169 getter_AddRefs(statement
));
2170 NS_ENSURE_SUCCESS(rv
, rv
);
2171 rv
= statement
->BindUTF8StringParameter(0, aTitle
);
2172 NS_ENSURE_SUCCESS(rv
, rv
);
2173 rv
= statement
->BindInt64Parameter(1, PR_Now());
2174 NS_ENSURE_SUCCESS(rv
, rv
);
2175 rv
= statement
->BindInt64Parameter(2, aItemId
);
2176 NS_ENSURE_SUCCESS(rv
, rv
);
2178 rv
= statement
->Execute();
2179 NS_ENSURE_SUCCESS(rv
, rv
);
2181 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2182 OnItemChanged(aItemId
, NS_LITERAL_CSTRING("title"),
2188 nsNavBookmarks::GetItemTitle(PRInt64 aItemId
, nsACString
&aTitle
)
2190 mozStorageStatementScoper
scope(mDBGetItemProperties
);
2192 nsresult rv
= mDBGetItemProperties
->BindInt64Parameter(0, aItemId
);
2193 NS_ENSURE_SUCCESS(rv
, rv
);
2196 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
2197 NS_ENSURE_SUCCESS(rv
, rv
);
2200 return NS_ERROR_INVALID_ARG
; // invalid bookmark id
2202 return mDBGetItemProperties
->GetUTF8String(kGetItemPropertiesIndex_Title
, aTitle
);
2206 nsNavBookmarks::GetBookmarkURI(PRInt64 aItemId
, nsIURI
**aURI
)
2208 NS_ENSURE_ARG_POINTER(aURI
);
2210 mozStorageStatementScoper
scope(mDBGetItemProperties
);
2211 nsresult rv
= mDBGetItemProperties
->BindInt64Parameter(0, aItemId
);
2212 NS_ENSURE_SUCCESS(rv
, rv
);
2215 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
2216 NS_ENSURE_SUCCESS(rv
, rv
);
2219 return NS_ERROR_INVALID_ARG
; // invalid bookmark id
2221 PRInt32 type
= mDBGetItemProperties
->AsInt32(kGetItemPropertiesIndex_Type
);
2222 if (type
!= TYPE_BOOKMARK
)
2223 return NS_ERROR_INVALID_ARG
; // invalid type (only for bookmarks)
2226 rv
= mDBGetItemProperties
->GetUTF8String(kGetItemPropertiesIndex_URI
, spec
);
2227 NS_ENSURE_SUCCESS(rv
, rv
);
2229 rv
= NS_NewURI(aURI
, spec
);
2230 NS_ENSURE_SUCCESS(rv
, rv
);
2236 nsNavBookmarks::GetItemType(PRInt64 aItemId
, PRUint16
*aType
)
2238 mozStorageStatementScoper
scope(mDBGetItemProperties
);
2240 nsresult rv
= mDBGetItemProperties
->BindInt64Parameter(0, aItemId
);
2241 NS_ENSURE_SUCCESS(rv
, rv
);
2244 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
2245 NS_ENSURE_SUCCESS(rv
, rv
);
2248 return NS_ERROR_INVALID_ARG
; // invalid bookmark id
2251 *aType
= (PRUint16
)mDBGetItemProperties
->AsInt32(kGetItemPropertiesIndex_Type
);
2256 nsNavBookmarks::GetFolderType(PRInt64 aFolder
, nsACString
&aType
)
2258 mozStorageStatementScoper
scope(mDBGetItemProperties
);
2259 nsresult rv
= mDBGetItemProperties
->BindInt64Parameter(0, aFolder
);
2260 NS_ENSURE_SUCCESS(rv
, rv
);
2263 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
2264 NS_ENSURE_SUCCESS(rv
, rv
);
2267 return NS_ERROR_INVALID_ARG
;
2270 return mDBGetItemProperties
->GetUTF8String(kGetItemPropertiesIndex_ServiceContractId
, aType
);
2274 nsNavBookmarks::ResultNodeForContainer(PRInt64 aID
,
2275 nsNavHistoryQueryOptions
*aOptions
,
2276 nsNavHistoryResultNode
**aNode
)
2278 mozStorageStatementScoper
scope(mDBGetItemProperties
);
2279 mDBGetItemProperties
->BindInt64Parameter(0, aID
);
2282 nsresult rv
= mDBGetItemProperties
->ExecuteStep(&results
);
2283 NS_ENSURE_SUCCESS(rv
, rv
);
2284 NS_ASSERTION(results
, "ResultNodeForContainer expects a valid item id");
2287 nsCAutoString contractId
;
2288 rv
= mDBGetItemProperties
->GetUTF8String(kGetItemPropertiesIndex_ServiceContractId
,
2290 NS_ENSURE_SUCCESS(rv
, rv
);
2293 nsCAutoString title
;
2294 rv
= mDBGetItemProperties
->GetUTF8String(kGetItemPropertiesIndex_Title
, title
);
2296 PRUint16 itemType
= (PRUint16
) mDBGetItemProperties
->AsInt32(kGetItemPropertiesIndex_Type
);
2297 if (itemType
== TYPE_DYNAMIC_CONTAINER
) {
2298 *aNode
= new nsNavHistoryContainerResultNode(EmptyCString(), title
, EmptyCString(),
2299 nsINavHistoryResultNode::RESULT_TYPE_DYNAMIC_CONTAINER
,
2303 (*aNode
)->mItemId
= aID
;
2304 } else { // TYPE_FOLDER
2305 *aNode
= new nsNavHistoryFolderResultNode(title
, aOptions
, aID
, contractId
);
2308 return NS_ERROR_OUT_OF_MEMORY
;
2310 (*aNode
)->mDateAdded
=
2311 mDBGetItemProperties
->AsInt64(kGetItemPropertiesIndex_DateAdded
);
2312 (*aNode
)->mLastModified
=
2313 mDBGetItemProperties
->AsInt64(kGetItemPropertiesIndex_LastModified
);
2320 nsNavBookmarks::QueryFolderChildren(PRInt64 aFolderId
,
2321 nsNavHistoryQueryOptions
*aOptions
,
2322 nsCOMArray
<nsNavHistoryResultNode
> *aChildren
)
2324 mozStorageStatementScoper
scope(mDBGetChildren
);
2326 nsresult rv
= mDBGetChildren
->BindInt64Parameter(0, aFolderId
);
2327 NS_ENSURE_SUCCESS(rv
, rv
);
2331 nsCOMPtr
<nsNavHistoryQueryOptions
> options
= do_QueryInterface(aOptions
, &rv
);
2332 NS_ENSURE_SUCCESS(rv
, rv
);
2335 while (NS_SUCCEEDED(mDBGetChildren
->ExecuteStep(&results
)) && results
) {
2337 // The results will be in order of index. Even if we don't add a node
2338 // because it was excluded, we need to count its index, so do that
2339 // before doing anything else. Index was initialized to -1 above, so
2340 // it will start counting at 0 the first time through the loop.
2343 PRUint16 itemType
= (PRUint16
) mDBGetChildren
->AsInt32(kGetChildrenIndex_Type
);
2344 PRInt64 id
= mDBGetChildren
->AsInt64(nsNavHistory::kGetInfoIndex_ItemId
);
2345 nsRefPtr
<nsNavHistoryResultNode
> node
;
2346 if (itemType
== TYPE_BOOKMARK
) {
2347 rv
= History()->RowToResult(mDBGetChildren
, options
,
2348 getter_AddRefs(node
));
2349 NS_ENSURE_SUCCESS(rv
, rv
);
2352 node
->GetType(&nodeType
);
2353 if ((nodeType
== nsINavHistoryResultNode::RESULT_TYPE_QUERY
&&
2354 aOptions
->ExcludeQueries()) ||
2355 (nodeType
!= nsINavHistoryResultNode::RESULT_TYPE_QUERY
&&
2356 nodeType
!= nsINavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT
&&
2357 aOptions
->ExcludeItems())) {
2360 } else if (itemType
== TYPE_FOLDER
|| itemType
== TYPE_DYNAMIC_CONTAINER
) {
2361 if (options
->ExcludeReadOnlyFolders()) {
2362 // see if it's read only and skip it
2363 PRBool readOnly
= PR_FALSE
;
2364 GetFolderReadonly(id
, &readOnly
);
2369 rv
= ResultNodeForContainer(id
, aOptions
, getter_AddRefs(node
));
2374 if (aOptions
->ExcludeItems()) {
2377 node
= new nsNavHistorySeparatorResultNode();
2378 NS_ENSURE_TRUE(node
, NS_ERROR_OUT_OF_MEMORY
);
2380 // add the item identifier (RowToResult does so for bookmark items in
2381 // the next else block);
2383 mDBGetChildren
->AsInt64(nsNavHistory::kGetInfoIndex_ItemId
);
2385 // date-added and last-modified
2387 mDBGetChildren
->AsInt64(nsNavHistory::kGetInfoIndex_ItemDateAdded
);
2388 node
->mLastModified
=
2389 mDBGetChildren
->AsInt64(nsNavHistory::kGetInfoIndex_ItemLastModified
);
2392 // this method fills all bookmark queries, so we store the index of the
2393 // item in its parent
2394 node
->mBookmarkIndex
= index
;
2396 NS_ENSURE_TRUE(aChildren
->AppendObject(node
), NS_ERROR_OUT_OF_MEMORY
);
2402 nsNavBookmarks::FolderCount(PRInt64 aFolder
)
2404 mozStorageStatementScoper
scope(mDBFolderCount
);
2406 nsresult rv
= mDBFolderCount
->BindInt64Parameter(0, aFolder
);
2407 NS_ENSURE_SUCCESS(rv
, 0);
2410 rv
= mDBFolderCount
->ExecuteStep(&results
);
2411 NS_ENSURE_SUCCESS(rv
, rv
);
2413 return mDBFolderCount
->AsInt32(0);
2417 nsNavBookmarks::IsBookmarked(nsIURI
*aURI
, PRBool
*aBookmarked
)
2419 NS_ENSURE_ARG(aURI
);
2421 nsNavHistory
* history
= History();
2422 NS_ENSURE_TRUE(history
, NS_ERROR_UNEXPECTED
);
2424 // convert the URL to an ID
2426 nsresult rv
= history
->GetUrlIdFor(aURI
, &urlID
, PR_FALSE
);
2427 NS_ENSURE_SUCCESS(rv
, rv
);
2429 // never seen this before, not even in history
2430 *aBookmarked
= PR_FALSE
;
2434 PRInt64 bookmarkedID
;
2435 PRBool foundOne
= mBookmarksHash
.Get(urlID
, &bookmarkedID
);
2437 // IsBookmarked only tests if this exact URI is bookmarked, so we need to
2438 // check that the destination matches
2440 *aBookmarked
= (urlID
== bookmarkedID
);
2442 *aBookmarked
= PR_FALSE
;
2445 // sanity check for the bookmark hashtable
2446 PRBool realBookmarked
;
2447 rv
= IsBookmarkedInDatabase(urlID
, &realBookmarked
);
2448 NS_ASSERTION(realBookmarked
== *aBookmarked
,
2449 "Bookmark hash table out-of-sync with the database");
2456 nsNavBookmarks::GetBookmarkedURIFor(nsIURI
* aURI
, nsIURI
** _retval
)
2460 nsNavHistory
* history
= History();
2461 NS_ENSURE_TRUE(history
, NS_ERROR_UNEXPECTED
);
2463 // convert the URL to an ID
2465 nsresult rv
= history
->GetUrlIdFor(aURI
, &urlID
, PR_FALSE
);
2466 NS_ENSURE_SUCCESS(rv
, rv
);
2468 // never seen this before, not even in history, leave result NULL
2473 if (mBookmarksHash
.Get(urlID
, &bookmarkID
)) {
2474 // found one, convert ID back to URL. This statement is NOT refcounted
2475 mozIStorageStatement
* statement
= history
->DBGetIdPageInfo();
2476 NS_ENSURE_TRUE(statement
, NS_ERROR_UNEXPECTED
);
2477 mozStorageStatementScoper
scoper(statement
);
2479 rv
= statement
->BindInt64Parameter(0, bookmarkID
);
2480 NS_ENSURE_SUCCESS(rv
, rv
);
2483 if (NS_SUCCEEDED(statement
->ExecuteStep(&hasMore
)) && hasMore
) {
2485 statement
->GetUTF8String(nsNavHistory::kGetInfoIndex_URL
, spec
);
2486 return NS_NewURI(_retval
, spec
);
2493 nsNavBookmarks::ChangeBookmarkURI(PRInt64 aBookmarkId
, nsIURI
*aNewURI
)
2495 NS_ENSURE_ARG(aNewURI
);
2497 mozStorageTransaction
transaction(mDBConn
, PR_FALSE
);
2500 nsresult rv
= History()->GetUrlIdFor(aNewURI
, &placeId
, PR_TRUE
);
2501 NS_ENSURE_SUCCESS(rv
, rv
);
2503 return NS_ERROR_INVALID_ARG
;
2505 nsCOMPtr
<mozIStorageStatement
> statement
;
2506 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
2507 "UPDATE moz_bookmarks SET fk = ?1 WHERE id = ?2"),
2508 getter_AddRefs(statement
));
2509 statement
->BindInt64Parameter(0, placeId
);
2510 statement
->BindInt64Parameter(1, aBookmarkId
);
2512 rv
= statement
->Execute();
2513 NS_ENSURE_SUCCESS(rv
, rv
);
2515 rv
= SetItemDateInternal(mDBSetItemLastModified
, aBookmarkId
, PR_Now());
2516 NS_ENSURE_SUCCESS(rv
, rv
);
2518 rv
= transaction
.Commit();
2519 NS_ENSURE_SUCCESS(rv
, rv
);
2521 // upon changing the uri for a bookmark, update the frecency for the new place
2522 // no need to check if this is a livemark, because...
2523 rv
= History()->UpdateFrecency(placeId
, PR_TRUE
/* isBookmark */);
2524 NS_ENSURE_SUCCESS(rv
, rv
);
2527 // upon changing the uri for a bookmark, update the frecency for the old place
2528 // XXX todo, we need to get the oldPlaceId (fk) before changing it above
2529 // and then here, we need to determine if that oldPlaceId is still a bookmark (and not a livemark)
2530 rv
= History()->UpdateFrecency(oldPlaceId
, PR_FALSE
/* isBookmark */);
2531 NS_ENSURE_SUCCESS(rv
, rv
);
2535 rv
= aNewURI
->GetSpec(spec
);
2536 NS_ENSURE_SUCCESS(rv
, rv
);
2538 // Pass the new URI to OnItemChanged.
2539 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2540 OnItemChanged(aBookmarkId
, NS_LITERAL_CSTRING("uri"), PR_FALSE
, spec
))
2546 nsNavBookmarks::GetFolderIdForItem(PRInt64 aItemId
, PRInt64
*aFolderId
)
2548 NS_ENSURE_ARG_POINTER(aFolderId
);
2550 mozStorageStatementScoper
scope(mDBGetItemProperties
);
2551 nsresult rv
= mDBGetItemProperties
->BindInt64Parameter(0, aItemId
);
2552 NS_ENSURE_SUCCESS(rv
, rv
);
2555 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
2556 NS_ENSURE_SUCCESS(rv
, rv
);
2559 return NS_ERROR_INVALID_ARG
; // invalid item id
2561 rv
= mDBGetItemProperties
->GetInt64(kGetItemPropertiesIndex_Parent
, aFolderId
);
2562 NS_ENSURE_SUCCESS(rv
, rv
);
2564 // this should not happen, but see bug #400448 for details
2565 NS_ENSURE_TRUE(aItemId
!= *aFolderId
, NS_ERROR_UNEXPECTED
);
2570 nsNavBookmarks::GetBookmarkIdsForURITArray(nsIURI
*aURI
,
2571 nsTArray
<PRInt64
> *aResult
)
2573 mozStorageStatementScoper
scope(mDBFindURIBookmarks
);
2575 nsresult rv
= BindStatementURI(mDBFindURIBookmarks
, 0, aURI
);
2576 NS_ENSURE_SUCCESS(rv
, rv
);
2577 mDBFindURIBookmarks
->BindInt32Parameter(1, TYPE_BOOKMARK
);
2580 while (NS_SUCCEEDED((rv
= mDBFindURIBookmarks
->ExecuteStep(&more
))) && more
) {
2581 if (! aResult
->AppendElement(
2582 mDBFindURIBookmarks
->AsInt64(kFindBookmarksIndex_ID
)))
2583 return NS_ERROR_OUT_OF_MEMORY
;
2586 NS_ENSURE_SUCCESS(rv
, rv
);
2591 nsNavBookmarks::GetBookmarkIdsForURI(nsIURI
*aURI
, PRUint32
*aCount
,
2592 PRInt64
**aBookmarks
)
2595 *aBookmarks
= nsnull
;
2596 nsTArray
<PRInt64
> bookmarks
;
2598 // Get the information from the DB as a TArray
2599 nsresult rv
= GetBookmarkIdsForURITArray(aURI
, &bookmarks
);
2600 NS_ENSURE_SUCCESS(rv
, rv
);
2602 // Copy the results into a new array for output
2603 if (bookmarks
.Length()) {
2604 *aBookmarks
= static_cast<PRInt64
*>
2605 (nsMemory::Alloc(sizeof(PRInt64
) * bookmarks
.Length()));
2607 return NS_ERROR_OUT_OF_MEMORY
;
2608 for (PRUint32 i
= 0; i
< bookmarks
.Length(); i
++)
2609 (*aBookmarks
)[i
] = bookmarks
[i
];
2611 *aCount
= bookmarks
.Length();
2617 nsNavBookmarks::GetItemIndex(PRInt64 aItemId
, PRInt32
*aIndex
)
2619 mozStorageStatementScoper
scope(mDBGetItemIndex
);
2620 mDBGetItemIndex
->BindInt64Parameter(0, aItemId
);
2622 nsresult rv
= mDBGetItemIndex
->ExecuteStep(&results
);
2623 NS_ENSURE_SUCCESS(rv
, rv
);
2629 *aIndex
= mDBGetItemIndex
->AsInt32(0);
2634 nsNavBookmarks::SetItemIndex(PRInt64 aItemId
, PRInt32 aNewIndex
)
2637 PRInt32 oldIndex
= 0;
2641 mozStorageStatementScoper
scopeGet(mDBGetItemProperties
);
2642 rv
= mDBGetItemProperties
->BindInt64Parameter(0, aItemId
);
2643 NS_ENSURE_SUCCESS(rv
, rv
);
2646 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
2647 NS_ENSURE_SUCCESS(rv
, rv
);
2651 oldIndex
= mDBGetItemProperties
->AsInt32(kGetItemPropertiesIndex_Position
);
2652 parent
= mDBGetItemProperties
->AsInt64(kGetItemPropertiesIndex_Parent
);
2655 mozStorageStatementScoper
scoper(mDBSetItemIndex
);
2656 rv
= mDBSetItemIndex
->BindInt64Parameter(0, aItemId
);
2657 NS_ENSURE_SUCCESS(rv
, rv
);
2658 rv
= mDBSetItemIndex
->BindInt32Parameter(1, aNewIndex
);
2659 NS_ENSURE_SUCCESS(rv
, rv
);
2661 rv
= mDBSetItemIndex
->Execute();
2662 NS_ENSURE_SUCCESS(rv
, rv
);
2664 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2665 OnItemRemoved(aItemId
, parent
, oldIndex
))
2666 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2667 OnItemAdded(aItemId
, parent
, aNewIndex
))
2673 nsNavBookmarks::SetKeywordForBookmark(PRInt64 aBookmarkId
, const nsAString
& aKeyword
)
2675 if (aBookmarkId
< 1)
2676 return NS_ERROR_INVALID_ARG
; // invalid bookmark id
2678 // Shortcuts are always lowercased internally.
2679 nsAutoString
kwd(aKeyword
);
2682 mozStorageTransaction
transaction(mDBConn
, PR_FALSE
);
2685 PRInt64 keywordId
= 0;
2687 if (!kwd
.IsEmpty()) {
2688 // Attempt to find pre-existing keyword record
2689 nsCOMPtr
<mozIStorageStatement
> getKeywordStmnt
;
2690 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
2691 "SELECT id from moz_keywords WHERE keyword = ?1"),
2692 getter_AddRefs(getKeywordStmnt
));
2693 NS_ENSURE_SUCCESS(rv
, rv
);
2694 rv
= getKeywordStmnt
->BindStringParameter(0, kwd
);
2695 NS_ENSURE_SUCCESS(rv
, rv
);
2697 rv
= getKeywordStmnt
->ExecuteStep(&results
);
2698 NS_ENSURE_SUCCESS(rv
, rv
);
2701 rv
= getKeywordStmnt
->GetInt64(0, &keywordId
);
2702 NS_ENSURE_SUCCESS(rv
, rv
);
2705 // If not already in the db, create new keyword record
2706 nsCOMPtr
<mozIStorageStatement
> addKeywordStmnt
;
2707 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
2708 "INSERT INTO moz_keywords (keyword) VALUES (?1)"),
2709 getter_AddRefs(addKeywordStmnt
));
2710 NS_ENSURE_SUCCESS(rv
, rv
);
2711 rv
= addKeywordStmnt
->BindStringParameter(0, kwd
);
2712 NS_ENSURE_SUCCESS(rv
, rv
);
2713 rv
= addKeywordStmnt
->Execute();
2714 NS_ENSURE_SUCCESS(rv
, rv
);
2716 nsCOMPtr
<mozIStorageStatement
> idStmt
;
2717 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
2719 "FROM moz_keywords "
2720 "ORDER BY ROWID DESC "
2722 getter_AddRefs(idStmt
));
2723 NS_ENSURE_SUCCESS(rv
, rv
);
2726 rv
= idStmt
->ExecuteStep(&hasResult
);
2727 NS_ENSURE_SUCCESS(rv
, rv
);
2728 NS_ASSERTION(hasResult
, "hasResult is false but the call succeeded?");
2729 keywordId
= idStmt
->AsInt64(0);
2733 // Update bookmark record w/ the keyword's id, or null
2734 nsCOMPtr
<mozIStorageStatement
> updateKeywordStmnt
;
2735 rv
= mDBConn
->CreateStatement(NS_LITERAL_CSTRING(
2736 "UPDATE moz_bookmarks SET keyword_id = ?1 WHERE id = ?2"),
2737 getter_AddRefs(updateKeywordStmnt
));
2738 NS_ENSURE_SUCCESS(rv
, rv
);
2739 rv
= updateKeywordStmnt
->BindInt64Parameter(0, keywordId
);
2740 NS_ENSURE_SUCCESS(rv
, rv
);
2741 rv
= updateKeywordStmnt
->BindInt64Parameter(1, aBookmarkId
);
2742 NS_ENSURE_SUCCESS(rv
, rv
);
2743 rv
= updateKeywordStmnt
->Execute();
2744 NS_ENSURE_SUCCESS(rv
, rv
);
2746 rv
= SetItemDateInternal(mDBSetItemLastModified
, aBookmarkId
, PR_Now());
2747 NS_ENSURE_SUCCESS(rv
, rv
);
2749 transaction
.Commit();
2751 // Pass the new keyword to OnItemChanged.
2752 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2753 OnItemChanged(aBookmarkId
, NS_LITERAL_CSTRING("keyword"),
2754 PR_FALSE
, NS_ConvertUTF16toUTF8(aKeyword
)))
2760 nsNavBookmarks::GetKeywordForURI(nsIURI
* aURI
, nsAString
& aKeyword
)
2762 aKeyword
.Truncate(0);
2764 mozStorageStatementScoper
scoper(mDBGetKeywordForURI
);
2765 nsresult rv
= BindStatementURI(mDBGetKeywordForURI
, 0, aURI
);
2766 NS_ENSURE_SUCCESS(rv
, rv
);
2768 PRBool hasMore
= PR_FALSE
;
2769 rv
= mDBGetKeywordForURI
->ExecuteStep(&hasMore
);
2770 if (NS_FAILED(rv
) || ! hasMore
) {
2771 aKeyword
.SetIsVoid(PR_TRUE
);
2772 return NS_OK
; // not found: return void keyword string
2775 // found, get the keyword
2776 return mDBGetKeywordForURI
->GetString(0, aKeyword
);
2780 nsNavBookmarks::GetKeywordForBookmark(PRInt64 aBookmarkId
, nsAString
& aKeyword
)
2782 aKeyword
.Truncate(0);
2784 mozStorageStatementScoper
scoper(mDBGetKeywordForBookmark
);
2785 nsresult rv
= mDBGetKeywordForBookmark
->BindInt64Parameter(0, aBookmarkId
);
2786 NS_ENSURE_SUCCESS(rv
, rv
);
2788 PRBool hasMore
= PR_FALSE
;
2789 rv
= mDBGetKeywordForBookmark
->ExecuteStep(&hasMore
);
2790 if (NS_FAILED(rv
) || ! hasMore
) {
2791 aKeyword
.SetIsVoid(PR_TRUE
);
2792 return NS_OK
; // not found: return void keyword string
2795 // found, get the keyword
2796 return mDBGetKeywordForBookmark
->GetString(0, aKeyword
);
2800 nsNavBookmarks::GetURIForKeyword(const nsAString
& aKeyword
, nsIURI
** aURI
)
2803 if (aKeyword
.IsEmpty())
2804 return NS_ERROR_INVALID_ARG
;
2806 // Shortcuts are always lowercased internally.
2807 nsAutoString
kwd(aKeyword
);
2810 mozStorageStatementScoper
scoper(mDBGetURIForKeyword
);
2811 nsresult rv
= mDBGetURIForKeyword
->BindStringParameter(0, kwd
);
2812 NS_ENSURE_SUCCESS(rv
, rv
);
2814 PRBool hasMore
= PR_FALSE
;
2815 rv
= mDBGetURIForKeyword
->ExecuteStep(&hasMore
);
2816 if (NS_FAILED(rv
) || ! hasMore
)
2817 return NS_OK
; // not found: leave URI null
2819 // found, get the URI
2821 rv
= mDBGetURIForKeyword
->GetUTF8String(0, spec
);
2822 NS_ENSURE_SUCCESS(rv
, rv
);
2823 return NS_NewURI(aURI
, spec
);
2826 // See RunInBatchMode
2828 nsNavBookmarks::BeginUpdateBatch()
2830 if (mBatchLevel
++ == 0) {
2831 mozIStorageConnection
* conn
= mDBConn
;
2832 PRBool transactionInProgress
= PR_TRUE
; // default to no transaction on err
2833 conn
->GetTransactionInProgress(&transactionInProgress
);
2834 mBatchHasTransaction
= ! transactionInProgress
;
2835 if (mBatchHasTransaction
)
2836 conn
->BeginTransaction();
2838 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2839 OnBeginUpdateBatch())
2845 nsNavBookmarks::EndUpdateBatch()
2847 if (--mBatchLevel
== 0) {
2848 if (mBatchHasTransaction
)
2849 mDBConn
->CommitTransaction();
2850 mBatchHasTransaction
= PR_FALSE
;
2851 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2858 nsNavBookmarks::RunInBatchMode(nsINavHistoryBatchCallback
* aCallback
,
2859 nsISupports
* aUserData
) {
2860 NS_ENSURE_ARG_POINTER(aCallback
);
2863 nsresult rv
= aCallback
->RunBatched(aUserData
);
2870 nsNavBookmarks::AddObserver(nsINavBookmarkObserver
*aObserver
,
2873 return mObservers
.AppendWeakElement(aObserver
, aOwnsWeak
);
2877 nsNavBookmarks::RemoveObserver(nsINavBookmarkObserver
*aObserver
)
2879 return mObservers
.RemoveWeakElement(aObserver
);
2883 * Called by the History service when shutting down
2886 nsNavBookmarks::OnQuit()
2891 // nsNavBookmarks::nsINavHistoryObserver
2894 nsNavBookmarks::OnBeginUpdateBatch()
2896 // These aren't passed through to bookmark observers currently.
2901 nsNavBookmarks::OnEndUpdateBatch()
2903 // These aren't passed through to bookmark observers currently.
2908 nsNavBookmarks::OnVisit(nsIURI
*aURI
, PRInt64 aVisitID
, PRTime aTime
,
2909 PRInt64 aSessionID
, PRInt64 aReferringID
,
2910 PRUint32 aTransitionType
, PRUint32
* aAdded
)
2912 // If the page is bookmarked, we need to notify observers
2913 PRBool bookmarked
= PR_FALSE
;
2914 IsBookmarked(aURI
, &bookmarked
);
2916 // query for all bookmarks for that URI, notify for each
2917 nsTArray
<PRInt64
> bookmarks
;
2919 nsresult rv
= GetBookmarkIdsForURITArray(aURI
, &bookmarks
);
2920 NS_ENSURE_SUCCESS(rv
, rv
);
2922 if (bookmarks
.Length()) {
2923 for (PRUint32 i
= 0; i
< bookmarks
.Length(); i
++)
2924 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2925 OnItemVisited(bookmarks
[i
], aVisitID
, aTime
))
2932 nsNavBookmarks::OnDeleteURI(nsIURI
*aURI
)
2934 // If the page is bookmarked, we need to notify observers
2935 PRBool bookmarked
= PR_FALSE
;
2936 IsBookmarked(aURI
, &bookmarked
);
2938 // query for all bookmarks for that URI, notify for each
2939 nsTArray
<PRInt64
> bookmarks
;
2941 nsresult rv
= GetBookmarkIdsForURITArray(aURI
, &bookmarks
);
2942 NS_ENSURE_SUCCESS(rv
, rv
);
2944 if (bookmarks
.Length()) {
2945 for (PRUint32 i
= 0; i
< bookmarks
.Length(); i
++)
2946 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2947 OnItemChanged(bookmarks
[i
], NS_LITERAL_CSTRING("cleartime"),
2948 PR_FALSE
, EmptyCString()))
2955 nsNavBookmarks::OnClearHistory()
2957 // TODO(bryner): we should notify on visited-time change for all URIs
2962 nsNavBookmarks::OnTitleChanged(nsIURI
* aURI
, const nsAString
& aPageTitle
)
2964 // NOOP. We don't consume page titles from moz_places anymore.
2965 // Title-change notifications are sent from SetItemTitle.
2970 nsNavBookmarks::OnPageChanged(nsIURI
*aURI
, PRUint32 aWhat
,
2971 const nsAString
&aValue
)
2974 if (aWhat
== nsINavHistoryObserver::ATTRIBUTE_FAVICON
) {
2975 // Favicons may be set to either pure URIs or to folder URIs
2977 rv
= aURI
->SchemeIs("place", &isPlaceURI
);
2978 NS_ENSURE_SUCCESS(rv
, rv
);
2981 rv
= aURI
->GetSpec(spec
);
2982 NS_ENSURE_SUCCESS(rv
, rv
);
2984 nsNavHistory
* history
= History();
2985 NS_ENSURE_TRUE(history
, NS_ERROR_UNEXPECTED
);
2987 nsCOMArray
<nsNavHistoryQuery
> queries
;
2988 nsCOMPtr
<nsNavHistoryQueryOptions
> options
;
2989 rv
= history
->QueryStringToQueryArray(spec
, &queries
, getter_AddRefs(options
));
2990 NS_ENSURE_SUCCESS(rv
, rv
);
2992 NS_ENSURE_STATE(queries
.Count() == 1);
2993 NS_ENSURE_STATE(queries
[0]->Folders().Length() == 1);
2995 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
2996 OnItemChanged(queries
[0]->Folders()[0], NS_LITERAL_CSTRING("favicon"),
2997 PR_FALSE
, NS_ConvertUTF16toUTF8(aValue
)));
3000 // query for all bookmarks for that URI, notify for each
3001 nsTArray
<PRInt64
> bookmarks
;
3002 rv
= GetBookmarkIdsForURITArray(aURI
, &bookmarks
);
3003 NS_ENSURE_SUCCESS(rv
, rv
);
3005 if (bookmarks
.Length()) {
3006 for (PRUint32 i
= 0; i
< bookmarks
.Length(); i
++)
3007 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
3008 OnItemChanged(bookmarks
[i
], NS_LITERAL_CSTRING("favicon"),
3009 PR_FALSE
, NS_ConvertUTF16toUTF8(aValue
)));
3017 nsNavBookmarks::OnPageExpired(nsIURI
* aURI
, PRTime aVisitTime
,
3020 // pages that are bookmarks shouldn't expire, so we don't need to handle it
3024 // nsIAnnotationObserver
3027 nsNavBookmarks::OnPageAnnotationSet(nsIURI
* aPage
, const nsACString
& aName
)
3033 nsNavBookmarks::OnItemAnnotationSet(PRInt64 aItemId
, const nsACString
& aName
)
3035 nsresult rv
= SetItemDateInternal(mDBSetItemLastModified
, aItemId
, PR_Now());
3036 NS_ENSURE_SUCCESS(rv
, rv
);
3038 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
3039 OnItemChanged(aItemId
, aName
, PR_TRUE
, EmptyCString()));
3046 nsNavBookmarks::OnPageAnnotationRemoved(nsIURI
* aPage
, const nsACString
& aName
)
3052 nsNavBookmarks::OnItemAnnotationRemoved(PRInt64 aItemId
, const nsACString
& aName
)
3054 nsresult rv
= SetItemDateInternal(mDBSetItemLastModified
, aItemId
, PR_Now());
3055 NS_ENSURE_SUCCESS(rv
, rv
);
3057 ENUMERATE_WEAKARRAY(mObservers
, nsINavBookmarkObserver
,
3058 OnItemChanged(aItemId
, aName
, PR_TRUE
, EmptyCString()));
3064 nsNavBookmarks::ItemExists(PRInt64 aItemId
) {
3065 mozStorageStatementScoper
scope(mDBGetItemProperties
);
3066 nsresult rv
= mDBGetItemProperties
->BindInt64Parameter(0, aItemId
);
3067 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);
3070 rv
= mDBGetItemProperties
->ExecuteStep(&results
);
3071 NS_ENSURE_SUCCESS(rv
, PR_FALSE
);