michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /** michael@0: * The definitions of objects that make up a history query result set. This file michael@0: * should only be included by nsNavHistory.h, include that if you want these michael@0: * classes. michael@0: */ michael@0: michael@0: #ifndef nsNavHistoryResult_h_ michael@0: #define nsNavHistoryResult_h_ michael@0: michael@0: #include "nsTArray.h" michael@0: #include "nsInterfaceHashtable.h" michael@0: #include "nsDataHashtable.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: #include "mozilla/storage.h" michael@0: #include "Helpers.h" michael@0: michael@0: class nsNavHistory; michael@0: class nsNavHistoryQuery; michael@0: class nsNavHistoryQueryOptions; michael@0: michael@0: class nsNavHistoryContainerResultNode; michael@0: class nsNavHistoryFolderResultNode; michael@0: class nsNavHistoryQueryResultNode; michael@0: michael@0: /** michael@0: * hashkey wrapper using int64_t KeyType michael@0: * michael@0: * @see nsTHashtable::EntryType for specification michael@0: * michael@0: * This just truncates the 64-bit int to a 32-bit one for using a hash number. michael@0: * It is used for bookmark folder IDs, which should be way less than 2^32. michael@0: */ michael@0: class nsTrimInt64HashKey : public PLDHashEntryHdr michael@0: { michael@0: public: michael@0: typedef const int64_t& KeyType; michael@0: typedef const int64_t* KeyTypePointer; michael@0: michael@0: nsTrimInt64HashKey(KeyTypePointer aKey) : mValue(*aKey) { } michael@0: nsTrimInt64HashKey(const nsTrimInt64HashKey& toCopy) : mValue(toCopy.mValue) { } michael@0: ~nsTrimInt64HashKey() { } michael@0: michael@0: KeyType GetKey() const { return mValue; } michael@0: bool KeyEquals(KeyTypePointer aKey) const { return *aKey == mValue; } michael@0: michael@0: static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } michael@0: static PLDHashNumber HashKey(KeyTypePointer aKey) michael@0: { return static_cast((*aKey) & UINT32_MAX); } michael@0: enum { ALLOW_MEMMOVE = true }; michael@0: michael@0: private: michael@0: const int64_t mValue; michael@0: }; michael@0: michael@0: michael@0: // Declare methods for implementing nsINavBookmarkObserver michael@0: // and nsINavHistoryObserver (some methods, such as BeginUpdateBatch overlap) michael@0: #define NS_DECL_BOOKMARK_HISTORY_OBSERVER_BASE \ michael@0: NS_DECL_NSINAVBOOKMARKOBSERVER \ michael@0: NS_IMETHOD OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle, \ michael@0: const nsACString& aGUID); \ michael@0: NS_IMETHOD OnFrecencyChanged(nsIURI* aURI, int32_t aNewFrecency, \ michael@0: const nsACString& aGUID, bool aHidden, \ michael@0: PRTime aLastVisitDate); \ michael@0: NS_IMETHOD OnManyFrecenciesChanged(); \ michael@0: NS_IMETHOD OnDeleteURI(nsIURI *aURI, const nsACString& aGUID, \ michael@0: uint16_t aReason); \ michael@0: NS_IMETHOD OnClearHistory(); \ michael@0: NS_IMETHOD OnPageChanged(nsIURI *aURI, uint32_t aChangedAttribute, \ michael@0: const nsAString &aNewValue, \ michael@0: const nsACString &aGUID); \ michael@0: NS_IMETHOD OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime, \ michael@0: const nsACString& aGUID, uint16_t aReason, \ michael@0: uint32_t aTransitionType); michael@0: michael@0: // The internal version has an output aAdded parameter, it is incremented by michael@0: // query nodes when the visited uri belongs to them. If no such query exists, michael@0: // the history result creates a new query node dynamically. michael@0: #define NS_DECL_BOOKMARK_HISTORY_OBSERVER_INTERNAL \ michael@0: NS_DECL_BOOKMARK_HISTORY_OBSERVER_BASE \ michael@0: NS_IMETHOD OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime, \ michael@0: int64_t aSessionId, int64_t aReferringId, \ michael@0: uint32_t aTransitionType, const nsACString& aGUID, \ michael@0: bool aHidden, uint32_t* aAdded); michael@0: michael@0: // The external version is used by results. michael@0: #define NS_DECL_BOOKMARK_HISTORY_OBSERVER_EXTERNAL \ michael@0: NS_DECL_BOOKMARK_HISTORY_OBSERVER_BASE \ michael@0: NS_IMETHOD OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime, \ michael@0: int64_t aSessionId, int64_t aReferringId, \ michael@0: uint32_t aTransitionType, const nsACString& aGUID, \ michael@0: bool aHidden); michael@0: michael@0: // nsNavHistoryResult michael@0: // michael@0: // nsNavHistory creates this object and fills in mChildren (by getting michael@0: // it through GetTopLevel()). Then FilledAllResults() is called to finish michael@0: // object initialization. michael@0: michael@0: #define NS_NAVHISTORYRESULT_IID \ michael@0: { 0x455d1d40, 0x1b9b, 0x40e6, { 0xa6, 0x41, 0x8b, 0xb7, 0xe8, 0x82, 0x23, 0x87 } } michael@0: michael@0: class nsNavHistoryResult : public nsSupportsWeakReference, michael@0: public nsINavHistoryResult, michael@0: public nsINavBookmarkObserver, michael@0: public nsINavHistoryObserver michael@0: { michael@0: public: michael@0: static nsresult NewHistoryResult(nsINavHistoryQuery** aQueries, michael@0: uint32_t aQueryCount, michael@0: nsNavHistoryQueryOptions* aOptions, michael@0: nsNavHistoryContainerResultNode* aRoot, michael@0: bool aBatchInProgress, michael@0: nsNavHistoryResult** result); michael@0: michael@0: NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYRESULT_IID) michael@0: michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: NS_DECL_NSINAVHISTORYRESULT michael@0: NS_DECL_BOOKMARK_HISTORY_OBSERVER_EXTERNAL michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNavHistoryResult, nsINavHistoryResult) michael@0: michael@0: void AddHistoryObserver(nsNavHistoryQueryResultNode* aNode); michael@0: void AddBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode, int64_t aFolder); michael@0: void AddAllBookmarksObserver(nsNavHistoryQueryResultNode* aNode); michael@0: void RemoveHistoryObserver(nsNavHistoryQueryResultNode* aNode); michael@0: void RemoveBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode, int64_t aFolder); michael@0: void RemoveAllBookmarksObserver(nsNavHistoryQueryResultNode* aNode); michael@0: void StopObserving(); michael@0: michael@0: public: michael@0: // two-stage init, use NewHistoryResult to construct michael@0: nsNavHistoryResult(nsNavHistoryContainerResultNode* mRoot); michael@0: virtual ~nsNavHistoryResult(); michael@0: nsresult Init(nsINavHistoryQuery** aQueries, michael@0: uint32_t aQueryCount, michael@0: nsNavHistoryQueryOptions *aOptions); michael@0: michael@0: nsRefPtr mRootNode; michael@0: michael@0: nsCOMArray mQueries; michael@0: nsCOMPtr mOptions; michael@0: michael@0: // One of nsNavHistoryQueryOptions.SORY_BY_* This is initialized to mOptions.sortingMode, michael@0: // but may be overridden if the user clicks on one of the columns. michael@0: uint16_t mSortingMode; michael@0: // If root node is closed and we try to apply a sortingMode, it would not michael@0: // work. So we will apply it when the node will be reopened and populated. michael@0: // This var states the fact we need to apply sortingMode in such a situation. michael@0: bool mNeedsToApplySortingMode; michael@0: michael@0: // The sorting annotation to be used for in SORT_BY_ANNOTATION_* modes michael@0: nsCString mSortingAnnotation; michael@0: michael@0: // node observers michael@0: bool mIsHistoryObserver; michael@0: bool mIsBookmarkFolderObserver; michael@0: bool mIsAllBookmarksObserver; michael@0: michael@0: typedef nsTArray< nsRefPtr > QueryObserverList; michael@0: QueryObserverList mHistoryObservers; michael@0: QueryObserverList mAllBookmarksObservers; michael@0: michael@0: typedef nsTArray< nsRefPtr > FolderObserverList; michael@0: nsDataHashtable mBookmarkFolderObservers; michael@0: FolderObserverList* BookmarkFolderObserversForId(int64_t aFolderId, bool aCreate); michael@0: michael@0: typedef nsTArray< nsRefPtr > ContainerObserverList; michael@0: michael@0: void RecursiveExpandCollapse(nsNavHistoryContainerResultNode* aContainer, michael@0: bool aExpand); michael@0: michael@0: void InvalidateTree(); michael@0: michael@0: bool mBatchInProgress; michael@0: michael@0: nsMaybeWeakPtrArray mObservers; michael@0: bool mSuppressNotifications; michael@0: michael@0: ContainerObserverList mRefreshParticipants; michael@0: void requestRefresh(nsNavHistoryContainerResultNode* aContainer); michael@0: }; michael@0: michael@0: NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResult, NS_NAVHISTORYRESULT_IID) michael@0: michael@0: // nsNavHistoryResultNode michael@0: // michael@0: // This is the base class for every node in a result set. The result itself michael@0: // is a node (nsNavHistoryResult inherits from this), as well as every michael@0: // leaf and branch on the tree. michael@0: michael@0: #define NS_NAVHISTORYRESULTNODE_IID \ michael@0: {0x54b61d38, 0x57c1, 0x11da, {0x95, 0xb8, 0x00, 0x13, 0x21, 0xc9, 0xf6, 0x9e}} michael@0: michael@0: // These are all the simple getters, they can be used for the result node michael@0: // implementation and all subclasses. More complex are GetIcon, GetParent michael@0: // (which depends on the definition of container result node), and GetUri michael@0: // (which is overridded for lazy construction for some containers). michael@0: #define NS_IMPLEMENT_SIMPLE_RESULTNODE_NO_GETITEMMID \ michael@0: NS_IMETHOD GetTitle(nsACString& aTitle) \ michael@0: { aTitle = mTitle; return NS_OK; } \ michael@0: NS_IMETHOD GetAccessCount(uint32_t* aAccessCount) \ michael@0: { *aAccessCount = mAccessCount; return NS_OK; } \ michael@0: NS_IMETHOD GetTime(PRTime* aTime) \ michael@0: { *aTime = mTime; return NS_OK; } \ michael@0: NS_IMETHOD GetIndentLevel(int32_t* aIndentLevel) \ michael@0: { *aIndentLevel = mIndentLevel; return NS_OK; } \ michael@0: NS_IMETHOD GetBookmarkIndex(int32_t* aIndex) \ michael@0: { *aIndex = mBookmarkIndex; return NS_OK; } \ michael@0: NS_IMETHOD GetDateAdded(PRTime* aDateAdded) \ michael@0: { *aDateAdded = mDateAdded; return NS_OK; } \ michael@0: NS_IMETHOD GetLastModified(PRTime* aLastModified) \ michael@0: { *aLastModified = mLastModified; return NS_OK; } michael@0: michael@0: #define NS_IMPLEMENT_SIMPLE_RESULTNODE \ michael@0: NS_IMPLEMENT_SIMPLE_RESULTNODE_NO_GETITEMMID \ michael@0: NS_IMETHOD GetItemId(int64_t* aId) \ michael@0: { *aId = mItemId; return NS_OK; } michael@0: michael@0: // This is used by the base classes instead of michael@0: // NS_FORWARD_NSINAVHISTORYRESULTNODE(nsNavHistoryResultNode) because they michael@0: // need to redefine GetType and GetUri rather than forwarding them. This michael@0: // implements all the simple getters instead of forwarding because they are so michael@0: // short and we can save a virtual function call. michael@0: // michael@0: // (GetUri is redefined only by QueryResultNode and FolderResultNode because michael@0: // the queries might not necessarily be parsed. The rest just return the node's michael@0: // buffer.) michael@0: #define NS_FORWARD_COMMON_RESULTNODE_TO_BASE_NO_GETITEMMID \ michael@0: NS_IMPLEMENT_SIMPLE_RESULTNODE_NO_GETITEMMID \ michael@0: NS_IMETHOD GetIcon(nsACString& aIcon) \ michael@0: { return nsNavHistoryResultNode::GetIcon(aIcon); } \ michael@0: NS_IMETHOD GetParent(nsINavHistoryContainerResultNode** aParent) \ michael@0: { return nsNavHistoryResultNode::GetParent(aParent); } \ michael@0: NS_IMETHOD GetParentResult(nsINavHistoryResult** aResult) \ michael@0: { return nsNavHistoryResultNode::GetParentResult(aResult); } \ michael@0: NS_IMETHOD GetTags(nsAString& aTags) \ michael@0: { return nsNavHistoryResultNode::GetTags(aTags); } \ michael@0: NS_IMETHOD GetPageGuid(nsACString& aPageGuid) \ michael@0: { return nsNavHistoryResultNode::GetPageGuid(aPageGuid); } \ michael@0: NS_IMETHOD GetBookmarkGuid(nsACString& aBookmarkGuid) \ michael@0: { return nsNavHistoryResultNode::GetBookmarkGuid(aBookmarkGuid); } michael@0: michael@0: #define NS_FORWARD_COMMON_RESULTNODE_TO_BASE \ michael@0: NS_FORWARD_COMMON_RESULTNODE_TO_BASE_NO_GETITEMMID \ michael@0: NS_IMETHOD GetItemId(int64_t* aId) \ michael@0: { *aId = mItemId; return NS_OK; } michael@0: michael@0: class nsNavHistoryResultNode : public nsINavHistoryResultNode michael@0: { michael@0: public: michael@0: nsNavHistoryResultNode(const nsACString& aURI, const nsACString& aTitle, michael@0: uint32_t aAccessCount, PRTime aTime, michael@0: const nsACString& aIconURI); michael@0: virtual ~nsNavHistoryResultNode() {} michael@0: michael@0: NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYRESULTNODE_IID) michael@0: michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: NS_DECL_CYCLE_COLLECTION_CLASS(nsNavHistoryResultNode) michael@0: michael@0: NS_IMPLEMENT_SIMPLE_RESULTNODE michael@0: NS_IMETHOD GetIcon(nsACString& aIcon); michael@0: NS_IMETHOD GetParent(nsINavHistoryContainerResultNode** aParent); michael@0: NS_IMETHOD GetParentResult(nsINavHistoryResult** aResult); michael@0: NS_IMETHOD GetType(uint32_t* type) michael@0: { *type = nsNavHistoryResultNode::RESULT_TYPE_URI; return NS_OK; } michael@0: NS_IMETHOD GetUri(nsACString& aURI) michael@0: { aURI = mURI; return NS_OK; } michael@0: NS_IMETHOD GetTags(nsAString& aTags); michael@0: NS_IMETHOD GetPageGuid(nsACString& aPageGuid); michael@0: NS_IMETHOD GetBookmarkGuid(nsACString& aBookmarkGuid); michael@0: michael@0: virtual void OnRemoving(); michael@0: michael@0: // Called from result's onItemChanged, see also bookmark observer declaration in michael@0: // nsNavHistoryFolderResultNode michael@0: NS_IMETHOD OnItemChanged(int64_t aItemId, michael@0: const nsACString &aProperty, michael@0: bool aIsAnnotationProperty, michael@0: const nsACString &aValue, michael@0: PRTime aNewLastModified, michael@0: uint16_t aItemType, michael@0: int64_t aParentId, michael@0: const nsACString& aGUID, michael@0: const nsACString& aParentGUID); michael@0: michael@0: public: michael@0: michael@0: nsNavHistoryResult* GetResult(); michael@0: nsNavHistoryQueryOptions* GetGeneratingOptions(); michael@0: michael@0: // These functions test the type. We don't use a virtual function since that michael@0: // would take a vtable slot for every one of (potentially very many) nodes. michael@0: // Note that GetType() already has a vtable slot because its on the iface. michael@0: bool IsTypeContainer(uint32_t type) { michael@0: return type == nsINavHistoryResultNode::RESULT_TYPE_QUERY || michael@0: type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER || michael@0: type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT; michael@0: } michael@0: bool IsContainer() { michael@0: uint32_t type; michael@0: GetType(&type); michael@0: return IsTypeContainer(type); michael@0: } michael@0: static bool IsTypeURI(uint32_t type) { michael@0: return type == nsINavHistoryResultNode::RESULT_TYPE_URI; michael@0: } michael@0: bool IsURI() { michael@0: uint32_t type; michael@0: GetType(&type); michael@0: return IsTypeURI(type); michael@0: } michael@0: static bool IsTypeFolder(uint32_t type) { michael@0: return type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER || michael@0: type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT; michael@0: } michael@0: bool IsFolder() { michael@0: uint32_t type; michael@0: GetType(&type); michael@0: return IsTypeFolder(type); michael@0: } michael@0: static bool IsTypeQuery(uint32_t type) { michael@0: return type == nsINavHistoryResultNode::RESULT_TYPE_QUERY; michael@0: } michael@0: bool IsQuery() { michael@0: uint32_t type; michael@0: GetType(&type); michael@0: return IsTypeQuery(type); michael@0: } michael@0: bool IsSeparator() { michael@0: uint32_t type; michael@0: GetType(&type); michael@0: return type == nsINavHistoryResultNode::RESULT_TYPE_SEPARATOR; michael@0: } michael@0: nsNavHistoryContainerResultNode* GetAsContainer() { michael@0: NS_ASSERTION(IsContainer(), "Not a container"); michael@0: return reinterpret_cast(this); michael@0: } michael@0: nsNavHistoryFolderResultNode* GetAsFolder() { michael@0: NS_ASSERTION(IsFolder(), "Not a folder"); michael@0: return reinterpret_cast(this); michael@0: } michael@0: nsNavHistoryQueryResultNode* GetAsQuery() { michael@0: NS_ASSERTION(IsQuery(), "Not a query"); michael@0: return reinterpret_cast(this); michael@0: } michael@0: michael@0: nsRefPtr mParent; michael@0: nsCString mURI; // not necessarily valid for containers, call GetUri michael@0: nsCString mTitle; michael@0: nsString mTags; michael@0: bool mAreTagsSorted; michael@0: uint32_t mAccessCount; michael@0: int64_t mTime; michael@0: nsCString mFaviconURI; michael@0: int32_t mBookmarkIndex; michael@0: int64_t mItemId; michael@0: int64_t mFolderId; michael@0: PRTime mDateAdded; michael@0: PRTime mLastModified; michael@0: michael@0: // The indent level of this node. The root node will have a value of -1. The michael@0: // root's children will have a value of 0, and so on. michael@0: int32_t mIndentLevel; michael@0: michael@0: // Frecency of the page. Valid only for URI nodes. michael@0: int32_t mFrecency; michael@0: michael@0: // Hidden status of the page. Valid only for URI nodes. michael@0: bool mHidden; michael@0: michael@0: // Transition type used when this node represents a single visit. michael@0: uint32_t mTransitionType; michael@0: michael@0: // Unique Id of the page. michael@0: nsCString mPageGuid; michael@0: michael@0: // Unique Id of the bookmark. michael@0: nsCString mBookmarkGuid; michael@0: }; michael@0: michael@0: NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResultNode, NS_NAVHISTORYRESULTNODE_IID) michael@0: michael@0: michael@0: // nsNavHistoryContainerResultNode michael@0: // michael@0: // This is the base class for all nodes that can have children. It is michael@0: // overridden for nodes that are dynamically populated such as queries and michael@0: // folders. It is used directly for simple containers such as host groups michael@0: // in history views. michael@0: michael@0: // derived classes each provide their own implementation of has children and michael@0: // forward the rest to us using this macro michael@0: #define NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN_AND_READONLY \ michael@0: NS_IMETHOD GetState(uint16_t* _state) \ michael@0: { return nsNavHistoryContainerResultNode::GetState(_state); } \ michael@0: NS_IMETHOD GetContainerOpen(bool *aContainerOpen) \ michael@0: { return nsNavHistoryContainerResultNode::GetContainerOpen(aContainerOpen); } \ michael@0: NS_IMETHOD SetContainerOpen(bool aContainerOpen) \ michael@0: { return nsNavHistoryContainerResultNode::SetContainerOpen(aContainerOpen); } \ michael@0: NS_IMETHOD GetChildCount(uint32_t *aChildCount) \ michael@0: { return nsNavHistoryContainerResultNode::GetChildCount(aChildCount); } \ michael@0: NS_IMETHOD GetChild(uint32_t index, nsINavHistoryResultNode **_retval) \ michael@0: { return nsNavHistoryContainerResultNode::GetChild(index, _retval); } \ michael@0: NS_IMETHOD GetChildIndex(nsINavHistoryResultNode* aNode, uint32_t* _retval) \ michael@0: { return nsNavHistoryContainerResultNode::GetChildIndex(aNode, _retval); } \ michael@0: NS_IMETHOD FindNodeByDetails(const nsACString& aURIString, PRTime aTime, \ michael@0: int64_t aItemId, bool aRecursive, \ michael@0: nsINavHistoryResultNode** _retval) \ michael@0: { return nsNavHistoryContainerResultNode::FindNodeByDetails(aURIString, aTime, aItemId, \ michael@0: aRecursive, _retval); } michael@0: michael@0: #define NS_NAVHISTORYCONTAINERRESULTNODE_IID \ michael@0: { 0x6e3bf8d3, 0x22aa, 0x4065, { 0x86, 0xbc, 0x37, 0x46, 0xb5, 0xb3, 0x2c, 0xe8 } } michael@0: michael@0: class nsNavHistoryContainerResultNode : public nsNavHistoryResultNode, michael@0: public nsINavHistoryContainerResultNode michael@0: { michael@0: public: michael@0: nsNavHistoryContainerResultNode( michael@0: const nsACString& aURI, const nsACString& aTitle, michael@0: const nsACString& aIconURI, uint32_t aContainerType, michael@0: bool aReadOnly, nsNavHistoryQueryOptions* aOptions); michael@0: nsNavHistoryContainerResultNode( michael@0: const nsACString& aURI, const nsACString& aTitle, michael@0: PRTime aTime, michael@0: const nsACString& aIconURI, uint32_t aContainerType, michael@0: bool aReadOnly, nsNavHistoryQueryOptions* aOptions); michael@0: michael@0: virtual nsresult Refresh(); michael@0: virtual ~nsNavHistoryContainerResultNode(); michael@0: michael@0: NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYCONTAINERRESULTNODE_IID) michael@0: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsNavHistoryContainerResultNode, nsNavHistoryResultNode) michael@0: NS_FORWARD_COMMON_RESULTNODE_TO_BASE michael@0: NS_IMETHOD GetType(uint32_t* type) michael@0: { *type = mContainerType; return NS_OK; } michael@0: NS_IMETHOD GetUri(nsACString& aURI) michael@0: { aURI = mURI; return NS_OK; } michael@0: NS_DECL_NSINAVHISTORYCONTAINERRESULTNODE michael@0: michael@0: public: michael@0: michael@0: virtual void OnRemoving(); michael@0: michael@0: bool AreChildrenVisible(); michael@0: michael@0: // Overridded by descendents to populate. michael@0: virtual nsresult OpenContainer(); michael@0: nsresult CloseContainer(bool aSuppressNotifications = false); michael@0: michael@0: virtual nsresult OpenContainerAsync(); michael@0: michael@0: // This points to the result that owns this container. All containers have michael@0: // their result pointer set so we can quickly get to the result without having michael@0: // to walk the tree. Yet, this also saves us from storing a million pointers michael@0: // for every leaf node to the result. michael@0: nsRefPtr mResult; michael@0: michael@0: // For example, RESULT_TYPE_QUERY. Query and Folder results override GetType michael@0: // so this is not used, but is still kept in sync. michael@0: uint32_t mContainerType; michael@0: michael@0: // When there are children, this stores the open state in the tree michael@0: // this is set to the default in the constructor. michael@0: bool mExpanded; michael@0: michael@0: // Filled in by the result type generator in nsNavHistory. michael@0: nsCOMArray mChildren; michael@0: michael@0: bool mChildrenReadOnly; michael@0: michael@0: nsCOMPtr mOptions; michael@0: michael@0: void FillStats(); michael@0: nsresult ReverseUpdateStats(int32_t aAccessCountChange); michael@0: michael@0: // Sorting methods. michael@0: typedef nsCOMArray::nsCOMArrayComparatorFunc SortComparator; michael@0: virtual uint16_t GetSortType(); michael@0: virtual void GetSortingAnnotation(nsACString& aSortingAnnotation); michael@0: michael@0: static SortComparator GetSortingComparator(uint16_t aSortType); michael@0: virtual void RecursiveSort(const char* aData, michael@0: SortComparator aComparator); michael@0: uint32_t FindInsertionPoint(nsNavHistoryResultNode* aNode, SortComparator aComparator, michael@0: const char* aData, bool* aItemExists); michael@0: bool DoesChildNeedResorting(uint32_t aIndex, SortComparator aComparator, michael@0: const char* aData); michael@0: michael@0: static int32_t SortComparison_StringLess(const nsAString& a, const nsAString& b); michael@0: michael@0: static int32_t SortComparison_Bookmark(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_TitleLess(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_TitleGreater(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_DateLess(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_DateGreater(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_URILess(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_URIGreater(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_VisitCountLess(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_VisitCountGreater(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_KeywordLess(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_KeywordGreater(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_AnnotationLess(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_AnnotationGreater(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_DateAddedLess(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_DateAddedGreater(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_LastModifiedLess(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_LastModifiedGreater(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_TagsLess(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_TagsGreater(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_FrecencyLess(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: static int32_t SortComparison_FrecencyGreater(nsNavHistoryResultNode* a, michael@0: nsNavHistoryResultNode* b, michael@0: void* closure); michael@0: michael@0: // finding children: THESE DO NOT ADDREF michael@0: nsNavHistoryResultNode* FindChildURI(nsIURI* aURI, uint32_t* aNodeIndex) michael@0: { michael@0: nsAutoCString spec; michael@0: if (NS_FAILED(aURI->GetSpec(spec))) michael@0: return nullptr; michael@0: return FindChildURI(spec, aNodeIndex); michael@0: } michael@0: nsNavHistoryResultNode* FindChildURI(const nsACString& aSpec, michael@0: uint32_t* aNodeIndex); michael@0: // returns the index of the given node, -1 if not found michael@0: int32_t FindChild(nsNavHistoryResultNode* aNode) michael@0: { return mChildren.IndexOf(aNode); } michael@0: michael@0: nsresult InsertChildAt(nsNavHistoryResultNode* aNode, int32_t aIndex, michael@0: bool aIsTemporary = false); michael@0: nsresult InsertSortedChild(nsNavHistoryResultNode* aNode, michael@0: bool aIsTemporary = false, michael@0: bool aIgnoreDuplicates = false); michael@0: bool EnsureItemPosition(uint32_t aIndex); michael@0: michael@0: nsresult RemoveChildAt(int32_t aIndex, bool aIsTemporary = false); michael@0: michael@0: void RecursiveFindURIs(bool aOnlyOne, michael@0: nsNavHistoryContainerResultNode* aContainer, michael@0: const nsCString& aSpec, michael@0: nsCOMArray* aMatches); michael@0: bool UpdateURIs(bool aRecursive, bool aOnlyOne, bool aUpdateSort, michael@0: const nsCString& aSpec, michael@0: nsresult (*aCallback)(nsNavHistoryResultNode*, const void*, michael@0: const nsNavHistoryResult*), michael@0: const void* aClosure); michael@0: nsresult ChangeTitles(nsIURI* aURI, const nsACString& aNewTitle, michael@0: bool aRecursive, bool aOnlyOne); michael@0: michael@0: protected: michael@0: michael@0: enum AsyncCanceledState { michael@0: NOT_CANCELED, CANCELED, CANCELED_RESTART_NEEDED michael@0: }; michael@0: michael@0: void CancelAsyncOpen(bool aRestart); michael@0: nsresult NotifyOnStateChange(uint16_t aOldState); michael@0: michael@0: nsCOMPtr mAsyncPendingStmt; michael@0: AsyncCanceledState mAsyncCanceledState; michael@0: }; michael@0: michael@0: NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryContainerResultNode, michael@0: NS_NAVHISTORYCONTAINERRESULTNODE_IID) michael@0: michael@0: // nsNavHistoryQueryResultNode michael@0: // michael@0: // Overridden container type for complex queries over history and/or michael@0: // bookmarks. This keeps itself in sync by listening to history and michael@0: // bookmark notifications. michael@0: michael@0: class nsNavHistoryQueryResultNode : public nsNavHistoryContainerResultNode, michael@0: public nsINavHistoryQueryResultNode michael@0: { michael@0: public: michael@0: nsNavHistoryQueryResultNode(const nsACString& aTitle, michael@0: const nsACString& aIconURI, michael@0: const nsACString& aQueryURI); michael@0: nsNavHistoryQueryResultNode(const nsACString& aTitle, michael@0: const nsACString& aIconURI, michael@0: const nsCOMArray& aQueries, michael@0: nsNavHistoryQueryOptions* aOptions); michael@0: nsNavHistoryQueryResultNode(const nsACString& aTitle, michael@0: const nsACString& aIconURI, michael@0: PRTime aTime, michael@0: const nsCOMArray& aQueries, michael@0: nsNavHistoryQueryOptions* aOptions); michael@0: michael@0: virtual ~nsNavHistoryQueryResultNode(); michael@0: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_FORWARD_COMMON_RESULTNODE_TO_BASE michael@0: NS_IMETHOD GetType(uint32_t* type) michael@0: { *type = nsNavHistoryResultNode::RESULT_TYPE_QUERY; return NS_OK; } michael@0: NS_IMETHOD GetUri(nsACString& aURI); // does special lazy creation michael@0: NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN_AND_READONLY michael@0: NS_IMETHOD GetHasChildren(bool* aHasChildren); michael@0: NS_IMETHOD GetChildrenReadOnly(bool *aChildrenReadOnly) michael@0: { return nsNavHistoryContainerResultNode::GetChildrenReadOnly(aChildrenReadOnly); } michael@0: NS_DECL_NSINAVHISTORYQUERYRESULTNODE michael@0: michael@0: bool CanExpand(); michael@0: bool IsContainersQuery(); michael@0: michael@0: virtual nsresult OpenContainer(); michael@0: michael@0: NS_DECL_BOOKMARK_HISTORY_OBSERVER_INTERNAL michael@0: virtual void OnRemoving(); michael@0: michael@0: public: michael@0: // this constructs lazily mURI from mQueries and mOptions, call michael@0: // VerifyQueriesSerialized either this or mQueries/mOptions should be valid michael@0: nsresult VerifyQueriesSerialized(); michael@0: michael@0: // these may be constructed lazily from mURI, call VerifyQueriesParsed michael@0: // either this or mURI should be valid michael@0: nsCOMArray mQueries; michael@0: uint32_t mLiveUpdate; // one of QUERYUPDATE_* in nsNavHistory.h michael@0: bool mHasSearchTerms; michael@0: nsresult VerifyQueriesParsed(); michael@0: michael@0: // safe options getter, ensures queries are parsed michael@0: nsNavHistoryQueryOptions* Options(); michael@0: michael@0: // this indicates whether the query contents are valid, they don't go away michael@0: // after the container is closed until a notification comes in michael@0: bool mContentsValid; michael@0: michael@0: nsresult FillChildren(); michael@0: void ClearChildren(bool unregister); michael@0: nsresult Refresh(); michael@0: michael@0: virtual uint16_t GetSortType(); michael@0: virtual void GetSortingAnnotation(nsACString& aSortingAnnotation); michael@0: virtual void RecursiveSort(const char* aData, michael@0: SortComparator aComparator); michael@0: michael@0: nsCOMPtr mRemovingURI; michael@0: nsresult NotifyIfTagsChanged(nsIURI* aURI); michael@0: michael@0: uint32_t mBatchChanges; michael@0: michael@0: // Tracks transition type filters shared by all mQueries. michael@0: nsTArray mTransitions; michael@0: }; michael@0: michael@0: michael@0: // nsNavHistoryFolderResultNode michael@0: // michael@0: // Overridden container type for bookmark folders. It will keep the contents michael@0: // of the folder in sync with the bookmark service. michael@0: michael@0: class nsNavHistoryFolderResultNode : public nsNavHistoryContainerResultNode, michael@0: public nsINavHistoryQueryResultNode, michael@0: public mozilla::places::AsyncStatementCallback michael@0: { michael@0: public: michael@0: nsNavHistoryFolderResultNode(const nsACString& aTitle, michael@0: nsNavHistoryQueryOptions* options, michael@0: int64_t aFolderId); michael@0: michael@0: virtual ~nsNavHistoryFolderResultNode(); michael@0: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_FORWARD_COMMON_RESULTNODE_TO_BASE_NO_GETITEMMID michael@0: NS_IMETHOD GetType(uint32_t* type) { michael@0: if (mQueryItemId != -1) { michael@0: *type = nsNavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT; michael@0: } else { michael@0: *type = nsNavHistoryResultNode::RESULT_TYPE_FOLDER; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: NS_IMETHOD GetUri(nsACString& aURI); michael@0: NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN_AND_READONLY michael@0: NS_IMETHOD GetHasChildren(bool* aHasChildren); michael@0: NS_IMETHOD GetChildrenReadOnly(bool *aChildrenReadOnly); michael@0: NS_IMETHOD GetItemId(int64_t *aItemId); michael@0: NS_DECL_NSINAVHISTORYQUERYRESULTNODE michael@0: michael@0: virtual nsresult OpenContainer(); michael@0: michael@0: virtual nsresult OpenContainerAsync(); michael@0: NS_DECL_ASYNCSTATEMENTCALLBACK michael@0: michael@0: // This object implements a bookmark observer interface without deriving from michael@0: // the bookmark observers. This is called from the result's actual observer michael@0: // and it knows all observers are FolderResultNodes michael@0: NS_DECL_NSINAVBOOKMARKOBSERVER michael@0: michael@0: virtual void OnRemoving(); michael@0: michael@0: // this indicates whether the folder contents are valid, they don't go away michael@0: // after the container is closed until a notification comes in michael@0: bool mContentsValid; michael@0: michael@0: // If the node is generated from a place:folder=X query, this is the query's michael@0: // itemId. michael@0: int64_t mQueryItemId; michael@0: michael@0: nsresult FillChildren(); michael@0: void ClearChildren(bool aUnregister); michael@0: nsresult Refresh(); michael@0: michael@0: bool StartIncrementalUpdate(); michael@0: void ReindexRange(int32_t aStartIndex, int32_t aEndIndex, int32_t aDelta); michael@0: michael@0: nsNavHistoryResultNode* FindChildById(int64_t aItemId, michael@0: uint32_t* aNodeIndex); michael@0: michael@0: private: michael@0: michael@0: nsresult OnChildrenFilled(); michael@0: void EnsureRegisteredAsFolderObserver(); michael@0: nsresult FillChildrenAsync(); michael@0: michael@0: bool mIsRegisteredFolderObserver; michael@0: int32_t mAsyncBookmarkIndex; michael@0: }; michael@0: michael@0: // nsNavHistorySeparatorResultNode michael@0: // michael@0: // Separator result nodes do not hold any data. michael@0: class nsNavHistorySeparatorResultNode : public nsNavHistoryResultNode michael@0: { michael@0: public: michael@0: nsNavHistorySeparatorResultNode(); michael@0: michael@0: NS_IMETHOD GetType(uint32_t* type) michael@0: { *type = nsNavHistoryResultNode::RESULT_TYPE_SEPARATOR; return NS_OK; } michael@0: }; michael@0: michael@0: #endif // nsNavHistoryResult_h_