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