NS_IMETHODIMP nsMsgSearchDBView::OpenWithHdrs(nsISimpleEnumerator *aHeaders, nsMsgViewSortTypeValue aSortType, nsMsgViewSortOrderValue aSortOrder, nsMsgViewFlagsTypeValue aViewFlags, int32_t *aCount) { if (aViewFlags & nsMsgViewFlagsType::kGroupBySort) return nsMsgGroupView::OpenWithHdrs(aHeaders, aSortType, aSortOrder, aViewFlags, aCount); m_sortType = aSortType; m_sortOrder = aSortOrder; m_viewFlags = aViewFlags; SaveSortInfo(m_sortType, m_sortOrder); bool hasMore; nsCOMPtr<nsISupports> supports; nsCOMPtr<nsIMsgDBHdr> msgHdr; nsCOMPtr<nsIMsgFolder> folder; nsresult rv = NS_OK; while (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv = aHeaders->HasMoreElements(&hasMore)) && hasMore) { rv = aHeaders->GetNext(getter_AddRefs(supports)); if (NS_SUCCEEDED(rv) && supports) { msgHdr = do_QueryInterface(supports); msgHdr->GetFolder(getter_AddRefs(folder)); AddHdrFromFolder(msgHdr, folder); } } *aCount = m_keys.Length(); return rv; }
NS_IMETHODIMP nsMsgXFVirtualFolderDBView::OnSearchHit(nsIMsgDBHdr* aMsgHdr, nsIMsgFolder *aFolder) { NS_ENSURE_ARG(aMsgHdr); NS_ENSURE_ARG(aFolder); nsCOMPtr<nsIMsgDatabase> dbToUse; nsCOMPtr<nsIDBFolderInfo> folderInfo; aFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(dbToUse)); if (m_curFolderGettingHits != aFolder && m_doingSearch && !m_doingQuickSearch) { m_curFolderHasCachedHits = false; // since we've gotten a hit for a new folder, the searches for // any previous folders are done, so deal with stale cached hits // for those folders now. UpdateCacheAndViewForPrevSearchedFolders(aFolder); m_curFolderGettingHits = aFolder; m_hdrHits.Clear(); m_curFolderStartKeyIndex = m_keys.Length(); } bool hdrInCache = false; nsCString searchUri; if (!m_doingQuickSearch) { m_viewFolder->GetURI(searchUri); dbToUse->HdrIsInCache(searchUri.get(), aMsgHdr, &hdrInCache); } if (!m_doingSearch || !m_curFolderHasCachedHits || !hdrInCache) { if (m_viewFlags & nsMsgViewFlagsType::kGroupBySort) nsMsgGroupView::OnNewHeader(aMsgHdr, nsMsgKey_None, true); else if (m_sortValid) InsertHdrFromFolder(aMsgHdr, aFolder); else AddHdrFromFolder(aMsgHdr, aFolder); } m_hdrHits.AppendObject(aMsgHdr); m_totalMessagesInView++; return NS_OK; }
nsresult nsMsgXFVirtualFolderDBView::InsertHdrFromFolder(nsIMsgDBHdr *msgHdr, nsISupports *folder) { nsMsgViewIndex insertIndex = GetInsertIndex(msgHdr); if (insertIndex == nsMsgViewIndex_None) return AddHdrFromFolder(msgHdr, folder); nsMsgKey msgKey; PRUint32 msgFlags; msgHdr->GetMessageKey(&msgKey); msgHdr->GetFlags(&msgFlags); m_keys.InsertElementAt(insertIndex, msgKey); m_flags.InsertElementAt(insertIndex, msgFlags); m_folders->InsertElementAt(folder, insertIndex); m_levels.InsertElementAt(insertIndex, 0); // the call to NoteChange() has to happen after we add the key // as NoteChange() will call RowCountChanged() which will call our GetRowCount() NoteChange(insertIndex, 1, nsMsgViewNotificationCode::insertOrDelete); return NS_OK; }
nsresult nsMsgSearchDBView::InsertHdrFromFolder(nsIMsgDBHdr *msgHdr, nsIMsgFolder *folder) { nsMsgViewIndex insertIndex = nsMsgViewIndex_None; // Threaded view always needs to go through AddHdrFromFolder since // it handles the xf view thread object creation. if (! (m_viewFlags & nsMsgViewFlagsType::kThreadedDisplay)) insertIndex = GetInsertIndex(msgHdr); if (insertIndex == nsMsgViewIndex_None) return AddHdrFromFolder(msgHdr, folder); nsMsgKey msgKey; uint32_t msgFlags; msgHdr->GetMessageKey(&msgKey); msgHdr->GetFlags(&msgFlags); InsertMsgHdrAt(insertIndex, msgHdr, msgKey, msgFlags, 0); // the call to NoteChange() has to happen after we add the key // as NoteChange() will call RowCountChanged() which will call our GetRowCount() NoteChange(insertIndex, 1, nsMsgViewNotificationCode::insertOrDelete); return NS_OK; }
NS_IMETHODIMP nsMsgSearchDBView::OnSearchHit(nsIMsgDBHdr* aMsgHdr, nsIMsgFolder *folder) { NS_ENSURE_ARG(aMsgHdr); NS_ENSURE_ARG(folder); if (m_folders.IndexOf(folder) < 0 ) //do this just for new folder { nsCOMPtr<nsIMsgDatabase> dbToUse; nsCOMPtr<nsIDBFolderInfo> folderInfo; folder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(dbToUse)); if (dbToUse) { dbToUse->AddListener(this); m_dbToUseList.AppendObject(dbToUse); } } m_totalMessagesInView++; if (m_sortValid) return InsertHdrFromFolder(aMsgHdr, folder); else return AddHdrFromFolder(aMsgHdr, folder); }
NS_IMETHODIMP nsMsgXFVirtualFolderDBView::OnSearchHit(nsIMsgDBHdr* aMsgHdr, nsIMsgFolder *folder) { NS_ENSURE_ARG(aMsgHdr); NS_ENSURE_ARG(folder); nsCOMPtr <nsISupports> supports = do_QueryInterface(folder); nsCOMPtr<nsIMsgDatabase> dbToUse; nsCOMPtr<nsIDBFolderInfo> folderInfo; folder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(dbToUse)); if (m_curFolderGettingHits != folder && m_doingSearch) { m_curFolderHasCachedHits = PR_FALSE; // since we've gotten a hit for a new folder, the searches for // any previous folders are done, so deal with stale cached hits // for those folders now. UpdateCacheAndViewForPrevSearchedFolders(folder); m_curFolderGettingHits = folder; m_hdrHits.Clear(); m_curFolderStartKeyIndex = m_keys.Length(); } PRBool hdrInCache = PR_FALSE; nsCString searchUri; m_viewFolder->GetURI(searchUri); dbToUse->HdrIsInCache(searchUri.get(), aMsgHdr, &hdrInCache); if (!m_doingSearch || !m_curFolderHasCachedHits || !hdrInCache) { if (m_sortValid) InsertHdrFromFolder(aMsgHdr, supports); else AddHdrFromFolder(aMsgHdr, supports); } m_hdrHits.AppendObject(aMsgHdr); return NS_OK; }
NS_IMETHODIMP nsMsgXFVirtualFolderDBView::OnNewSearch() { PRInt32 oldSize = GetSize(); RemovePendingDBListeners(); m_doingSearch = PR_TRUE; m_folders->Clear(); m_keys.Clear(); m_levels.Clear(); m_flags.Clear(); // needs to happen after we remove the keys, since RowCountChanged() will call our GetRowCount() if (mTree) mTree->RowCountChanged(0, -oldSize); // to use the search results cache, we'll need to iterate over the scopes in the // search session, calling getNthSearchScope for i = 0; i < searchSession.countSearchScopes; i++ // and for each folder, then open the db and pull out the cached hits, add them to the view. // For each hit in a new folder, we'll then clean up the stale hits from the previous folder(s). PRInt32 scopeCount; nsCOMPtr <nsIMsgSearchSession> searchSession = do_QueryReferent(m_searchSession); nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID); searchSession->CountSearchScopes(&scopeCount); if (mTree) mTree->BeginUpdateBatch(); for (PRInt32 i = 0; i < scopeCount; i++) { nsMsgSearchScopeValue scopeId; nsCOMPtr<nsIMsgFolder> searchFolder; searchSession->GetNthSearchScope(i, &scopeId, getter_AddRefs(searchFolder)); if (searchFolder) { nsCOMPtr<nsISimpleEnumerator> cachedHits; nsCOMPtr<nsIMsgDatabase> searchDB; nsCString searchUri; m_viewFolder->GetURI(searchUri); nsresult rv = searchFolder->GetMsgDatabase(nsnull, getter_AddRefs(searchDB)); if (NS_SUCCEEDED(rv) && searchDB) { if (msgDBService) msgDBService->RegisterPendingListener(searchFolder, this); m_foldersSearchingOver.AppendObject(searchFolder); searchDB->GetCachedHits(searchUri.get(), getter_AddRefs(cachedHits)); PRBool hasMore; if (cachedHits) { cachedHits->HasMoreElements(&hasMore); if (hasMore) { nsMsgKey prevKey = nsMsgKey_None; while (hasMore) { nsCOMPtr <nsIMsgDBHdr> pHeader; nsresult rv = cachedHits->GetNext(getter_AddRefs(pHeader)); NS_ASSERTION(NS_SUCCEEDED(rv), "nsMsgDBEnumerator broken"); if (pHeader && NS_SUCCEEDED(rv)) { nsMsgKey msgKey; pHeader->GetMessageKey(&msgKey); NS_ASSERTION(prevKey == nsMsgKey_None || msgKey > prevKey, "cached Hits not sorted"); prevKey = msgKey; AddHdrFromFolder(pHeader, searchFolder); // need to QI to nsISupports? } else break; cachedHits->HasMoreElements(&hasMore); } } } } } } if (mTree) mTree->EndUpdateBatch(); m_curFolderStartKeyIndex = 0; m_curFolderGettingHits = nsnull; m_curFolderHasCachedHits = PR_FALSE; // if we have cached hits, sort them. if (GetSize() > 0) { if (m_sortType != nsMsgViewSortType::byThread) { m_sortValid = PR_FALSE; //sort the results Sort(m_sortType, m_sortOrder); } } // mSearchResults->Clear(); return NS_OK; }
NS_IMETHODIMP nsMsgXFVirtualFolderDBView::OnNewSearch() { int32_t oldSize = GetSize(); RemovePendingDBListeners(); m_doingSearch = true; m_totalMessagesInView = 0; m_folders.Clear(); m_keys.Clear(); m_levels.Clear(); m_flags.Clear(); // needs to happen after we remove the keys, since RowCountChanged() will call our GetRowCount() if (mTree) mTree->RowCountChanged(0, -oldSize); // to use the search results cache, we'll need to iterate over the scopes in the // search session, calling getNthSearchScope for i = 0; i < searchSession.countSearchScopes; i++ // and for each folder, then open the db and pull out the cached hits, add them to the view. // For each hit in a new folder, we'll then clean up the stale hits from the previous folder(s). int32_t scopeCount; nsCOMPtr<nsIMsgSearchSession> searchSession = do_QueryReferent(m_searchSession); NS_ENSURE_TRUE(searchSession, NS_OK); // just ignore nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID); searchSession->CountSearchScopes(&scopeCount); // Figure out how many search terms the virtual folder has. nsCOMPtr<nsIMsgDatabase> virtDatabase; nsCOMPtr<nsIDBFolderInfo> dbFolderInfo; nsresult rv = m_viewFolder->GetDBFolderInfoAndDB(getter_AddRefs(dbFolderInfo), getter_AddRefs(virtDatabase)); NS_ENSURE_SUCCESS(rv, rv); nsCString terms; dbFolderInfo->GetCharProperty("searchStr", terms); nsCOMPtr<nsISupportsArray> searchTerms; rv = searchSession->GetSearchTerms(getter_AddRefs(searchTerms)); NS_ENSURE_SUCCESS(rv, rv); nsCString curSearchAsString; rv = MsgTermListToString(searchTerms, curSearchAsString); // Trim off the initial AND/OR, which is irrelevant and inconsistent between // what searchSpec.js generates, and what's in virtualFolders.dat. curSearchAsString.Cut(0, StringBeginsWith(curSearchAsString, NS_LITERAL_CSTRING("AND")) ? 3 : 2); terms.Cut(0, StringBeginsWith(terms, NS_LITERAL_CSTRING("AND")) ? 3 : 2); NS_ENSURE_SUCCESS(rv, rv); // If the search session search string doesn't match the vf search str, then we're doing // quick search, which means we don't want to invalidate cached results, or // used cached results. m_doingQuickSearch = !curSearchAsString.Equals(terms); if (mTree && !m_doingQuickSearch) mTree->BeginUpdateBatch(); for (int32_t i = 0; i < scopeCount; i++) { nsMsgSearchScopeValue scopeId; nsCOMPtr<nsIMsgFolder> searchFolder; searchSession->GetNthSearchScope(i, &scopeId, getter_AddRefs(searchFolder)); if (searchFolder) { nsCOMPtr<nsISimpleEnumerator> cachedHits; nsCOMPtr<nsIMsgDatabase> searchDB; nsCString searchUri; m_viewFolder->GetURI(searchUri); nsresult rv = searchFolder->GetMsgDatabase(getter_AddRefs(searchDB)); if (NS_SUCCEEDED(rv) && searchDB) { if (msgDBService) msgDBService->RegisterPendingListener(searchFolder, this); m_foldersSearchingOver.AppendObject(searchFolder); if (m_doingQuickSearch) // ignore cached hits in quick search case. continue; searchDB->GetCachedHits(searchUri.get(), getter_AddRefs(cachedHits)); bool hasMore; if (cachedHits) { cachedHits->HasMoreElements(&hasMore); if (hasMore) { nsMsgKey prevKey = nsMsgKey_None; while (hasMore) { nsCOMPtr <nsIMsgDBHdr> pHeader; nsresult rv = cachedHits->GetNext(getter_AddRefs(pHeader)); NS_ASSERTION(NS_SUCCEEDED(rv), "nsMsgDBEnumerator broken"); if (pHeader && NS_SUCCEEDED(rv)) { nsMsgKey msgKey; pHeader->GetMessageKey(&msgKey); NS_ASSERTION(prevKey == nsMsgKey_None || msgKey > prevKey, "cached Hits not sorted"); prevKey = msgKey; AddHdrFromFolder(pHeader, searchFolder); } else break; cachedHits->HasMoreElements(&hasMore); } } } } } } if (mTree && !m_doingQuickSearch) mTree->EndUpdateBatch(); m_curFolderStartKeyIndex = 0; m_curFolderGettingHits = nullptr; m_curFolderHasCachedHits = false; // if we have cached hits, sort them. if (GetSize() > 0) { // currently, we keep threaded views sorted while we build them. if (m_sortType != nsMsgViewSortType::byThread && !(m_viewFlags & nsMsgViewFlagsType::kThreadedDisplay)) { m_sortValid = false; //sort the results Sort(m_sortType, m_sortOrder); } } return NS_OK; }