diff --git a/src/seasidecache.cpp b/src/seasidecache.cpp index 5882184..bc14ce3 100644 --- a/src/seasidecache.cpp +++ b/src/seasidecache.cpp @@ -1384,6 +1384,15 @@ void SeasideCache::requestStateChanged(QContactAbstractRequest::State state) cacheItem->itemData->mergeCandidatesFetched(candidateIds); } } + else if (m_fetchFilter != FilterNone) { + // We have completed fetching this filter set + completeSynchronizeList( + this, + m_contacts[m_fetchFilter], + m_cacheIndex, + m_contactIdRequest.ids(), + m_queryIndex); + } } else if (request == &m_relationshipSaveRequest || request == &m_relationshipRemoveRequest) { QSet contactIds; foreach (const QContactRelationship &relationship, m_relationshipSaveRequest.relationships() + @@ -1614,9 +1623,10 @@ void SeasideCache::keepPopulated() if (!m_keepPopulated) { m_keepPopulated = true; - // Start a query to fully populate the cache - m_refreshRequired = true; - requestUpdate(); + // Start a query to fully populate the cache, starting with favorites + m_fetchFilter = FilterFavorites; + m_fetchRequest.setFilter(QContactFavorite::match()); + m_fetchRequest.start(); } } diff --git a/src/synchronizelists.h b/src/synchronizelists.h index abef92e..4b9529a 100644 --- a/src/synchronizelists.h +++ b/src/synchronizelists.h @@ -29,39 +29,76 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." */ -#ifndef SYNCHRONIZELISTS_P_H -#define SYNCHRONIZELISTS_P_H +#ifndef SYNCHRONIZELISTS_H +#define SYNCHRONIZELISTS_H // Helper utility to synchronize a cached list with some reference list with correct // QAbstractItemModel signals and filtering. -// If the reference list is populated incrementally this can be called multiple times with the -// same variables c and r to progressively synchronize the lists. If after the final call either -// the c or r index is not equal to the length of the cache or reference lists respectively then -// the remaining items can be synchronized manually by removing the remaining items from the -// cache list before (filtering and) appending the remaining reference items. +// If the reference list is populated incrementally synchronizeList can be called multiple times with the +// same variables c and r to progressively synchronize the lists. After the final call completeSynchronizeList +// can be called to remove or append any items which remain unsynchronized. +// The Filtered variants allow the reference list to be filtered by a callback function to +// exclude unwanted items from the synchronized list. -template +template +bool compareIdentity(const T &item, const T &reference) +{ + return item == reference; +} + +template +int insertRange(Agent *agent, int index, int count, const ReferenceList &source, int sourceIndex) +{ + agent->insertRange(index, count, source, sourceIndex); + return count; +} + +template +int removeRange(Agent *agent, int index, int count) +{ + agent->removeRange(index, count); + return 0; +} + +template +int updateRange(Agent *agent, int index, int count, const ReferenceList &source, int sourceIndex) +{ + Q_UNUSED(agent); + Q_UNUSED(index); + Q_UNUSED(source); + Q_UNUSED(sourceIndex); + return count; +} + +template class SynchronizeList { - typedef typename ValueList::value_type ValueType; + typedef typename CacheList::const_reference CacheItem; + typedef typename ReferenceList::const_reference ReferenceItem; public: SynchronizeList( Agent *agent, - const ValueList &cache, + const CacheList &cache, int &c, const ReferenceList &reference, int &r) : agent(agent), cache(cache), c(c), reference(reference), r(r) { - while (c < cache.count() && r < reference.count()) { - if (cache.at(c) == reference.at(r)) { - ++c; - ++r; + int lastEqualC = c; + int lastEqualR = r; + for (; c < cache.count() && r < reference.count(); ++c, ++r) { + if (compareIdentity(cache.at(c), reference.at(r))) { continue; } + if (c > lastEqualC) { + lastEqualC += updateRange(agent, lastEqualC, c - lastEqualC, reference, lastEqualR); + c = lastEqualC; + lastEqualR = r; + } + bool match = false; // Iterate through both the reference and cache lists in parallel looking for first @@ -69,11 +106,11 @@ class SynchronizeList // looking. int count = 1; for (; !match && c + count < cache.count() && r + count < reference.count(); ++count) { - const ValueType cacheValue = cache.at(c + count); - const ValueType referenceValue = reference.at(r + count); + CacheItem cacheItem = cache.at(c + count); + ReferenceItem referenceItem = reference.at(r + count); for (int i = 0; i <= count; ++i) { - if (cacheMatch(i, count, referenceValue) || referenceMatch(i, count, cacheValue)) { + if (cacheMatch(i, count, referenceItem) || referenceMatch(i, count, cacheItem)) { match = true; break; } @@ -82,9 +119,9 @@ class SynchronizeList // Continue scanning the reference list if the cache has been exhausted. for (int re = r + count; !match && re < reference.count(); ++re) { - const ValueType referenceValue = reference.at(re); + ReferenceItem referenceItem = reference.at(re); for (int i = 0; i < count; ++i) { - if (cacheMatch(i, re - r, referenceValue)) { + if (cacheMatch(i, re - r, referenceItem)) { match = true; break; } @@ -93,9 +130,9 @@ class SynchronizeList // Continue scanning the cache if the reference list has been exhausted. for (int ce = c + count; !match && ce < cache.count(); ++ce) { - const ValueType cacheValue = cache.at(ce); + CacheItem cacheItem = cache.at(ce); for (int i = 0; i < count; ++i) { - if (referenceMatch(i, ce - c, cacheValue)) { + if (referenceMatch(i, ce - c, cacheItem)) { match = true; break; } @@ -104,38 +141,44 @@ class SynchronizeList if (!match) return; + + lastEqualC = c; + lastEqualR = r; + } + + if (c > lastEqualC) { + updateRange(agent, lastEqualC, c - lastEqualC, reference, lastEqualR); } } private: - // Tests if the cached value at i matches a referenceValue. + // Tests if the cached contact id at i matches a referenceId. // If there is a match removes all items traversed in the cache since the previous match // and inserts any items in the reference set found to to not be in the cache. - bool cacheMatch(int i, int count, ValueType referenceValue) + bool cacheMatch(int i, int count, ReferenceItem referenceItem) { - if (cache.at(c + i) == referenceValue) { + if (compareIdentity(cache.at(c + i), referenceItem)) { if (i > 0) - c += agent->removeRange(c, i); - c += agent->insertRange(c, count, reference, r) + 1; - r += count + 1; + c += removeRange(agent, c, i); + c += insertRange(agent, c, count, reference, r); + r += count; return true; } else { return false; } } - // Tests if the reference value at i matches a cacheValue. + // Tests if the reference contact id at i matches a cacheId. // If there is a match inserts all items traversed in the reference set since the // previous match and removes any items from the cache that were not found in the // reference list. - bool referenceMatch(int i, int count, ValueType cacheValue) + bool referenceMatch(int i, int count, CacheItem cacheItem) { - if (reference.at(r + i) == cacheValue) { - c += agent->removeRange(c, count); + if (compareIdentity(reference.at(r + i), cacheItem)) { + c += removeRange(agent, c, count); if (i > 0) - c += agent->insertRange(c, i, reference, r); - c += 1; - r += i + 1; + c += insertRange(agent, c, i, reference, r); + r += i; return true; } else { return false; @@ -143,156 +186,86 @@ class SynchronizeList } Agent * const agent; - const ValueList &cache; + const CacheList &cache; int &c; const ReferenceList &reference; int &r; }; -template -void synchronizeList( +template +void completeSynchronizeList( Agent *agent, - const ValueList &cache, - int &c, + const CacheList &cache, + int &cacheIndex, const ReferenceList &reference, - int &r) + int &referenceIndex) { - SynchronizeList(agent, cache, c, reference, r); -} - -template -class SynchronizeFilteredList -{ - typedef typename ValueList::value_type ValueType; - -public: - SynchronizeFilteredList( - Agent *agent, - const ValueList &cache, - int &c, - const ReferenceList &reference, - int &r) - : cache(cache) - , agent(agent) - , previousIndex(0) - , removeCount(0) - { - synchronizeList(this, cache, c, reference, r); - - if (filteredValues.count() > 0) { - c += filteredValues.count(); - agent->insertRange(previousIndex, filteredValues.count(), filteredValues, 0); - } else if (removeCount > 0) { - c -= removeCount; - agent->removeRange(previousIndex, removeCount); - } - - for (; previousIndex < c; ++previousIndex) { - int filterCount = 0; - for (int i; (i = previousIndex + filterCount) < c; ++filterCount) { - if (agent->filterValue(cache.at(i))) - break; - } - if (filterCount > 0) { - agent->removeRange(previousIndex, filterCount); - c -= filterCount; - } - } + if (cacheIndex < cache.count()) { + agent->removeRange(cacheIndex, cache.count() - cacheIndex); } - - int insertRange(int index, int count, const ValueList &source, int sourceIndex) - { - int adjustedIndex = index; - - if (removeCount > 0) { - adjustedIndex -= removeCount; - agent->removeRange(previousIndex, removeCount); - removeCount = 0; - } else if (filteredValues.count() > 0 && index > previousIndex) { - agent->insertRange(previousIndex, filteredValues.count(), filteredValues, 0); - adjustedIndex += filteredValues.count(); - previousIndex += filteredValues.count(); - filteredValues.resize(0); - } - - if (filteredValues.isEmpty()) { - for (; previousIndex < adjustedIndex;) { - int filterCount = 0; - for (int i; (i = previousIndex + filterCount) < adjustedIndex; ++filterCount) { - if (agent->filterValue(cache.at(i))) - break; - } - if (filterCount > 0) { - agent->removeRange(previousIndex, filterCount); - adjustedIndex -= filterCount; - } else { - ++previousIndex; - } - } - } - - for (int i = 0; i < count; ++i) { - const ValueType sourceValue = source.at(sourceIndex + i); - if (agent->filterValue(sourceValue)) - filteredValues.append(sourceValue); - } - - return adjustedIndex - index; + if (referenceIndex < reference.count()) { + agent->insertRange(cache.count(), reference.count() - referenceIndex, reference, referenceIndex); } - int removeRange(int index, int count) - { - int adjustedIndex = index; - if (filteredValues.count() > 0) { - adjustedIndex += filteredValues.count(); - agent->insertRange(previousIndex, filteredValues.count(), filteredValues, 0); - filteredValues.resize(0); - } else if (removeCount > 0 && adjustedIndex > previousIndex + removeCount) { - adjustedIndex -= removeCount; - agent->removeRange(previousIndex, removeCount); - removeCount = 0; - } + cacheIndex = 0; + referenceIndex = 0; +} - if (removeCount == 0) { - for (; previousIndex < adjustedIndex;) { - int filterCount = 0; - for (int i; (i = previousIndex + filterCount) < adjustedIndex; ++filterCount) { - if (agent->filterValue(cache.at(i))) - break; - } - if (previousIndex + filterCount == adjustedIndex) { - removeCount += filterCount; - break; - } else if (filterCount > 0) { - agent->removeRange(previousIndex, filterCount); - adjustedIndex -= filterCount; - } else { - ++previousIndex; - } - } - } +template +void synchronizeList( + Agent *agent, + const CacheList &cache, + int &cacheIndex, + const ReferenceList &reference, + int &referenceIndex) +{ + SynchronizeList( + agent, cache, cacheIndex, reference, referenceIndex); +} - removeCount += count; +template +void synchronizeList(Agent *agent, const CacheList &cache, const ReferenceList &reference) +{ + int cacheIndex = 0; + int referenceIndex = 0; + synchronizeList(agent, cache, cacheIndex, reference, referenceIndex); + completeSynchronizeList(agent, cache, cacheIndex, reference, referenceIndex); +} - return adjustedIndex - index + count; - } +template +ReferenceList filterList( + Agent *agent, + const ReferenceList &reference) +{ + ReferenceList filtered; + filtered.reserve(reference.count()); + foreach (const typename ReferenceList::value_type &value, reference) + if (agent->filterValue(value)) + filtered.append(value); - ValueList filteredValues; - const ValueList &cache; - Agent *agent; - int previousIndex; - int removeCount; -}; + return filtered; +} -template +template void synchronizeFilteredList( Agent *agent, - const ValueList &cache, - int &c, + const CacheList &cache, + int &cacheIndex, const ReferenceList &reference, - int &r) + int &referenceIndex) +{ + ReferenceList filtered = filterList(agent, reference); + synchronizeList(agent, cache, cacheIndex, filtered, referenceIndex); +} + +template +void synchronizeFilteredList(Agent *agent, const CacheList &cache, const ReferenceList &reference) { - SynchronizeFilteredList(agent, cache, c, reference, r); + int cacheIndex = 0; + int referenceIndex = 0; + ReferenceList filtered = filterList(agent, reference); + synchronizeList(agent, cache, cacheIndex, filtered, referenceIndex); + completeSynchronizeList(agent, cache, cacheIndex, filtered, referenceIndex); } #endif diff --git a/tests/tst_synchronizelists/tst_synchronizelists.cpp b/tests/tst_synchronizelists/tst_synchronizelists.cpp index 4ab5a67..7112604 100644 --- a/tests/tst_synchronizelists/tst_synchronizelists.cpp +++ b/tests/tst_synchronizelists/tst_synchronizelists.cpp @@ -234,17 +234,7 @@ void tst_SynchronizeLists::filtered() m_cache = original; m_filter = expected; - int c = 0; - int r = 0; - - synchronizeFilteredList(this, m_cache, c, reference, r); - - if (c < m_cache.count()) - m_cache.remove(c, m_cache.count() - c); - for (; r < reference.count(); ++r) { - if (m_filter.contains(reference.at(r))) - m_cache.append(reference.at(r)); - } + synchronizeFilteredList(this, m_cache, reference); if (m_cache != expected) { qDebug() << "expected" << expected; @@ -290,15 +280,7 @@ void tst_SynchronizeLists::unfiltered() m_filterEnabled = false; m_cache = original; - int c = 0; - int r = 0; - - synchronizeList(this, m_cache, c, reference, r); - - if (c < m_cache.count()) - m_cache.remove(c, m_cache.count() - c); - for (; r < reference.count(); ++r) - m_cache.append(reference.at(r)); + synchronizeList(this, m_cache, reference); if (m_cache != reference) { qDebug() << "expected" << reference;