From 21ac7212e15ac888233b4d9878579719b1854238 Mon Sep 17 00:00:00 2001 From: Matt Vogt Date: Tue, 7 Jan 2014 21:59:44 -0800 Subject: [PATCH] [libcontacts] Allow properties to be specified for searchability A model can now specify properties that should be loaded asynchronously to facilitate searching. The nickname property is now loaded in the first metadata retrieval, since some contacts have no other name details. --- src/seasidecache.cpp | 166 +++++++++++++++++++++++-------------------- src/seasidecache.h | 18 ++--- 2 files changed, 100 insertions(+), 84 deletions(-) diff --git a/src/seasidecache.cpp b/src/seasidecache.cpp index 3bd859d..fee93c8 100644 --- a/src/seasidecache.cpp +++ b/src/seasidecache.cpp @@ -200,6 +200,9 @@ QContactFetchHint metadataFetchHint(quint32 fetchTypes = 0) detailType() << detailType(); + // Include nickname, as some contacts have no other name + types << detailType(); + if (fetchTypes & SeasideCache::FetchAccountUri) { types << detailType(); } @@ -209,6 +212,9 @@ QContactFetchHint metadataFetchHint(quint32 fetchTypes = 0) if (fetchTypes & SeasideCache::FetchEmailAddress) { types << detailType(); } + if (fetchTypes & SeasideCache::FetchOrganization) { + types << detailType(); + } setDetailTypesHint(fetchHint, types); return fetchHint; @@ -248,9 +254,6 @@ QContactFetchHint extendedMetadataFetchHint(quint32 fetchTypes) if (fetchTypes & SeasideCache::FetchEmailAddress) { types << detailType(); } - if (fetchTypes & SeasideCache::FetchNickname) { - types << detailType(); - } if (fetchTypes & SeasideCache::FetchOrganization) { types << detailType(); } @@ -528,7 +531,8 @@ SeasideCache::SeasideCache() , m_keepPopulated(false) , m_populateProgress(Unpopulated) , m_fetchTypes(0) - , m_fetchTypesChanged(false) + , m_extraFetchTypes(0) + , m_dataTypesFetched(0) , m_updatesPending(false) , m_refreshRequired(false) , m_contactsUpdated(false) @@ -645,7 +649,7 @@ void SeasideCache::checkForExpiry() } } -void SeasideCache::registerModel(ListModel *model, FilterType type, FetchDataType fetchTypes) +void SeasideCache::registerModel(ListModel *model, FilterType type, FetchDataType requiredTypes, FetchDataType extraTypes) { if (!instancePtr) { new SeasideCache; @@ -656,7 +660,12 @@ void SeasideCache::registerModel(ListModel *model, FilterType type, FetchDataTyp } instancePtr->m_models[type].append(model); - instancePtr->keepPopulated(fetchTypes); + + instancePtr->keepPopulated(requiredTypes & SeasideCache::FetchTypesMask, extraTypes & SeasideCache::FetchTypesMask); + if (requiredTypes & SeasideCache::FetchTypesMask) { + // If we have filtered models, they will need a contact ID refresh after the cache is populated + instancePtr->m_refreshRequired = true; + } } void SeasideCache::unregisterModel(ListModel *model) @@ -1578,26 +1587,37 @@ bool SeasideCache::event(QEvent *event) m_fetchProcessedCount = 0; m_populateProgress = FetchFavorites; + m_dataTypesFetched |= m_fetchTypes; return true; } } - if ((m_populateProgress == Populated) && m_fetchTypesChanged) { - if (m_fetchRequest.isActive()) { - requestPending = true; - } else { - // We need to refetch the metadata for all contacts (because the required data changed) - m_fetchRequest.setFilter(favoriteFilter()); - m_fetchRequest.setFetchHint(favoriteFetchHint(m_fetchTypes)); - m_fetchRequest.setSorting(m_sortOrder); - m_fetchRequest.start(); + if ((m_populateProgress == Populated) && m_fetchTypes) { + quint32 unfetchedTypes = m_fetchTypes & ~m_dataTypesFetched & SeasideCache::FetchTypesMask; + if (unfetchedTypes) { + if (m_fetchRequest.isActive()) { + requestPending = true; + } else { + // Fetch the missing data types for whichever contacts need them + if (unfetchedTypes == SeasideCache::FetchPhoneNumber) { + m_fetchRequest.setFilter(QContactStatusFlags::matchFlag(QContactStatusFlags::HasPhoneNumber, QContactFilter::MatchContains)); + } else if (unfetchedTypes == SeasideCache::FetchEmailAddress) { + m_fetchRequest.setFilter(QContactStatusFlags::matchFlag(QContactStatusFlags::HasEmailAddress, QContactFilter::MatchContains)); + } else if (unfetchedTypes == SeasideCache::FetchAccountUri) { + m_fetchRequest.setFilter(QContactStatusFlags::matchFlag(QContactStatusFlags::HasOnlineAccount, QContactFilter::MatchContains)); + } else { + m_fetchRequest.setFilter(allFilter()); + } - m_fetchProcessedCount = 0; - m_fetchTypesChanged = false; - m_populateProgress = RefetchFavorites; + m_fetchRequest.setFetchHint(extendedMetadataFetchHint(unfetchedTypes)); + m_fetchRequest.start(); - return true; + m_fetchProcessedCount = 0; + m_dataTypesFetched |= unfetchedTypes; + + return true; + } } } @@ -1635,7 +1655,7 @@ bool SeasideCache::event(QEvent *event) // If completion is not required, we need to at least retrieve as much detail // as the favorites store, so we don't update any favorite with a smaller data subset m_activeResolve = &resolve; - m_fetchRequest.setFetchHint(resolve.requireComplete ? basicFetchHint() : favoriteFetchHint(m_fetchTypes)); + m_fetchRequest.setFetchHint(resolve.requireComplete ? basicFetchHint() : favoriteFetchHint(m_fetchTypes | m_extraFetchTypes)); m_fetchRequest.start(); m_fetchProcessedCount = 0; @@ -1732,41 +1752,32 @@ bool SeasideCache::event(QEvent *event) if (!requestPending) { // No remaining work is pending - do we have any background tasks? - if (m_keepPopulated) { - // Load extra data items that we want to be able to search on, if not already fetched - const quint32 fetchMask = (SeasideCache::FetchNickname | - SeasideCache::FetchOrganization | - SeasideCache::FetchPhoneNumber | - SeasideCache::FetchEmailAddress | - SeasideCache::FetchAccountUri); + quint32 unfetchedTypes = m_extraFetchTypes & ~m_dataTypesFetched & SeasideCache::FetchTypesMask; + if (unfetchedTypes) { + quint32 fetchType = 0; - if ((m_fetchTypes & fetchMask) != fetchMask) { + // Load extra data items that we want to be able to search on, if not already fetched + if (unfetchedTypes & SeasideCache::FetchOrganization) { + fetchType = SeasideCache::FetchOrganization; m_fetchRequest.setFilter(allFilter()); + } else if (unfetchedTypes & SeasideCache::FetchPhoneNumber) { + fetchType = SeasideCache::FetchPhoneNumber; + m_fetchRequest.setFilter(QContactStatusFlags::matchFlag(QContactStatusFlags::HasPhoneNumber, QContactFilter::MatchContains)); + } else if (unfetchedTypes & SeasideCache::FetchEmailAddress) { + fetchType = SeasideCache::FetchEmailAddress; + m_fetchRequest.setFilter(QContactStatusFlags::matchFlag(QContactStatusFlags::HasEmailAddress, QContactFilter::MatchContains)); + } else { + fetchType = SeasideCache::FetchAccountUri; + m_fetchRequest.setFilter(QContactStatusFlags::matchFlag(QContactStatusFlags::HasOnlineAccount, QContactFilter::MatchContains)); + } - quint32 fetchType = 0; - if ((m_fetchTypes & SeasideCache::FetchNickname) == 0) { - fetchType = SeasideCache::FetchNickname; - } else if ((m_fetchTypes & SeasideCache::FetchOrganization) == 0) { - fetchType = SeasideCache::FetchOrganization; - } else if ((m_fetchTypes & SeasideCache::FetchPhoneNumber) == 0) { - fetchType = SeasideCache::FetchPhoneNumber; - m_fetchRequest.setFilter(QContactStatusFlags::matchFlag(QContactStatusFlags::HasPhoneNumber, QContactFilter::MatchContains)); - } else if ((m_fetchTypes & SeasideCache::FetchEmailAddress) == 0) { - fetchType = SeasideCache::FetchEmailAddress; - m_fetchRequest.setFilter(QContactStatusFlags::matchFlag(QContactStatusFlags::HasEmailAddress, QContactFilter::MatchContains)); - } else { - fetchType = SeasideCache::FetchAccountUri; - m_fetchRequest.setFilter(QContactStatusFlags::matchFlag(QContactStatusFlags::HasOnlineAccount, QContactFilter::MatchContains)); - } - - m_fetchRequest.setFetchHint(extendedMetadataFetchHint(fetchType)); - m_fetchRequest.start(); + m_fetchRequest.setFetchHint(extendedMetadataFetchHint(fetchType)); + m_fetchRequest.start(); - m_fetchProcessedCount = 0; - m_fetchTypes |= fetchType; + m_fetchProcessedCount = 0; + m_dataTypesFetched |= fetchType; - return true; - } + return true; } m_updatesPending = false; @@ -2653,6 +2664,7 @@ void SeasideCache::requestStateChanged(QContactAbstractRequest::State state) m_fetchProcessedCount = 0; m_populateProgress = FetchFavorites; + m_dataTypesFetched |= m_fetchTypes; activityCompleted = false; } else if (m_populateProgress == FetchFavorites) { if (m_contactsToAppend.find(FilterFavorites) == m_contactsToAppend.end()) { @@ -2661,15 +2673,15 @@ void SeasideCache::requestStateChanged(QContactAbstractRequest::State state) qDebug() << "Favorites queried in" << m_timer.elapsed() << "ms"; } - // Next, query for all contacts (except favorites) - // Request the metadata of all contacts (only data from the primary table) + // Next, query for all contacts + // Request the metadata of all contacts (only data from the primary table, and any + // other details required to determine whether the contacts matches the filter) m_fetchRequest.setFilter(allFilter()); m_fetchRequest.setFetchHint(metadataFetchHint(m_fetchTypes)); m_fetchRequest.setSorting(m_sortOrder); m_fetchRequest.start(); m_fetchProcessedCount = 0; - m_fetchTypesChanged = false; m_populateProgress = FetchMetadata; activityCompleted = false; } else if (m_populateProgress == FetchMetadata) { @@ -2679,9 +2691,9 @@ void SeasideCache::requestStateChanged(QContactAbstractRequest::State state) qDebug() << "All queried in" << m_timer.elapsed() << "ms"; } - // Now query for online contacts + // Now query for online contacts - fetch the account details, so we know if they're valid m_fetchRequest.setFilter(onlineFilter()); - m_fetchRequest.setFetchHint(onlineFetchHint(m_fetchTypes)); + m_fetchRequest.setFetchHint(onlineFetchHint(m_fetchTypes | SeasideCache::FetchAccountUri)); m_fetchRequest.setSorting(m_onlineSortOrder); m_fetchRequest.start(); m_fetchProcessedCount = 0; @@ -2694,18 +2706,6 @@ void SeasideCache::requestStateChanged(QContactAbstractRequest::State state) qDebug() << "Online queried in" << m_timer.elapsed() << "ms"; } - m_populateProgress = Populated; - } else if (m_populateProgress == RefetchFavorites) { - // Re-fetch the non-favorites - m_fetchRequest.setFilter(nonfavoriteFilter()); - m_fetchRequest.setFetchHint(onlineFetchHint(m_fetchTypes)); - m_fetchRequest.start(); - m_fetchProcessedCount = 0; - - m_fetchProcessedCount = 0; - m_populateProgress = RefetchOthers; - } else if (m_populateProgress == RefetchOthers) { - // We're up to date again m_populateProgress = Populated; } else { // Result of a specific query @@ -3024,21 +3024,35 @@ QString SeasideCache::exportContacts() return vcard.fileName(); } -void SeasideCache::keepPopulated(quint32 fetchTypes) +void SeasideCache::keepPopulated(quint32 requiredTypes, quint32 extraTypes) { - if ((m_fetchTypes & fetchTypes) != fetchTypes) { - m_fetchTypes |= fetchTypes; - m_fetchTypesChanged = true; - requestUpdate(); + bool updateRequired(false); - if ((m_fetchTypes & SeasideCache::FetchPhoneNumber) != 0) { - // We don't need to check resolved numbers any further - m_resolvedPhoneNumbers.clear(); - } + // If these types are required, we will fetch them immediately + quint32 unfetchedTypes = requiredTypes & ~m_fetchTypes & SeasideCache::FetchTypesMask; + if (unfetchedTypes) { + m_fetchTypes |= requiredTypes; + updateRequired = true; + } + + // Otherwise, we can fetch them when idle + unfetchedTypes = extraTypes & ~m_extraFetchTypes & SeasideCache::FetchTypesMask; + if (unfetchedTypes) { + m_extraFetchTypes |= extraTypes; + updateRequired = true; + } + + if (((requiredTypes | extraTypes) & SeasideCache::FetchPhoneNumber) != 0) { + // We won't need to check resolved numbers any further + m_resolvedPhoneNumbers.clear(); } if (!m_keepPopulated) { m_keepPopulated = true; + updateRequired = true; + } + + if (updateRequired) { requestUpdate(); } } diff --git a/src/seasidecache.h b/src/seasidecache.h index dd14175..bf3257a 100644 --- a/src/seasidecache.h +++ b/src/seasidecache.h @@ -103,8 +103,11 @@ class CONTACTCACHE_EXPORT SeasideCache : public QObject FetchAccountUri = (1 << 0), FetchPhoneNumber = (1 << 1), FetchEmailAddress = (1 << 2), - FetchNickname = (1 << 3), - FetchOrganization = (1 << 4) + FetchOrganization = (1 << 3), + FetchTypesMask = (FetchAccountUri | + FetchPhoneNumber | + FetchEmailAddress | + FetchOrganization) }; enum DisplayLabelOrder { @@ -279,7 +282,7 @@ class CONTACTCACHE_EXPORT SeasideCache : public QObject static quint32 internalId(QContactLocalId id); #endif - static void registerModel(ListModel *model, FilterType type, FetchDataType extraData = FetchNone); + static void registerModel(ListModel *model, FilterType type, FetchDataType requiredTypes = FetchNone, FetchDataType extraTypes = FetchNone); static void unregisterModel(ListModel *model); static void registerUser(QObject *user); @@ -389,9 +392,7 @@ private slots: FetchFavorites, FetchMetadata, FetchOnline, - Populated, - RefetchFavorites, - RefetchOthers + Populated }; SeasideCache(); @@ -399,7 +400,7 @@ private slots: static void checkForExpiry(); - void keepPopulated(quint32 fetchTypes); + void keepPopulated(quint32 requiredTypes, quint32 extraTypes); void requestUpdate(); void appendContacts(const QList &contacts, FilterType filterType, bool partialFetch, const QSet &queryDetailTypes); @@ -496,7 +497,8 @@ private slots: bool m_keepPopulated; PopulateProgress m_populateProgress; quint32 m_fetchTypes; - bool m_fetchTypesChanged; + quint32 m_extraFetchTypes; + quint32 m_dataTypesFetched; bool m_updatesPending; bool m_refreshRequired; bool m_contactsUpdated;