1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 /**
7 * The definitions of objects that make up a history query result set. This file
8 * should only be included by nsNavHistory.h, include that if you want these
9 * classes.
10 */
11
12 #ifndef nsNavHistoryResult_h_
13 #define nsNavHistoryResult_h_
14
15 #include "INativePlacesEventCallback.h"
16 #include "nsTArray.h"
17 #include "nsMaybeWeakPtr.h"
18 #include "nsInterfaceHashtable.h"
19 #include "nsTHashMap.h"
20 #include "nsCycleCollectionParticipant.h"
21 #include "mozilla/storage.h"
22 #include "Helpers.h"
23
24 class nsNavHistory;
25 class nsNavHistoryQuery;
26 class nsNavHistoryQueryOptions;
27
28 class nsNavHistoryContainerResultNode;
29 class nsNavHistoryFolderResultNode;
30 class nsNavHistoryQueryResultNode;
31
32 /**
33 * hashkey wrapper using int64_t KeyType
34 *
35 * @see nsTHashtable::EntryType for specification
36 *
37 * This just truncates the 64-bit int to a 32-bit one for using a hash number.
38 * It is used for bookmark folder IDs, which should be way less than 2^32.
39 */
40 class nsTrimInt64HashKey : public PLDHashEntryHdr {
41 public:
42 typedef const int64_t& KeyType;
43 typedef const int64_t* KeyTypePointer;
44
nsTrimInt64HashKey(KeyTypePointer aKey)45 explicit nsTrimInt64HashKey(KeyTypePointer aKey) : mValue(*aKey) {}
nsTrimInt64HashKey(const nsTrimInt64HashKey & toCopy)46 nsTrimInt64HashKey(const nsTrimInt64HashKey& toCopy)
47 : mValue(toCopy.mValue) {}
48 ~nsTrimInt64HashKey() = default;
49
GetKey()50 KeyType GetKey() const { return mValue; }
KeyEquals(KeyTypePointer aKey)51 bool KeyEquals(KeyTypePointer aKey) const { return *aKey == mValue; }
52
KeyToPointer(KeyType aKey)53 static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
HashKey(KeyTypePointer aKey)54 static PLDHashNumber HashKey(KeyTypePointer aKey) {
55 return static_cast<uint32_t>((*aKey) & UINT32_MAX);
56 }
57 enum { ALLOW_MEMMOVE = true };
58
59 private:
60 const int64_t mValue;
61 };
62
63 // nsNavHistoryResult
64 //
65 // nsNavHistory creates this object and fills in mChildren (by getting
66 // it through GetTopLevel()). Then FilledAllResults() is called to finish
67 // object initialization.
68
69 #define NS_NAVHISTORYRESULT_IID \
70 { \
71 0x455d1d40, 0x1b9b, 0x40e6, { \
72 0xa6, 0x41, 0x8b, 0xb7, 0xe8, 0x82, 0x23, 0x87 \
73 } \
74 }
75
76 class nsNavHistoryResult final
77 : public nsSupportsWeakReference,
78 public nsINavHistoryResult,
79 public nsINavBookmarkObserver,
80 public mozilla::places::INativePlacesEventCallback {
81 public:
82 NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYRESULT_IID)
83
84 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
85 NS_DECL_NSINAVHISTORYRESULT
86 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNavHistoryResult,
87 nsINavHistoryResult)
88 NS_DECL_NSINAVBOOKMARKOBSERVER;
89
90 void AddHistoryObserver(nsNavHistoryQueryResultNode* aNode);
91 void AddBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode,
92 const nsACString& aFolderGUID);
93 void AddAllBookmarksObserver(nsNavHistoryQueryResultNode* aNode);
94 void AddMobilePrefsObserver(nsNavHistoryQueryResultNode* aNode);
95 void RemoveHistoryObserver(nsNavHistoryQueryResultNode* aNode);
96 void RemoveBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode,
97 const nsACString& aFolderGUID);
98 void RemoveAllBookmarksObserver(nsNavHistoryQueryResultNode* aNode);
99 void RemoveMobilePrefsObserver(nsNavHistoryQueryResultNode* aNode);
100 void StopObserving();
101 void EnsureIsObservingBookmarks();
102
103 nsresult OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
104 uint32_t aTransitionType, const nsACString& aGUID,
105 bool aHidden, uint32_t aVisitCount,
106 const nsAString& aLastKnownTitle);
107
108 void OnIconChanged(nsIURI* aURI, nsIURI* aFaviconURI,
109 const nsACString& aGUID);
110
111 explicit nsNavHistoryResult(nsNavHistoryContainerResultNode* mRoot,
112 const RefPtr<nsNavHistoryQuery>& aQuery,
113 const RefPtr<nsNavHistoryQueryOptions>& aOptions);
114
115 RefPtr<nsNavHistoryContainerResultNode> mRootNode;
116
117 RefPtr<nsNavHistoryQuery> mQuery;
118 RefPtr<nsNavHistoryQueryOptions> mOptions;
119
120 // One of nsNavHistoryQueryOptions.SORY_BY_* This is initialized to
121 // mOptions.sortingMode, but may be overridden if the user clicks on one of
122 // the columns.
123 uint16_t mSortingMode;
124 // If root node is closed and we try to apply a sortingMode, it would not
125 // work. So we will apply it when the node will be reopened and populated.
126 // This var states the fact we need to apply sortingMode in such a situation.
127 bool mNeedsToApplySortingMode;
128
129 // node observers
130 bool mIsHistoryObserver;
131 bool mIsBookmarksObserver;
132 bool mIsMobilePrefObserver;
133
134 typedef nsTArray<RefPtr<nsNavHistoryQueryResultNode> > QueryObserverList;
135 QueryObserverList mHistoryObservers;
136 QueryObserverList mAllBookmarksObservers;
137 QueryObserverList mMobilePrefObservers;
138
139 typedef nsTArray<RefPtr<nsNavHistoryFolderResultNode> > FolderObserverList;
140 nsTHashMap<nsCStringHashKey, FolderObserverList*> mBookmarkFolderObservers;
141 FolderObserverList* BookmarkFolderObserversForGUID(const nsACString& aGUID,
142 bool aCreate);
143
144 typedef nsTArray<RefPtr<nsNavHistoryContainerResultNode> >
145 ContainerObserverList;
146
147 void RecursiveExpandCollapse(nsNavHistoryContainerResultNode* aContainer,
148 bool aExpand);
149
150 void InvalidateTree();
151
152 nsMaybeWeakPtrArray<nsINavHistoryResultObserver> mObservers;
153 bool mSuppressNotifications;
154
155 // Tracks whether observers for history details were added.
156 bool mIsHistoryDetailsObserver;
157 // Tracks whether any result observer is interested in history details
158 // updates.
159 bool mObserversWantHistoryDetails;
160 /**
161 * Updates mObserversWantHistoryDetails when observers are added/removed.
162 * @returns Whether we started observing for history changes.
163 */
164 bool UpdateHistoryDetailsObservers();
165 // Whether NodeHistoryDetailsChanged can be skipped.
166 bool CanSkipHistoryDetailsNotifications() const;
167
168 ContainerObserverList mRefreshParticipants;
169 void requestRefresh(nsNavHistoryContainerResultNode* aContainer);
170
171 void HandlePlacesEvent(const PlacesEventSequence& aEvents) override;
172
173 void OnMobilePrefChanged();
174
IsBatching()175 bool IsBatching() const { return mBatchInProgress > 0; };
176
177 static void OnMobilePrefChangedCallback(const char* prefName, void* self);
178
179 protected:
180 virtual ~nsNavHistoryResult();
181
182 private:
183 // Number of batch processes currently running. IsBatching() returns true if
184 // this value is greater than or equal to 1. Also, when this value changes to
185 // 1 from 0, batching() in nsINavHistoryResultObserver is called with
186 // parameter as true, when changes to 0, that means finishing all batch
187 // processes, batching() is called with false.
188 uint32_t mBatchInProgress;
189
190 // Stop all observers upon unlinking.
191 void StopObservingOnUnlink();
192 };
193
NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResult,NS_NAVHISTORYRESULT_IID)194 NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResult, NS_NAVHISTORYRESULT_IID)
195
196 // nsNavHistoryResultNode
197 //
198 // This is the base class for every node in a result set. The result itself
199 // is a node (nsNavHistoryResult inherits from this), as well as every
200 // leaf and branch on the tree.
201
202 #define NS_NAVHISTORYRESULTNODE_IID \
203 { \
204 0x54b61d38, 0x57c1, 0x11da, { \
205 0x95, 0xb8, 0x00, 0x13, 0x21, 0xc9, 0xf6, 0x9e \
206 } \
207 }
208
209 // These are all the simple getters, they can be used for the result node
210 // implementation and all subclasses. More complex are GetIcon, GetParent
211 // (which depends on the definition of container result node), and GetUri
212 // (which is overridded for lazy construction for some containers).
213 #define NS_IMPLEMENT_SIMPLE_RESULTNODE \
214 NS_IMETHOD GetTitle(nsACString& aTitle) override { \
215 aTitle = mTitle; \
216 return NS_OK; \
217 } \
218 NS_IMETHOD GetAccessCount(uint32_t* aAccessCount) override { \
219 *aAccessCount = mAccessCount; \
220 return NS_OK; \
221 } \
222 NS_IMETHOD GetTime(PRTime* aTime) override { \
223 *aTime = mTime; \
224 return NS_OK; \
225 } \
226 NS_IMETHOD GetIndentLevel(int32_t* aIndentLevel) override { \
227 *aIndentLevel = mIndentLevel; \
228 return NS_OK; \
229 } \
230 NS_IMETHOD GetBookmarkIndex(int32_t* aIndex) override { \
231 *aIndex = mBookmarkIndex; \
232 return NS_OK; \
233 } \
234 NS_IMETHOD GetDateAdded(PRTime* aDateAdded) override { \
235 *aDateAdded = mDateAdded; \
236 return NS_OK; \
237 } \
238 NS_IMETHOD GetLastModified(PRTime* aLastModified) override { \
239 *aLastModified = mLastModified; \
240 return NS_OK; \
241 } \
242 NS_IMETHOD GetItemId(int64_t* aId) override { \
243 *aId = mItemId; \
244 return NS_OK; \
245 }
246
247 // This is used by the base classes instead of
248 // NS_FORWARD_NSINAVHISTORYRESULTNODE(nsNavHistoryResultNode) because they
249 // need to redefine GetType and GetUri rather than forwarding them. This
250 // implements all the simple getters instead of forwarding because they are so
251 // short and we can save a virtual function call.
252 //
253 // (GetUri is redefined only by QueryResultNode and FolderResultNode because
254 // the query might not necessarily be parsed. The rest just return the node's
255 // buffer.)
256 #define NS_FORWARD_COMMON_RESULTNODE_TO_BASE \
257 NS_IMPLEMENT_SIMPLE_RESULTNODE \
258 NS_IMETHOD GetIcon(nsACString& aIcon) override { \
259 return nsNavHistoryResultNode::GetIcon(aIcon); \
260 } \
261 NS_IMETHOD GetParent(nsINavHistoryContainerResultNode** aParent) override { \
262 return nsNavHistoryResultNode::GetParent(aParent); \
263 } \
264 NS_IMETHOD GetParentResult(nsINavHistoryResult** aResult) override { \
265 return nsNavHistoryResultNode::GetParentResult(aResult); \
266 } \
267 NS_IMETHOD GetTags(nsAString& aTags) override { \
268 return nsNavHistoryResultNode::GetTags(aTags); \
269 } \
270 NS_IMETHOD GetPageGuid(nsACString& aPageGuid) override { \
271 return nsNavHistoryResultNode::GetPageGuid(aPageGuid); \
272 } \
273 NS_IMETHOD GetBookmarkGuid(nsACString& aBookmarkGuid) override { \
274 return nsNavHistoryResultNode::GetBookmarkGuid(aBookmarkGuid); \
275 } \
276 NS_IMETHOD GetVisitId(int64_t* aVisitId) override { \
277 return nsNavHistoryResultNode::GetVisitId(aVisitId); \
278 } \
279 NS_IMETHOD GetFromVisitId(int64_t* aFromVisitId) override { \
280 return nsNavHistoryResultNode::GetFromVisitId(aFromVisitId); \
281 } \
282 NS_IMETHOD GetVisitType(uint32_t* aVisitType) override { \
283 return nsNavHistoryResultNode::GetVisitType(aVisitType); \
284 }
285
286 class nsNavHistoryResultNode : public nsINavHistoryResultNode {
287 public:
288 nsNavHistoryResultNode(const nsACString& aURI, const nsACString& aTitle,
289 uint32_t aAccessCount, PRTime aTime);
290
291 NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYRESULTNODE_IID)
292
293 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
294 NS_DECL_CYCLE_COLLECTION_CLASS(nsNavHistoryResultNode)
295
296 NS_IMPLEMENT_SIMPLE_RESULTNODE
297 NS_IMETHOD GetIcon(nsACString& aIcon) override;
298 NS_IMETHOD GetParent(nsINavHistoryContainerResultNode** aParent) override;
299 NS_IMETHOD GetParentResult(nsINavHistoryResult** aResult) override;
300 NS_IMETHOD GetType(uint32_t* type) override {
301 *type = nsNavHistoryResultNode::RESULT_TYPE_URI;
302 return NS_OK;
303 }
304 NS_IMETHOD GetUri(nsACString& aURI) override {
305 aURI = mURI;
306 return NS_OK;
307 }
308 NS_IMETHOD GetTags(nsAString& aTags) override;
309 NS_IMETHOD GetPageGuid(nsACString& aPageGuid) override;
310 NS_IMETHOD GetBookmarkGuid(nsACString& aBookmarkGuid) override;
311 NS_IMETHOD GetVisitId(int64_t* aVisitId) override;
312 NS_IMETHOD GetFromVisitId(int64_t* aFromVisitId) override;
313 NS_IMETHOD GetVisitType(uint32_t* aVisitType) override;
314
315 virtual void OnRemoving();
316
317 nsresult OnItemTagsChanged(int64_t aItemId, const nsAString& aURL);
318 nsresult OnItemTimeChanged(int64_t aItemId, const nsACString& aGUID,
319 PRTime aDateAdded, PRTime aLastModified);
320 nsresult OnItemTitleChanged(int64_t aItemId, const nsACString& aGUID,
321 const nsACString& aTitle, PRTime aLastModified);
322 nsresult OnItemUrlChanged(int64_t aItemId, const nsACString& aGUID,
323 const nsACString& aURL, PRTime aLastModified);
324
325 // Called from result's onItemChanged, see also bookmark observer declaration
326 // in nsNavHistoryFolderResultNode
327 NS_IMETHOD OnItemChanged(int64_t aItemId, const nsACString& aProperty,
328 bool aIsAnnotationProperty, const nsACString& aValue,
329 PRTime aNewLastModified, uint16_t aItemType,
330 int64_t aParentId, const nsACString& aGUID,
331 const nsACString& aParentGUID,
332 const nsACString& aOldValue, uint16_t aSource);
333
334 virtual nsresult OnMobilePrefChanged(bool newValue) { return NS_OK; };
335
336 protected:
337 virtual ~nsNavHistoryResultNode() = default;
338
339 public:
340 nsNavHistoryResult* GetResult();
341
342 // These functions test the type. We don't use a virtual function since that
343 // would take a vtable slot for every one of (potentially very many) nodes.
344 // Note that GetType() already has a vtable slot because its on the iface.
345 bool IsTypeContainer(uint32_t type) {
346 return type == nsINavHistoryResultNode::RESULT_TYPE_QUERY ||
347 type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER ||
348 type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT;
349 }
350 bool IsContainer() {
351 uint32_t type;
352 GetType(&type);
353 return IsTypeContainer(type);
354 }
355 static bool IsTypeURI(uint32_t type) {
356 return type == nsINavHistoryResultNode::RESULT_TYPE_URI;
357 }
358 bool IsURI() {
359 uint32_t type;
360 GetType(&type);
361 return IsTypeURI(type);
362 }
363 static bool IsTypeFolder(uint32_t type) {
364 return type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER ||
365 type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT;
366 }
367 bool IsFolder() {
368 uint32_t type;
369 GetType(&type);
370 return IsTypeFolder(type);
371 }
372 static bool IsTypeQuery(uint32_t type) {
373 return type == nsINavHistoryResultNode::RESULT_TYPE_QUERY;
374 }
375 bool IsQuery() {
376 uint32_t type;
377 GetType(&type);
378 return IsTypeQuery(type);
379 }
380 bool IsSeparator() {
381 uint32_t type;
382 GetType(&type);
383 return type == nsINavHistoryResultNode::RESULT_TYPE_SEPARATOR;
384 }
385 nsNavHistoryContainerResultNode* GetAsContainer() {
386 NS_ASSERTION(IsContainer(), "Not a container");
387 return reinterpret_cast<nsNavHistoryContainerResultNode*>(this);
388 }
389 nsNavHistoryFolderResultNode* GetAsFolder() {
390 NS_ASSERTION(IsFolder(), "Not a folder");
391 return reinterpret_cast<nsNavHistoryFolderResultNode*>(this);
392 }
393 nsNavHistoryQueryResultNode* GetAsQuery() {
394 NS_ASSERTION(IsQuery(), "Not a query");
395 return reinterpret_cast<nsNavHistoryQueryResultNode*>(this);
396 }
397
398 RefPtr<nsNavHistoryContainerResultNode> mParent;
399 nsCString mURI; // not necessarily valid for containers, call GetUri
400 nsCString mTitle;
401 nsString mTags;
402 bool mAreTagsSorted;
403 uint32_t mAccessCount;
404 int64_t mTime;
405 int32_t mBookmarkIndex;
406 int64_t mItemId;
407 int64_t mVisitId;
408 int64_t mFromVisitId;
409 PRTime mDateAdded;
410 PRTime mLastModified;
411
412 // The indent level of this node. The root node will have a value of -1. The
413 // root's children will have a value of 0, and so on.
414 int32_t mIndentLevel;
415
416 // Frecency of the page. Valid only for URI nodes.
417 int32_t mFrecency;
418
419 // Hidden status of the page. Valid only for URI nodes.
420 bool mHidden;
421
422 // Transition type used when this node represents a single visit.
423 uint32_t mTransitionType;
424
425 // Unique Id of the page.
426 nsCString mPageGuid;
427
428 // Unique Id of the bookmark.
429 nsCString mBookmarkGuid;
430 };
431
NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResultNode,NS_NAVHISTORYRESULTNODE_IID)432 NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResultNode,
433 NS_NAVHISTORYRESULTNODE_IID)
434
435 // nsNavHistoryContainerResultNode
436 //
437 // This is the base class for all nodes that can have children. It is
438 // overridden for nodes that are dynamically populated such as queries and
439 // folders. It is used directly for simple containers such as host groups
440 // in history views.
441
442 // derived classes each provide their own implementation of has children and
443 // forward the rest to us using this macro
444 #define NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN \
445 NS_IMETHOD GetState(uint16_t* _state) override { \
446 return nsNavHistoryContainerResultNode::GetState(_state); \
447 } \
448 NS_IMETHOD GetContainerOpen(bool* aContainerOpen) override { \
449 return nsNavHistoryContainerResultNode::GetContainerOpen(aContainerOpen); \
450 } \
451 NS_IMETHOD SetContainerOpen(bool aContainerOpen) override { \
452 return nsNavHistoryContainerResultNode::SetContainerOpen(aContainerOpen); \
453 } \
454 NS_IMETHOD GetChildCount(uint32_t* aChildCount) override { \
455 return nsNavHistoryContainerResultNode::GetChildCount(aChildCount); \
456 } \
457 NS_IMETHOD GetChild(uint32_t index, nsINavHistoryResultNode** _retval) \
458 override { \
459 return nsNavHistoryContainerResultNode::GetChild(index, _retval); \
460 } \
461 NS_IMETHOD GetChildIndex(nsINavHistoryResultNode* aNode, uint32_t* _retval) \
462 override { \
463 return nsNavHistoryContainerResultNode::GetChildIndex(aNode, _retval); \
464 }
465
466 #define NS_NAVHISTORYCONTAINERRESULTNODE_IID \
467 { \
468 0x6e3bf8d3, 0x22aa, 0x4065, { \
469 0x86, 0xbc, 0x37, 0x46, 0xb5, 0xb3, 0x2c, 0xe8 \
470 } \
471 }
472
473 class nsNavHistoryContainerResultNode
474 : public nsNavHistoryResultNode,
475 public nsINavHistoryContainerResultNode {
476 public:
477 nsNavHistoryContainerResultNode(const nsACString& aURI,
478 const nsACString& aTitle, PRTime aTime,
479 uint32_t aContainerType,
480 nsNavHistoryQueryOptions* aOptions);
481
482 virtual nsresult Refresh();
483
484 NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYCONTAINERRESULTNODE_IID)
485
486 NS_DECL_ISUPPORTS_INHERITED
487 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsNavHistoryContainerResultNode,
488 nsNavHistoryResultNode)
489 NS_FORWARD_COMMON_RESULTNODE_TO_BASE
490 NS_IMETHOD GetType(uint32_t* type) override {
491 *type = mContainerType;
492 return NS_OK;
493 }
494 NS_IMETHOD GetUri(nsACString& aURI) override {
495 aURI = mURI;
496 return NS_OK;
497 }
498 NS_DECL_NSINAVHISTORYCONTAINERRESULTNODE
499
500 public:
501 virtual void OnRemoving() override;
502
503 bool AreChildrenVisible();
504
505 // Overridded by descendents to populate.
506 virtual nsresult OpenContainer();
507 nsresult CloseContainer(bool aSuppressNotifications = false);
508
509 virtual nsresult OpenContainerAsync();
510
511 // This points to the result that owns this container. All containers have
512 // their result pointer set so we can quickly get to the result without having
513 // to walk the tree. Yet, this also saves us from storing a million pointers
514 // for every leaf node to the result.
515 RefPtr<nsNavHistoryResult> mResult;
516
517 // For example, RESULT_TYPE_QUERY. Query and Folder results override GetType
518 // so this is not used, but is still kept in sync.
519 uint32_t mContainerType;
520
521 // When there are children, this stores the open state in the tree
522 // this is set to the default in the constructor.
523 bool mExpanded;
524
525 // Filled in by the result type generator in nsNavHistory.
526 nsCOMArray<nsNavHistoryResultNode> mChildren;
527
528 // mOriginalOptions is the options object used to _define_ this specific
529 // container node. It may differ from mOptions, that is the options used
530 // to _fill_ this container node, because mOptions may be modified by
531 // the direct parent of this container node, see SetAsParentOfNode. For
532 // example, if the parent has excludeItems, options will have it too, even if
533 // originally this object was not defined with that option.
534 RefPtr<nsNavHistoryQueryOptions> mOriginalOptions;
535 RefPtr<nsNavHistoryQueryOptions> mOptions;
536
537 void FillStats();
538 // Sets this container as parent of aNode, propagating the appropriate
539 // options.
540 void SetAsParentOfNode(nsNavHistoryResultNode* aNode);
541 nsresult ReverseUpdateStats(int32_t aAccessCountChange);
542
543 // Sorting methods.
544 typedef nsCOMArray<nsNavHistoryResultNode>::TComparatorFunc SortComparator;
545 virtual uint16_t GetSortType();
546
547 static SortComparator GetSortingComparator(uint16_t aSortType);
548 virtual void RecursiveSort(SortComparator aComparator);
549 uint32_t FindInsertionPoint(nsNavHistoryResultNode* aNode,
550 SortComparator aComparator, bool* aItemExists);
551 bool DoesChildNeedResorting(uint32_t aIndex, SortComparator aComparator);
552
553 static int32_t SortComparison_StringLess(const nsAString& a,
554 const nsAString& b);
555
556 static int32_t SortComparison_Bookmark(nsNavHistoryResultNode* a,
557 nsNavHistoryResultNode* b,
558 void* closure);
559 static int32_t SortComparison_TitleLess(nsNavHistoryResultNode* a,
560 nsNavHistoryResultNode* b,
561 void* closure);
562 static int32_t SortComparison_TitleGreater(nsNavHistoryResultNode* a,
563 nsNavHistoryResultNode* b,
564 void* closure);
565 static int32_t SortComparison_DateLess(nsNavHistoryResultNode* a,
566 nsNavHistoryResultNode* b,
567 void* closure);
568 static int32_t SortComparison_DateGreater(nsNavHistoryResultNode* a,
569 nsNavHistoryResultNode* b,
570 void* closure);
571 static int32_t SortComparison_URILess(nsNavHistoryResultNode* a,
572 nsNavHistoryResultNode* b,
573 void* closure);
574 static int32_t SortComparison_URIGreater(nsNavHistoryResultNode* a,
575 nsNavHistoryResultNode* b,
576 void* closure);
577 static int32_t SortComparison_VisitCountLess(nsNavHistoryResultNode* a,
578 nsNavHistoryResultNode* b,
579 void* closure);
580 static int32_t SortComparison_VisitCountGreater(nsNavHistoryResultNode* a,
581 nsNavHistoryResultNode* b,
582 void* closure);
583 static int32_t SortComparison_DateAddedLess(nsNavHistoryResultNode* a,
584 nsNavHistoryResultNode* b,
585 void* closure);
586 static int32_t SortComparison_DateAddedGreater(nsNavHistoryResultNode* a,
587 nsNavHistoryResultNode* b,
588 void* closure);
589 static int32_t SortComparison_LastModifiedLess(nsNavHistoryResultNode* a,
590 nsNavHistoryResultNode* b,
591 void* closure);
592 static int32_t SortComparison_LastModifiedGreater(nsNavHistoryResultNode* a,
593 nsNavHistoryResultNode* b,
594 void* closure);
595 static int32_t SortComparison_TagsLess(nsNavHistoryResultNode* a,
596 nsNavHistoryResultNode* b,
597 void* closure);
598 static int32_t SortComparison_TagsGreater(nsNavHistoryResultNode* a,
599 nsNavHistoryResultNode* b,
600 void* closure);
601 static int32_t SortComparison_FrecencyLess(nsNavHistoryResultNode* a,
602 nsNavHistoryResultNode* b,
603 void* closure);
604 static int32_t SortComparison_FrecencyGreater(nsNavHistoryResultNode* a,
605 nsNavHistoryResultNode* b,
606 void* closure);
607
608 // finding children: THESE DO NOT ADDREF
609 nsNavHistoryResultNode* FindChildByURI(const nsACString& aSpec,
610 uint32_t* aNodeIndex);
611 void FindChildrenByURI(const nsCString& aSpec,
612 nsCOMArray<nsNavHistoryResultNode>* aMatches);
613 // returns the index of the given node, -1 if not found
614 int32_t FindChild(nsNavHistoryResultNode* aNode) {
615 return mChildren.IndexOf(aNode);
616 }
617
618 nsNavHistoryResultNode* FindChildByGuid(const nsACString& guid,
619 int32_t* nodeIndex);
620
621 nsresult InsertChildAt(nsNavHistoryResultNode* aNode, int32_t aIndex);
622 nsresult InsertSortedChild(nsNavHistoryResultNode* aNode,
623 bool aIgnoreDuplicates = false);
624 bool EnsureItemPosition(uint32_t aIndex);
625
626 nsresult RemoveChildAt(int32_t aIndex);
627
628 void RecursiveFindURIs(bool aOnlyOne,
629 nsNavHistoryContainerResultNode* aContainer,
630 const nsCString& aSpec,
631 nsCOMArray<nsNavHistoryResultNode>* aMatches);
632 bool UpdateURIs(bool aRecursive, bool aOnlyOne, bool aUpdateSort,
633 const nsCString& aSpec,
634 nsresult (*aCallback)(nsNavHistoryResultNode*, const void*,
635 const nsNavHistoryResult*),
636 const void* aClosure);
637 nsresult ChangeTitles(nsIURI* aURI, const nsACString& aNewTitle,
638 bool aRecursive, bool aOnlyOne);
639
640 protected:
641 virtual ~nsNavHistoryContainerResultNode();
642
643 enum AsyncCanceledState { NOT_CANCELED, CANCELED, CANCELED_RESTART_NEEDED };
644
645 void CancelAsyncOpen(bool aRestart);
646 nsresult NotifyOnStateChange(uint16_t aOldState);
647
648 nsCOMPtr<mozIStoragePendingStatement> mAsyncPendingStmt;
649 AsyncCanceledState mAsyncCanceledState;
650 };
651
NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryContainerResultNode,NS_NAVHISTORYCONTAINERRESULTNODE_IID)652 NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryContainerResultNode,
653 NS_NAVHISTORYCONTAINERRESULTNODE_IID)
654
655 // nsNavHistoryQueryResultNode
656 //
657 // Overridden container type for complex queries over history and/or
658 // bookmarks. This keeps itself in sync by listening to history and
659 // bookmark notifications.
660
661 class nsNavHistoryQueryResultNode final
662 : public nsNavHistoryContainerResultNode,
663 public nsINavHistoryQueryResultNode,
664 public nsINavBookmarkObserver {
665 public:
666 nsNavHistoryQueryResultNode(const nsACString& aTitle, PRTime aTime,
667 const nsACString& aQueryURI,
668 const RefPtr<nsNavHistoryQuery>& aQuery,
669 const RefPtr<nsNavHistoryQueryOptions>& aOptions);
670
671 NS_DECL_ISUPPORTS_INHERITED
672 NS_FORWARD_COMMON_RESULTNODE_TO_BASE
673 NS_IMETHOD GetType(uint32_t* type) override {
674 *type = nsNavHistoryResultNode::RESULT_TYPE_QUERY;
675 return NS_OK;
676 }
677 NS_IMETHOD GetUri(nsACString& aURI) override; // does special lazy creation
678 NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN
679 NS_IMETHOD GetHasChildren(bool* aHasChildren) override;
680 NS_DECL_NSINAVHISTORYQUERYRESULTNODE
681
682 virtual nsresult OnMobilePrefChanged(bool newValue) override;
683
684 bool CanExpand();
685 bool IsContainersQuery();
686
687 virtual nsresult OpenContainer() override;
688
689 NS_DECL_NSINAVBOOKMARKOBSERVER;
690
691 nsresult OnItemAdded(int64_t aItemId, int64_t aParentId, int32_t aIndex,
692 uint16_t aItemType, nsIURI* aURI, PRTime aDateAdded,
693 const nsACString& aGUID, const nsACString& aParentGUID,
694 uint16_t aSource);
695 nsresult OnItemRemoved(int64_t aItemId, int64_t aParentFolder, int32_t aIndex,
696 uint16_t aItemType, nsIURI* aURI,
697 const nsACString& aGUID, const nsACString& aParentGUID,
698 uint16_t aSource);
699 nsresult OnItemMoved(int64_t aFolder, int32_t aOldIndex, int32_t aNewIndex,
700 uint16_t aItemType, const nsACString& aGUID,
701 const nsACString& aOldParentGUID,
702 const nsACString& aNewParentGUID, uint16_t aSource,
703 const nsACString& aURI);
704 nsresult OnItemTagsChanged(int64_t aItemId, const nsAString& aURL);
705 nsresult OnItemTimeChanged(int64_t aItemId, const nsACString& aGUID,
706 PRTime aDateAdded, PRTime aLastModified);
707 nsresult OnItemTitleChanged(int64_t aItemId, const nsACString& aGUID,
708 const nsACString& aTitle, PRTime aLastModified);
709 nsresult OnItemUrlChanged(int64_t aItemId, const nsACString& aGUID,
710 const nsACString& aURL, PRTime aLastModified);
711
712 // The internal version has an output aAdded parameter, it is incremented by
713 // query nodes when the visited uri belongs to them. If no such query exists,
714 // the history result creates a new query node dynamically.
715 nsresult OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
716 uint32_t aTransitionType, bool aHidden, uint32_t* aAdded);
717 nsresult OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle,
718 const nsACString& aGUID);
719 nsresult OnClearHistory();
720 nsresult OnPageRemovedFromStore(nsIURI* aURI, const nsACString& aGUID,
721 uint16_t aReason);
722 nsresult OnPageRemovedVisits(nsIURI* aURI, bool aPartialRemoval,
723 const nsACString& aGUID, uint16_t aReason,
724 uint32_t aTransitionType);
725
726 virtual void OnRemoving() override;
727
728 nsresult OnBeginUpdateBatch();
729 nsresult OnEndUpdateBatch();
730
731 public:
732 RefPtr<nsNavHistoryQuery> mQuery;
733 uint32_t mLiveUpdate; // one of QUERYUPDATE_* in nsNavHistory.h
734 bool mHasSearchTerms;
735
736 // safe options getter, ensures query is parsed
737 nsNavHistoryQueryOptions* Options();
738
739 // this indicates whether the query contents are valid, they don't go away
740 // after the container is closed until a notification comes in
741 bool mContentsValid;
742
743 nsresult FillChildren();
744 void ClearChildren(bool unregister);
745 nsresult Refresh() override;
746
747 virtual uint16_t GetSortType() override;
748 virtual void RecursiveSort(SortComparator aComparator) override;
749
750 nsresult NotifyIfTagsChanged(nsIURI* aURI);
751
752 uint32_t mBatchChanges;
753
754 // Tracks transition type filters.
755 nsTArray<uint32_t> mTransitions;
756
757 protected:
758 virtual ~nsNavHistoryQueryResultNode();
759 };
760
761 // nsNavHistoryFolderResultNode
762 //
763 // Overridden container type for bookmark folders. It will keep the contents
764 // of the folder in sync with the bookmark service.
765
766 class nsNavHistoryFolderResultNode final
767 : public nsNavHistoryContainerResultNode,
768 public nsINavHistoryQueryResultNode,
769 public nsINavBookmarkObserver,
770 public mozilla::places::WeakAsyncStatementCallback {
771 public:
772 nsNavHistoryFolderResultNode(const nsACString& aTitle,
773 nsNavHistoryQueryOptions* options,
774 int64_t aFolderId);
775
776 NS_DECL_ISUPPORTS_INHERITED
777 NS_FORWARD_COMMON_RESULTNODE_TO_BASE
GetType(uint32_t * type)778 NS_IMETHOD GetType(uint32_t* type) override {
779 if (mTargetFolderItemId != mItemId) {
780 *type = nsNavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT;
781 } else {
782 *type = nsNavHistoryResultNode::RESULT_TYPE_FOLDER;
783 }
784 return NS_OK;
785 }
786 NS_IMETHOD GetUri(nsACString& aURI) override;
787 NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN
788 NS_IMETHOD GetHasChildren(bool* aHasChildren) override;
789 NS_DECL_NSINAVHISTORYQUERYRESULTNODE
790
791 virtual nsresult OpenContainer() override;
792
793 virtual nsresult OpenContainerAsync() override;
794 NS_DECL_ASYNCSTATEMENTCALLBACK
795
796 // This object implements a bookmark observer interface. This is called from
797 // the result's actual observer and it knows all observers are
798 // FolderResultNodes
799 NS_DECL_NSINAVBOOKMARKOBSERVER
800
801 nsresult OnItemAdded(int64_t aItemId, int64_t aParentId, int32_t aIndex,
802 uint16_t aItemType, nsIURI* aURI, PRTime aDateAdded,
803 const nsACString& aGUID, const nsACString& aParentGUID,
804 uint16_t aSource);
805 nsresult OnItemRemoved(int64_t aItemId, int64_t aParentFolder, int32_t aIndex,
806 uint16_t aItemType, nsIURI* aURI,
807 const nsACString& aGUID, const nsACString& aParentGUID,
808 uint16_t aSource);
809 nsresult OnItemMoved(int64_t aFolder, int32_t aOldIndex, int32_t aNewIndex,
810 uint16_t aItemType, const nsACString& aGUID,
811 const nsACString& aOldParentGUID,
812 const nsACString& aNewParentGUID, uint16_t aSource,
813 const nsACString& aURI);
814 nsresult OnItemVisited(nsIURI* aURI, int64_t aVisitId, PRTime aTime);
815 virtual void OnRemoving() override;
816
817 // this indicates whether the folder contents are valid, they don't go away
818 // after the container is closed until a notification comes in
819 bool mContentsValid;
820
821 // If the node is generated from a place:folder=X query, this is the target
822 // folder id and GUID. For regular folder nodes, they are set to the same
823 // values as mItemId and mBookmarkGuid. For more complex queries, they are set
824 // to -1/an empty string.
825 int64_t mTargetFolderItemId;
826 nsCString mTargetFolderGuid;
827
828 nsresult FillChildren();
829 void ClearChildren(bool aUnregister);
830 nsresult Refresh() override;
831
832 bool StartIncrementalUpdate();
833 void ReindexRange(int32_t aStartIndex, int32_t aEndIndex, int32_t aDelta);
834
835 nsNavHistoryResultNode* FindChildById(int64_t aItemId, uint32_t* aNodeIndex);
836
837 nsresult OnBeginUpdateBatch();
838 nsresult OnEndUpdateBatch();
839
840 protected:
841 virtual ~nsNavHistoryFolderResultNode();
842
843 private:
844 nsresult OnChildrenFilled();
845 void EnsureRegisteredAsFolderObserver();
846 nsresult FillChildrenAsync();
847
848 bool mIsRegisteredFolderObserver;
849 int32_t mAsyncBookmarkIndex;
850 };
851
852 // nsNavHistorySeparatorResultNode
853 //
854 // Separator result nodes do not hold any data.
855 class nsNavHistorySeparatorResultNode : public nsNavHistoryResultNode {
856 public:
857 nsNavHistorySeparatorResultNode();
858
GetType(uint32_t * type)859 NS_IMETHOD GetType(uint32_t* type) override {
860 *type = nsNavHistoryResultNode::RESULT_TYPE_SEPARATOR;
861 return NS_OK;
862 }
863 };
864
865 #endif // nsNavHistoryResult_h_
866