Commit ff44b52d authored by mvogt's avatar mvogt

[libcontacts] Update the synchronizeList function

Also restore pre-fetching of favorite contact details.
parent e702826d
......@@ -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<ContactIdType> 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();
}
}
......
......@@ -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 <typename Agent, typename ValueList, typename ReferenceList>
template <typename T>
bool compareIdentity(const T &item, const T &reference)
{
return item == reference;
}
template <typename Agent, typename ReferenceList>
int insertRange(Agent *agent, int index, int count, const ReferenceList &source, int sourceIndex)
{
agent->insertRange(index, count, source, sourceIndex);
return count;
}
template <typename Agent>
int removeRange(Agent *agent, int index, int count)
{
agent->removeRange(index, count);
return 0;
}
template <typename Agent, typename ReferenceList>
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 <typename Agent, typename CacheList, typename ReferenceList>
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 @@ public:
// 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 @@ public:
// 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 @@ public:
// 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 @@ public:
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 @@ private:
}
Agent * const agent;
const ValueList &cache;
const CacheList &cache;
int &c;
const ReferenceList &reference;
int &r;
};
template <typename Agent, typename ValueList, typename ReferenceList>
void synchronizeList(
template <typename Agent, typename CacheList, typename ReferenceList>
void completeSynchronizeList(
Agent *agent,
const ValueList &cache,
int &c,
const CacheList &cache,
int &cacheIndex,
const ReferenceList &reference,
int &r)
int &referenceIndex)
{
SynchronizeList<Agent, ValueList, ReferenceList>(agent, cache, c, reference, r);
}
template <typename Agent, typename ValueList, typename ReferenceList>
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 <typename Agent, typename CacheList, typename ReferenceList>
void synchronizeList(
Agent *agent,
const CacheList &cache,
int &cacheIndex,
const ReferenceList &reference,
int &referenceIndex)
{
SynchronizeList<Agent, CacheList, ReferenceList>(
agent, cache, cacheIndex, reference, referenceIndex);
}
removeCount += count;
template <typename Agent, typename CacheList, typename ReferenceList>
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 <typename Agent, typename ReferenceList>
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 <typename Agent, typename ValueList, typename ReferenceList>
template <typename Agent, typename CacheList, typename ReferenceList>
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 <typename Agent, typename CacheList, typename ReferenceList>
void synchronizeFilteredList(Agent *agent, const CacheList &cache, const ReferenceList &reference)
{
SynchronizeFilteredList<Agent, ValueList, ReferenceList>(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
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment