void SeasidePerson::setAvatarPath(QUrl avatarPath) { QContactAvatar avatarDetail = mContact.detail<QContactAvatar>(); avatarDetail.setImageUrl(QUrl(avatarPath)); mContact.saveDetail(&avatarDetail); emit avatarPathChanged(); }
void BusinessCardHandling::saveAvatar(const QString filename, QPixmap p, QContact& contact) { // Path to store avatar picture QString path; #ifdef Q_OS_SYMBIAN path.append("c:/System/"); #endif path.append(filename); // Remove same file if exists QFile file; if (file.exists(path)) file.remove(path); // Save pixmap into file bool saveRet = p.save(path); if (saveRet) { // Create avatar QContactAvatar contactAvatar; contactAvatar.setImageUrl(QUrl(path)); bool saveAvatar = contact.saveDetail(&contactAvatar); // Save contact if (saveAvatar) m_contactManager->saveContact(&contact); // NOTE: Do not remove picture, system needs it for showing avatar // Remove picture file //bool removeRet = file.remove(path); } }
QContactDetail *CntTransformAvatar::transformItemField(const CContactItemField& field, const QContact &contact) { Q_UNUSED(contact); QContactAvatar *avatar = new QContactAvatar(); if (field.ContentType().ContainsFieldType(KUidContactFieldCodImage)) { CContactTextField* storage = field.TextStorage(); QString avatarString = QString::fromUtf16(storage->Text().Ptr(), storage->Text().Length()); avatar->setImageUrl(QUrl(avatarString)); } return avatar; }
int main(int argc, char *argv[]) { QCoreApplication application(argc, argv); QMap<QString, QString> parameters; parameters.insert(QString::fromLatin1("mergePresenceChanges"), QString::fromLatin1("false")); QContactManager manager(QString::fromLatin1("org.nemomobile.contacts.sqlite"), parameters); QContactFetchRequest request; request.setManager(&manager); // Perform an initial request to ensure the database has been created before we start timing request.start(); request.waitForFinished(); qint64 elapsedTimeTotal = 0; QElapsedTimer asyncTotalTimer; asyncTotalTimer.start(); // Fetch all, no optimization hints for (int i = 0; i < 3; ++i) { QElapsedTimer timer; timer.start(); request.start(); request.waitForFinished(); qint64 elapsed = timer.elapsed(); qDebug() << i << ": Fetch completed in" << elapsed << "ms"; elapsedTimeTotal += elapsed; } // Skip relationships QContactFetchHint hint; hint.setOptimizationHints(QContactFetchHint::NoRelationships); request.setFetchHint(hint); for (int i = 0; i < 3; ++i) { QElapsedTimer timer; timer.start(); request.start(); request.waitForFinished(); qint64 elapsed = timer.elapsed(); qDebug() << i << ": No-relationships fetch completed in" << elapsed << "ms"; elapsedTimeTotal += elapsed; } // Reduce data access #ifdef USING_QTPIM hint.setDetailTypesHint(QList<QContactDetail::DetailType>() << QContactName::Type << QContactAddress::Type); #else hint.setDetailDefinitionsHint(QStringList() << QContactName::DefinitionName << QContactAddress::DefinitionName); #endif request.setFetchHint(hint); for (int i = 0; i < 3; ++i) { QElapsedTimer timer; timer.start(); request.start(); request.waitForFinished(); qint64 elapsed = timer.elapsed(); qDebug() << i << ": Reduced data fetch completed in" << elapsed << "ms"; elapsedTimeTotal += elapsed; } // Reduce number of results hint.setMaxCountHint(request.contacts().count() / 8); request.setFetchHint(hint); for (int i = 0; i < 3; ++i) { QElapsedTimer timer; timer.start(); request.start(); request.waitForFinished(); qint64 elapsed = timer.elapsed(); qDebug() << i << ": Max count fetch completed in" << elapsed << "ms"; elapsedTimeTotal += elapsed; } qint64 asyncTotalElapsed = asyncTotalTimer.elapsed(); // Time some synchronous operations. First, generate the test data. qsrand((int)asyncTotalElapsed); QList<int> nbrContacts; nbrContacts << 10 << 100 << 500 << 1000 << 2000; QList<QList<QContact> > testData; qDebug() << "\n\n\n\n\n"; qDebug() << "Generating test data for timings..."; for (int i = 0; i < nbrContacts.size(); ++i) { int howMany = nbrContacts.at(i); QList<QContact> newTestData; newTestData.reserve(howMany); for (int j = 0; j < howMany; ++j) { // Use testing sync target, so 'local' won't be modified into 'was_local' via aggregation newTestData.append(generateContact(QString::fromLatin1("testing"))); } testData.append(newTestData); } // Perform the timings - these all create new contacts and assume an "empty" initial database QElapsedTimer syncTimer; for (int i = 0; i < testData.size(); ++i) { QList<QContact> td = testData.at(i); qint64 ste = 0; qDebug() << "Performing tests for" << td.size() << "contacts:"; syncTimer.start(); manager.saveContacts(&td); ste = syncTimer.elapsed(); qDebug() << " saving took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; QContactDetailFilter testingFilter; #ifdef USING_QTPIM testingFilter.setDetailType(QContactSyncTarget::Type, QContactSyncTarget::FieldSyncTarget); #else testingFilter.setDetailDefinitionName(QContactSyncTarget::DefinitionName, QContactSyncTarget::FieldSyncTarget); #endif testingFilter.setValue(QString::fromLatin1("testing")); QContactFetchHint fh; syncTimer.start(); QList<QContact> readContacts = manager.contacts(testingFilter, QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); if (readContacts.size() != td.size()) { qWarning() << "Invalid retrieval count:" << readContacts.size() << "expecting:" << td.size(); } qDebug() << " reading all (" << readContacts.size() << "), all details, took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; #ifdef USING_QTPIM fh.setDetailTypesHint(QList<QContactDetail::DetailType>() << QContactDisplayLabel::Type << QContactName::Type << QContactAvatar::Type << QContactPhoneNumber::Type << QContactEmailAddress::Type); #else fh.setDetailDefinitionsHint(QStringList() << QContactDisplayLabel::DefinitionName << QContactName::DefinitionName << QContactAvatar::DefinitionName << QContactPhoneNumber::DefinitionName << QContactEmailAddress::DefinitionName); #endif syncTimer.start(); readContacts = manager.contacts(testingFilter, QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); if (readContacts.size() != td.size()) { qWarning() << "Invalid retrieval count:" << readContacts.size() << "expecting:" << td.size(); } qDebug() << " reading all, common details, took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; fh.setOptimizationHints(QContactFetchHint::NoRelationships); #ifdef USING_QTPIM fh.setDetailTypesHint(QList<QContactDetail::DetailType>()); #else fh.setDetailDefinitionsHint(QStringList()); #endif syncTimer.start(); readContacts = manager.contacts(testingFilter, QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); if (readContacts.size() != td.size()) { qWarning() << "Invalid retrieval count:" << readContacts.size() << "expecting:" << td.size(); } qDebug() << " reading all, no relationships, took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; #ifdef USING_QTPIM fh.setDetailTypesHint(QList<QContactDetail::DetailType>() << QContactDisplayLabel::Type << QContactName::Type << QContactAvatar::Type); #else fh.setDetailDefinitionsHint(QStringList() << QContactDisplayLabel::DefinitionName << QContactName::DefinitionName << QContactAvatar::DefinitionName); #endif syncTimer.start(); readContacts = manager.contacts(testingFilter, QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); if (readContacts.size() != td.size()) { qWarning() << "Invalid retrieval count:" << readContacts.size() << "expecting:" << td.size(); } qDebug() << " reading all, display details + no rels, took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; // Read the contacts, selected by ID QList<QContactId> idsToRetrieve; for (int j = 0; j < td.size(); ++j) { idsToRetrieve.append(retrievalId(td.at(j))); } syncTimer.start(); readContacts = manager.contacts(idsToRetrieve, fh, 0); ste = syncTimer.elapsed(); if (readContacts.size() != td.size()) { qWarning() << "Invalid retrieval count:" << readContacts.size() << "expecting:" << td.size(); } qDebug() << " reading all by IDs, display details + no rels, took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; // Read the same set using ID filtering #ifdef USING_QTPIM QContactIdFilter idFilter; #else QContactLocalIdFilter idFilter; #endif idFilter.setIds(idsToRetrieve); syncTimer.start(); readContacts = manager.contacts(idFilter, QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); if (readContacts.size() != td.size()) { qWarning() << "Invalid retrieval count:" << readContacts.size() << "expecting:" << td.size(); } qDebug() << " reading all by ID filter, display details + no rels, took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; // Read the same set, but filter everything out using syncTarget QContactDetailFilter aggregateFilter; #ifdef USING_QTPIM aggregateFilter.setDetailType(QContactSyncTarget::Type, QContactSyncTarget::FieldSyncTarget); #else aggregateFilter.setDetailDefinitionName(QContactSyncTarget::DefinitionName, QContactSyncTarget::FieldSyncTarget); #endif aggregateFilter.setValue(QString::fromLatin1("aggregate")); syncTimer.start(); readContacts = manager.contacts(idFilter & aggregateFilter, QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); if (readContacts.size() != 0) { qWarning() << "Invalid retrieval count:" << readContacts.size() << "expecting:" << 0; } qDebug() << " reading all by ID filter & aggregate, display details + no rels, took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; QContactDetailFilter firstNameStartsA; #ifdef USING_QTPIM firstNameStartsA.setDetailType(QContactName::Type, QContactName::FieldFirstName); #else firstNameStartsA.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldFirstName); #endif firstNameStartsA.setValue("A"); firstNameStartsA.setMatchFlags(QContactDetailFilter::MatchStartsWith); #ifdef USING_QTPIM fh.setDetailTypesHint(QList<QContactDetail::DetailType>()); #else fh.setDetailDefinitionsHint(QStringList()); #endif syncTimer.start(); readContacts = manager.contacts(firstNameStartsA, QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); qDebug() << " reading filtered (" << readContacts.size() << "), no relationships, took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; QList<ContactIdType> idsToRemove; for (int j = 0; j < td.size(); ++j) { idsToRemove.append(retrievalId(td.at(j))); } syncTimer.start(); manager.removeContacts(idsToRemove); ste = syncTimer.elapsed(); qDebug() << " removing test data took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; } // these tests are slightly different to those above. They operate on much smaller // batches, but occur after the database has already been prefilled with some data. QList<int> smallerNbrContacts; smallerNbrContacts << 1 << 2 << 5 << 10 << 20 << 50; QList<QList<QContact> > smallerTestData; qDebug() << "\n\nGenerating smaller test data for prefilled timings..."; for (int i = 0; i < smallerNbrContacts.size(); ++i) { int howMany = smallerNbrContacts.at(i); QList<QContact> newTestData; newTestData.reserve(howMany); for (int j = 0; j < howMany; ++j) { newTestData.append(generateContact()); } smallerTestData.append(newTestData); } // prefill the database QList<QContact> prefillData; for (int i = 0; i < testData.size() && testData.at(i).size() < 1001; ++i) { prefillData = testData.at(i); } qDebug() << "Prefilling database with" << prefillData.size() << "contacts... this will take a while..."; manager.saveContacts(&prefillData); qDebug() << "Now performing timings (shouldn't get aggregated)..."; for (int i = 0; i < smallerTestData.size(); ++i) { QList<QContact> td = smallerTestData.at(i); qint64 ste = 0; qDebug() << "Performing tests for" << td.size() << "contacts:"; syncTimer.start(); manager.saveContacts(&td); ste = syncTimer.elapsed(); qDebug() << " saving took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; QContactFetchHint fh; syncTimer.start(); QList<QContact> readContacts = manager.contacts(QContactFilter(), QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); qDebug() << " reading all (" << readContacts.size() << "), all details, took" << ste << "milliseconds"; elapsedTimeTotal += ste; #ifdef USING_QTPIM fh.setDetailTypesHint(QList<QContactDetail::DetailType>() << QContactDisplayLabel::Type << QContactName::Type << QContactAvatar::Type << QContactPhoneNumber::Type << QContactEmailAddress::Type); #else fh.setDetailDefinitionsHint(QStringList() << QContactDisplayLabel::DefinitionName << QContactName::DefinitionName << QContactAvatar::DefinitionName << QContactPhoneNumber::DefinitionName << QContactEmailAddress::DefinitionName); #endif syncTimer.start(); readContacts = manager.contacts(QContactFilter(), QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); qDebug() << " reading all, common details, took" << ste << "milliseconds"; elapsedTimeTotal += ste; fh.setOptimizationHints(QContactFetchHint::NoRelationships); #ifdef USING_QTPIM fh.setDetailTypesHint(QList<QContactDetail::DetailType>()); #else fh.setDetailDefinitionsHint(QStringList()); #endif syncTimer.start(); readContacts = manager.contacts(QContactFilter(), QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); qDebug() << " reading all, no relationships, took" << ste << "milliseconds"; elapsedTimeTotal += ste; #ifdef USING_QTPIM fh.setDetailTypesHint(QList<QContactDetail::DetailType>() << QContactDisplayLabel::Type << QContactName::Type << QContactAvatar::Type); #else fh.setDetailDefinitionsHint(QStringList() << QContactDisplayLabel::DefinitionName << QContactName::DefinitionName << QContactAvatar::DefinitionName); #endif syncTimer.start(); readContacts = manager.contacts(QContactFilter(), QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); qDebug() << " reading all, display details + no rels, took" << ste << "milliseconds"; elapsedTimeTotal += ste; QContactDetailFilter firstNameStartsA; #ifdef USING_QTPIM firstNameStartsA.setDetailType(QContactName::Type, QContactName::FieldFirstName); #else firstNameStartsA.setDetailDefinitionName(QContactName::DefinitionName, QContactName::FieldFirstName); #endif firstNameStartsA.setValue("A"); firstNameStartsA.setMatchFlags(QContactDetailFilter::MatchStartsWith); #ifdef USING_QTPIM fh.setDetailTypesHint(QList<QContactDetail::DetailType>()); #else fh.setDetailDefinitionsHint(QStringList()); #endif syncTimer.start(); readContacts = manager.contacts(firstNameStartsA, QList<QContactSortOrder>(), fh); ste = syncTimer.elapsed(); qDebug() << " reading filtered (" << readContacts.size() << "), no relationships, took" << ste << "milliseconds"; elapsedTimeTotal += ste; QList<ContactIdType> idsToRemove; for (int j = 0; j < td.size(); ++j) { idsToRemove.append(retrievalId(td.at(j))); } syncTimer.start(); manager.removeContacts(idsToRemove); ste = syncTimer.elapsed(); qDebug() << " removing test data took" << ste << "milliseconds (" << ((1.0 * ste) / (1.0 * td.size())) << "msec per contact )"; elapsedTimeTotal += ste; } // The next test is about saving contacts which should get aggregated into others. // Aggregation is an expensive operation, so we expect these save operations to take longer. qDebug() << "\n\nPerforming aggregation tests"; QList<QContact> contactsToAggregate; for (int i = 0; i < 100; ++i) { QContact existingContact = prefillData.at(prefillData.size() - 1 - i); QContact contactToAggregate; QContactSyncTarget newSyncTarget; newSyncTarget.setSyncTarget(QString(QLatin1String("fetchtimes-aggregation"))); QContactName aggName = existingContact.detail<QContactName>(); // ensures it'll get aggregated QContactOnlineAccount newOnlineAcct; // new data, which should get promoted up etc. newOnlineAcct.setAccountUri(QString(QLatin1String("test-aggregation-%1@fetchtimes")).arg(i)); contactToAggregate.saveDetail(&newSyncTarget); contactToAggregate.saveDetail(&aggName); contactToAggregate.saveDetail(&newOnlineAcct); contactsToAggregate.append(contactToAggregate); } syncTimer.start(); manager.saveContacts(&contactsToAggregate); qint64 aggregationElapsed = syncTimer.elapsed(); int totalAggregatesInDatabase = manager.contactIds().count(); qDebug() << "Average time for aggregation of" << contactsToAggregate.size() << "contacts (with" << totalAggregatesInDatabase << "existing in database):" << aggregationElapsed << "milliseconds (" << ((1.0 * aggregationElapsed) / (1.0 * contactsToAggregate.size())) << " msec per aggregated contact )"; elapsedTimeTotal += aggregationElapsed; // Now perform the test again, this time with more aggregates, to test nonlinearity. contactsToAggregate.clear(); for (int i = 200; i < 400; ++i) { QContact existingContact = prefillData.at(prefillData.size() - 1 - i); QContact contactToAggregate; QContactSyncTarget newSyncTarget; newSyncTarget.setSyncTarget(QString(QLatin1String("fetchtimes-aggregation"))); QContactName aggName = existingContact.detail<QContactName>(); // ensures it'll get aggregated QContactOnlineAccount newOnlineAcct; // new data, which should get promoted up etc. newOnlineAcct.setAccountUri(QString(QLatin1String("test-aggregation-%1@fetchtimes")).arg(i)); contactToAggregate.saveDetail(&newSyncTarget); contactToAggregate.saveDetail(&aggName); contactToAggregate.saveDetail(&newOnlineAcct); contactsToAggregate.append(contactToAggregate); } syncTimer.start(); manager.saveContacts(&contactsToAggregate); aggregationElapsed = syncTimer.elapsed(); totalAggregatesInDatabase = manager.contactIds().count(); qDebug() << "Average time for aggregation of" << contactsToAggregate.size() << "contacts (with" << totalAggregatesInDatabase << "existing in database):" << aggregationElapsed << "milliseconds (" << ((1.0 * aggregationElapsed) / (1.0 * contactsToAggregate.size())) << " msec per aggregated contact )"; elapsedTimeTotal += aggregationElapsed; // The next test is about updating existing contacts, amongst a large set. // We're especially interested in presence updates, as these are common. qDebug() << "\n\nPerforming presence update tests:"; // in the first presence update test, we update a small number of contacts. QStringList presenceAvatars = generateAvatarsList(); QList<QContact> contactsToUpdate; for (int i = 0; i < 10; ++i) { contactsToUpdate.append(prefillData.at(prefillData.size() - 1 - i)); } // modify the presence, nickname and avatar of the test data for (int j = 0; j < contactsToUpdate.size(); ++j) { QString genstr = QString::number(j); QContact curr = contactsToUpdate[j]; QContactPresence cp = curr.detail<QContactPresence>(); QContactNickname nn = curr.detail<QContactNickname>(); QContactAvatar av = curr.detail<QContactAvatar>(); cp.setNickname(genstr); cp.setCustomMessage(genstr); cp.setTimestamp(QDateTime::currentDateTime()); cp.setPresenceState(static_cast<QContactPresence::PresenceState>(qrand() % 4)); nn.setNickname(nn.nickname() + genstr); av.setImageUrl(genstr + presenceAvatars.at(qrand() % presenceAvatars.size())); curr.saveDetail(&cp); curr.saveDetail(&nn); curr.saveDetail(&av); contactsToUpdate.replace(j, curr); } // perform a batch save. syncTimer.start(); manager.saveContacts(&contactsToUpdate); qint64 presenceElapsed = syncTimer.elapsed(); totalAggregatesInDatabase = manager.contactIds().count(); qDebug() << " update ( batch of" << contactsToUpdate.size() << ") presence+nick+avatar (with" << totalAggregatesInDatabase << "existing in database, all overlap):" << presenceElapsed << "milliseconds (" << ((1.0 * presenceElapsed) / (1.0 * contactsToUpdate.size())) << " msec per updated contact )"; elapsedTimeTotal += presenceElapsed; // in the second presence update test, we update ALL of the contacts // This simulates having a large number of contacts from a single source (eg, a social network) // where (due to changed connectivity status) presence updates for the entire set become available. contactsToUpdate.clear(); QDateTime timestamp = QDateTime::currentDateTime(); for (int j = 0; j < prefillData.size(); ++j) { QContact curr = prefillData.at(j); QString genstr = QString::number(j) + "2"; QContactPresence cp = curr.detail<QContactPresence>(); QContactNickname nn = curr.detail<QContactNickname>(); QContactAvatar av = curr.detail<QContactAvatar>(); cp.setNickname(genstr); cp.setCustomMessage(genstr); cp.setTimestamp(timestamp); cp.setPresenceState(static_cast<QContactPresence::PresenceState>((qrand() % 4) + 1)); nn.setNickname(nn.nickname() + genstr); av.setImageUrl(genstr + presenceAvatars.at(qrand() % presenceAvatars.size())); curr.saveDetail(&cp); curr.saveDetail(&nn); curr.saveDetail(&av); contactsToUpdate.append(curr); } // perform a batch save. syncTimer.start(); manager.saveContacts(&contactsToUpdate); presenceElapsed = syncTimer.elapsed(); totalAggregatesInDatabase = manager.contactIds().count(); qDebug() << " update ( batch of" << contactsToUpdate.size() << ") presence+nick+avatar (with" << totalAggregatesInDatabase << "existing in database, all overlap):" << presenceElapsed << "milliseconds (" << ((1.0 * presenceElapsed) / (1.0 * contactsToUpdate.size())) << " msec per updated contact )"; elapsedTimeTotal += presenceElapsed; // the third presence update test is identical to the previous, but with 2000 prefilled contacts in database. qDebug() << " Adding more prefill data, please wait..."; QList<QContact> morePrefillData; for (int i = 0; i < 1000; ++i) { morePrefillData.append(generateContact(QString::fromLatin1("testing"))); } manager.saveContacts(&morePrefillData); // now do the updates and save. contactsToUpdate.clear(); timestamp = QDateTime::currentDateTime(); for (int j = 0; j < prefillData.size(); ++j) { QContact curr = prefillData.at(j); QString genstr = QString::number(j) + "3"; QContactPresence cp = curr.detail<QContactPresence>(); QContactNickname nn = curr.detail<QContactNickname>(); QContactAvatar av = curr.detail<QContactAvatar>(); cp.setNickname(genstr); cp.setCustomMessage(genstr); cp.setTimestamp(timestamp); cp.setPresenceState(static_cast<QContactPresence::PresenceState>((qrand() % 4) + 1)); nn.setNickname(nn.nickname() + genstr); av.setImageUrl(genstr + presenceAvatars.at(qrand() % presenceAvatars.size())); curr.saveDetail(&cp); curr.saveDetail(&nn); curr.saveDetail(&av); contactsToUpdate.append(curr); } for (int j = 0; j < morePrefillData.size(); ++j) { QContact curr = morePrefillData.at(j); QString genstr = QString::number(j) + "3"; QContactPresence cp = curr.detail<QContactPresence>(); QContactNickname nn = curr.detail<QContactNickname>(); QContactAvatar av = curr.detail<QContactAvatar>(); cp.setNickname(genstr); cp.setCustomMessage(genstr); cp.setTimestamp(timestamp); cp.setPresenceState(static_cast<QContactPresence::PresenceState>((qrand() % 4) + 1)); nn.setNickname(nn.nickname() + genstr); av.setImageUrl(genstr + presenceAvatars.at(qrand() % presenceAvatars.size())); curr.saveDetail(&cp); curr.saveDetail(&nn); curr.saveDetail(&av); contactsToUpdate.append(curr); } // perform a batch save. syncTimer.start(); manager.saveContacts(&contactsToUpdate); presenceElapsed = syncTimer.elapsed(); totalAggregatesInDatabase = manager.contactIds().count(); qDebug() << " update ( batch of" << contactsToUpdate.size() << ") presence+nick+avatar (with" << totalAggregatesInDatabase << "existing in database, all overlap):" << presenceElapsed << "milliseconds (" << ((1.0 * presenceElapsed) / (1.0 * contactsToUpdate.size())) << " msec per updated contact )"; elapsedTimeTotal += presenceElapsed; // clean up the "more prefill data" qDebug() << " cleaning up extra prefill data, please wait..."; QList<ContactIdType> morePrefillIds; for (int j = 0; j < morePrefillData.size(); ++j) { morePrefillIds.append(retrievalId(morePrefillData.at(j))); } manager.removeContacts(morePrefillIds); // the fourth presence update test checks update time for non-overlapping sets of data. qDebug() << " generating non-overlapping / aggregated prefill data, please wait..."; morePrefillData.clear(); for (int i = 0; i < 1000; ++i) { morePrefillData.append(generateContact("test-presence-4", false)); // false = don't aggregate. } manager.saveContacts(&morePrefillData); // now do the update contactsToUpdate.clear(); timestamp = QDateTime::currentDateTime(); for (int j = 0; j < morePrefillData.size(); ++j) { QContact curr = morePrefillData.at(j); QString genstr = QString::number(j) + "4"; QContactPresence cp = curr.detail<QContactPresence>(); QContactNickname nn = curr.detail<QContactNickname>(); QContactAvatar av = curr.detail<QContactAvatar>(); cp.setNickname(genstr); cp.setCustomMessage(genstr); cp.setTimestamp(timestamp); cp.setPresenceState(static_cast<QContactPresence::PresenceState>((qrand() % 4) + 1)); nn.setNickname(nn.nickname() + genstr); av.setImageUrl(genstr + presenceAvatars.at(qrand() % presenceAvatars.size())); curr.saveDetail(&cp); curr.saveDetail(&nn); curr.saveDetail(&av); contactsToUpdate.append(curr); } // perform a batch save. syncTimer.start(); manager.saveContacts(&contactsToUpdate); presenceElapsed = syncTimer.elapsed(); totalAggregatesInDatabase = manager.contactIds().count(); qDebug() << " update ( batch of" << contactsToUpdate.size() << ") presence+nick+avatar (with" << totalAggregatesInDatabase << "existing in database, no overlap):" << presenceElapsed << "milliseconds (" << ((1.0 * presenceElapsed) / (1.0 * contactsToUpdate.size())) << " msec per updated contact )"; elapsedTimeTotal += presenceElapsed; // clean up the "more prefill data" qDebug() << " cleaning up extra prefill data, please wait..."; #ifdef USING_QTPIM morePrefillIds.clear(); for (int j = 0; j < morePrefillData.size(); ++j) { morePrefillIds.append(morePrefillData.at(j).id()); } #else morePrefillIds.clear(); for (int j = 0; j < morePrefillData.size(); ++j) { morePrefillIds.append(morePrefillData.at(j).localId()); } #endif manager.removeContacts(morePrefillIds); // the fifth presence update test is similar to the above except that half of // the extra contacts have a (high) chance of being aggregated into an existing contact. // So, database should have 2000 constituents, 1000 from "local", 1000 from "test-presence-5" // with 1500 aggregates (about 500 of test-presence-5 contacts will share an aggregate with // a local contact). TODO: check what happens if multiple aggregates for local contacts // could possibly match a given test-presence-5 contact (which is possible, since the backend // never aggregates two contacts from the same sync source...) qDebug() << " generating partially-overlapping / aggregated prefill data, please wait..."; morePrefillData.clear(); for (int i = 0; i < 1000; ++i) { if (i < 500) { morePrefillData.append(generateContact("test-presence-5", false)); // false = don't aggregate. } else { morePrefillData.append(generateContact("test-presence-5", true)); // true = possibly aggregate. } } manager.saveContacts(&morePrefillData); // now do the update contactsToUpdate.clear(); timestamp = QDateTime::currentDateTime(); for (int j = 0; j < morePrefillData.size(); ++j) { QContact curr = morePrefillData.at(j); QString genstr = QString::number(j) + "5"; QContactPresence cp = curr.detail<QContactPresence>(); QContactNickname nn = curr.detail<QContactNickname>(); QContactAvatar av = curr.detail<QContactAvatar>(); cp.setNickname(genstr); cp.setCustomMessage(genstr); cp.setTimestamp(timestamp); cp.setPresenceState(static_cast<QContactPresence::PresenceState>((qrand() % 4) + 1)); nn.setNickname(nn.nickname() + genstr); av.setImageUrl(genstr + presenceAvatars.at(qrand() % presenceAvatars.size())); curr.saveDetail(&cp); curr.saveDetail(&nn); curr.saveDetail(&av); contactsToUpdate.append(curr); } // perform a batch save. syncTimer.start(); manager.saveContacts(&contactsToUpdate); presenceElapsed = syncTimer.elapsed(); totalAggregatesInDatabase = manager.contactIds().count(); qDebug() << " update ( batch of" << contactsToUpdate.size() << ") presence+nick+avatar (with" << totalAggregatesInDatabase << "existing in database, 500 overlap):" << presenceElapsed << "milliseconds (" << ((1.0 * presenceElapsed) / (1.0 * contactsToUpdate.size())) << " msec per updated contact )"; elapsedTimeTotal += presenceElapsed; // the sixth presence update test is identical to the fifth test, except that we ONLY // update the presence status (not nickname or avatar). morePrefillData = contactsToUpdate; contactsToUpdate.clear(); for (int j = 0; j < morePrefillData.size(); ++j) { QContact curr = morePrefillData.at(j); QContactPresence cp = curr.detail<QContactPresence>(); cp.setPresenceState(static_cast<QContactPresence::PresenceState>((qrand() % 4) + 1)); curr.saveDetail(&cp); contactsToUpdate.append(curr); } // perform a batch save. syncTimer.start(); manager.saveContacts(&contactsToUpdate); presenceElapsed = syncTimer.elapsed(); totalAggregatesInDatabase = manager.contactIds().count(); qDebug() << " update ( batch of" << contactsToUpdate.size() << ") presence only (with" << totalAggregatesInDatabase << "existing in database, 500 overlap):" << presenceElapsed << "milliseconds (" << ((1.0 * presenceElapsed) / (1.0 * contactsToUpdate.size())) << " msec per updated contact )"; elapsedTimeTotal += presenceElapsed; // the seventh presence update test is identical to the 6th test, except that // we also pass a "detail type mask" to the update. This allows the backend // to perform optimisation based upon which details are modified. morePrefillData = contactsToUpdate; contactsToUpdate.clear(); for (int j = 0; j < morePrefillData.size(); ++j) { QContact curr = morePrefillData.at(j); QContactPresence cp = curr.detail<QContactPresence>(); cp.setPresenceState(static_cast<QContactPresence::PresenceState>((qrand() % 4) + 1)); curr.saveDetail(&cp); contactsToUpdate.append(curr); } // perform a batch save. #ifdef USING_QTPIM QList<QContactDetail::DetailType> typeMask; typeMask << QContactDetail::TypePresence; #else QStringList typeMask; typeMask << QString(QLatin1String(QContactPresence::DefinitionName)); #endif syncTimer.start(); manager.saveContacts(&contactsToUpdate, typeMask); presenceElapsed = syncTimer.elapsed(); totalAggregatesInDatabase = manager.contactIds().count(); qDebug() << " update ( batch of" << contactsToUpdate.size() << ") masked presence only (with" << totalAggregatesInDatabase << "existing in database, 500 overlap):" << presenceElapsed << "milliseconds (" << ((1.0 * presenceElapsed) / (1.0 * contactsToUpdate.size())) << " msec per updated contact )"; elapsedTimeTotal += presenceElapsed; // clean up the "more prefill data" qDebug() << " cleaning up extra prefill data, please wait..."; #ifdef USING_QTPIM morePrefillIds.clear(); for (int j = 0; j < morePrefillData.size(); ++j) { morePrefillIds.append(morePrefillData.at(j).id()); } #else morePrefillIds.clear(); for (int j = 0; j < morePrefillData.size(); ++j) { morePrefillIds.append(morePrefillData.at(j).localId()); } #endif manager.removeContacts(morePrefillIds); qDebug() << "\n\nCumulative elapsed time:" << elapsedTimeTotal << "milliseconds"; return 0; }
QContact generateContact(const QString &syncTarget = QString(QLatin1String("local")), bool possiblyAggregate = false) { static const QStringList firstNames(generateFirstNamesList()); static const QStringList middleNames(generateMiddleNamesList()); static const QStringList lastNames(generateLastNamesList()); static const QStringList nonOverlappingFirstNames(generateNonOverlappingFirstNamesList()); static const QStringList nonOverlappingLastNames(generateNonOverlappingLastNamesList()); static const QStringList phoneNumbers(generatePhoneNumbersList()); static const QStringList emailProviders(generateEmailProvidersList()); static const QStringList avatars(generateAvatarsList()); static const QStringList hobbies(generateHobbiesList()); // we randomly determine whether to generate various details // to ensure that we have heterogeneous contacts in the db. QContact retn; int random = qrand(); bool preventAggregate = (syncTarget != QLatin1String("local") && !possiblyAggregate); // We always have a sync target. QContactSyncTarget synctarget; synctarget.setSyncTarget(syncTarget); retn.saveDetail(&synctarget); // We always have a name. Select an overlapping name if the sync target // is something other than "local" and possiblyAggregate is true. QContactName name; name.setFirstName(preventAggregate ? nonOverlappingFirstNames.at(random % nonOverlappingFirstNames.size()) : firstNames.at(random % firstNames.size())); name.setLastName(preventAggregate ? nonOverlappingLastNames.at(random % nonOverlappingLastNames.size()) : lastNames.at(random % lastNames.size())); if ((random % 6) == 0) name.setMiddleName(middleNames.at(random % middleNames.size())); if ((random % 17) == 0) name.setPrefix(QLatin1String("Dr.")); retn.saveDetail(&name); // Favorite if ((random % 31) == 0) { QContactFavorite fav; fav.setFavorite(true); retn.saveDetail(&fav); } // Phone number if ((random % 3) == 0) { QContactPhoneNumber phn; QString randomPhn = phoneNumbers.at(random % phoneNumbers.size()); phn.setNumber(preventAggregate ? QString(QString::number(random % 500000) + randomPhn) : randomPhn); if ((random % 9) == 0) phn.setContexts(QContactDetail::ContextWork); retn.saveDetail(&phn); } // Email if ((random % 2) == 0) { QContactEmailAddress em; em.setEmailAddress(QString(QLatin1String("%1%2%3%4")) .arg(preventAggregate ? QString(QString::number(random % 500000) + syncTarget) : QString()) .arg(name.firstName()).arg(name.lastName()) .arg(emailProviders.at(random % emailProviders.size()))); if (random % 9) em.setContexts(QContactDetail::ContextWork); retn.saveDetail(&em); } // Avatar if ((random % 5) == 0) { QContactAvatar av; av.setImageUrl(name.firstName() + avatars.at(random % avatars.size())); retn.saveDetail(&av); } // Hobby if ((random % 21) == 0) { QContactHobby h1; h1.setHobby(hobbies.at(random % hobbies.size())); retn.saveDetail(&h1); int newRandom = qrand(); if ((newRandom % 2) == 0) { QContactHobby h2; h2.setHobby(hobbies.at(newRandom % hobbies.size())); retn.saveDetail(&h2); } } return retn; }
void SeasideCache::reset() { for (int i = 0; i < FilterTypesCount; ++i) { m_contacts[i].clear(); m_populated[i] = false; m_models[i] = 0; } m_cache.clear(); m_cacheIndices.clear(); for (uint i = 0; i < sizeof(contactsData) / sizeof(Contact); ++i) { QContact contact; // This is specific to the qtcontacts-sqlite backend: const QString idStr(QString::fromLatin1("qtcontacts:org.nemomobile.contacts.sqlite::sql-%1")); contact.setId(QContactId::fromString(idStr.arg(i + 1))); QContactName name; name.setFirstName(QString::fromLatin1(contactsData[i].firstName)); name.setMiddleName(QString::fromUtf8(contactsData[i].middleName)); name.setLastName(QString::fromLatin1(contactsData[i].lastName)); contact.saveDetail(&name); if (contactsData[i].avatar) { QContactAvatar avatar; avatar.setImageUrl(QUrl(QLatin1String(contactsData[i].avatar))); contact.saveDetail(&avatar); } QContactStatusFlags statusFlags; if (contactsData[i].email) { QContactEmailAddress email; email.setEmailAddress(QLatin1String(contactsData[i].email)); contact.saveDetail(&email); statusFlags.setFlag(QContactStatusFlags::HasEmailAddress, true); } if (contactsData[i].phoneNumber) { QContactPhoneNumber phoneNumber; phoneNumber.setNumber(QLatin1String(contactsData[i].phoneNumber)); contact.saveDetail(&phoneNumber); statusFlags.setFlag(QContactStatusFlags::HasPhoneNumber, true); } contact.saveDetail(&statusFlags); m_cacheIndices.insert(internalId(contact), m_cache.count()); m_cache.append(CacheItem(contact)); QString fullName = name.firstName() + QChar::fromLatin1(' ') + name.lastName(); CacheItem &cacheItem = m_cache.last(); cacheItem.nameGroup = determineNameGroup(&cacheItem); cacheItem.displayLabel = fullName; } insert(FilterAll, 0, getContactsForFilterType(FilterAll)); insert(FilterFavorites, 0, getContactsForFilterType(FilterFavorites)); insert(FilterOnline, 0, getContactsForFilterType(FilterOnline)); }
void SeasidePhotoHandler::propertyProcessed(const QVersitDocument &, const QVersitProperty &property, const QContact &, bool *alreadyProcessed, QList<QContactDetail> * updatedDetails) { // if the property is a PHOTO property, store the data to disk // and then create an avatar detail which points to it. if (property.name().toLower() != QLatin1String("photo")) return; #ifndef QT_VERSION_5 // The Qt4 / QtMobility version has QContactThumbnail support. // We need to remove any such thumbnail detail from the output, // as some backends (such as qtcontacts-sqlite) do not support // that detail type. for (int i = 0; i < updatedDetails->size(); ++i) { if (updatedDetails->at(i).definitionName() == QContactThumbnail::DefinitionName) { updatedDetails->removeAt(i); --i; } } #endif // The data might be either a URL, a file path, or encoded image data // It's hard to tell what the content is, because versit removes the encoding // information in the process of decoding the data... // Try to interpret the data as a URL QString path(property.variantValue().toString()); QUrl url(path); if (url.isValid()) { // Treat remote URL as a true URL, and reference it in the avatar if (!url.scheme().isEmpty() && !url.isLocalFile()) { QContactAvatar newAvatar; newAvatar.setImageUrl(url); updatedDetails->append(newAvatar); // we have successfully processed this PHOTO property. *alreadyProcessed = true; return; } } if (!url.isValid()) { // See if we can resolve the data as a local file path url = QUrl::fromLocalFile(path); } QByteArray photoData; if (url.isValid()) { // Try to read the data from the referenced file const QString filePath(url.path()); if (QFile::exists(filePath)) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { qWarning() << "Unable to process photo data as file:" << path; return; } else { photoData = file.readAll(); } } } if (photoData.isEmpty()) { // Try to interpret the encoded property data as the image photoData = property.variantValue().toByteArray(); if (photoData.isEmpty()) { qWarning() << "Failed to extract avatar data from vCard PHOTO property"; return; } } QImage img; bool loaded = img.loadFromData(photoData); if (!loaded) { qWarning() << "Failed to load avatar image from vCard PHOTO data"; return; } // We will save the avatar image to disk in the system's data location // Since we're importing user data, it should not require privileged access const QString subdirectory(QString::fromLatin1(".local/share/system/Contacts/avatars")); const QString photoDirPath(QDir::home().filePath(subdirectory)); // create the photo file dir if it doesn't exist. QDir photoDir; if (!photoDir.mkpath(photoDirPath)) { qWarning() << "Failed to create avatar image directory when loading avatar image from vCard PHOTO data"; return; } // construct the filename of the new avatar image. QString photoFilePath = QString::fromLatin1(QCryptographicHash::hash(photoData, QCryptographicHash::Md5).toHex()); photoFilePath = photoDirPath + QDir::separator() + photoFilePath + QString::fromLatin1(".jpg"); // save the file to disk bool saved = img.save(photoFilePath); if (!saved) { qWarning() << "Failed to save avatar image from vCard PHOTO data to" << photoFilePath; return; } qWarning() << "Successfully saved avatar image from vCard PHOTO data to" << photoFilePath; // save the avatar detail - TODO: mark the avatar as "owned by the contact" (remove on delete) QContactAvatar newAvatar; newAvatar.setImageUrl(QUrl::fromLocalFile(photoFilePath)); updatedDetails->append(newAvatar); // we have successfully processed this PHOTO property. *alreadyProcessed = true; }
/** * Method to get the result for a network request. * @param aOperation The type of operation to be requested * @param aTransportResult The result of transport operation * @param aResponse The QByteArray instance containing the network response. * The plugins should delete this instance once they have read the * data from it. * @param aResult [out] An output parameter to the plugin manager.If the * return value is SmfSendRequestAgain, QVariant will be of type * SmfPluginRequestData. * For SmfGalleryPlugin: If last operation was pictures(), aResult will * be of type QList<SmfPicture>. If last operation was description(), * aResult will be of type QString. If last operation was upload() or * postComment(), aResult will be of type bool. * @param aRetType [out] SmfPluginRetType * @param aPageResult [out] The SmfResultPage structure variable */ SmfPluginError FlickrContactFetcherPlugin::responseAvailable( const SmfRequestTypeID aOperation, const SmfTransportResult &aTransportResult, QByteArray *aResponse, QVariant* aResult, SmfPluginRetType &aRetType, SmfResultPage &aPageResult ) { Q_UNUSED(aPageResult) qDebug()<<"Inside FlickrContactFetcherPlugin::responseAvailable()"; SmfPluginError error = SmfPluginErrNetworkError; if( !aResponse || (0 == aResponse->size()) ) { qDebug()<<"Response is NULL or empty"; aRetType = SmfRequestError; return error; } QByteArray response(*aResponse); delete aResponse; QFile respFile("c://data//SmfPluginFlickrContactResponse.txt"); if(!respFile.open(QIODevice::WriteOnly)) { qDebug()<<"File to write the response could not be opened, so writing to this file"; qDebug()<<"Flickr response = "<<QString(response); } else { respFile.write(response); respFile.close(); qDebug()<<"Writing FB response to a file named 'SmfPluginFlickrContactResponse.txt'"; } qDebug()<<"FB response size = "<<response.size(); if(SmfTransportOpNoError == aTransportResult) { qDebug()<<"No transport error"; #ifndef TESTINGTHISFUNCTION if(SmfContactGetFriends == aOperation) #else if(SmfContactGetFriends == aOperation ||aOperation == SmfContactGetFollowers||aOperation== SmfContactSearch ||aOperation ==SmfContactSearchNear||aOperation ==SmfContactSearchInGroup) #endif { qDebug()<<"For getting friends response"; QList<SmfContact> list; #ifdef SMF_XMLPARSING // Xml parsing // For getting contacts from xml response QXmlStreamReader xml(response); while (!xml.atEnd()) { xml.readNext(); if (xml.tokenType() == QXmlStreamReader::StartElement) { // If the tag is contact if (xml.name() == "contact") { qDebug()<<"Contact tag found"; SmfContact contact; QStringRef str; QContactName contactname; QString username = xml.attributes().value("username").toString(); qDebug()<<"Username = "******"Name",namevar1); list.append(contact); } } } #else // To remove the "jsonFlickrApi(" and also remove the last ")" from the response, // as these gives a Json parsing error response.remove(0, 14); response.chop(1); // For getting contacts from json response bool ok; SmfPluginUtil util; QVariantMap result = util.parse(response, &ok).toMap(); if (!ok) { qDebug()<<"An error occurred during json parsing"; aResult->setValue(list); aRetType = SmfRequestError; return SmfPluginErrParsingFailed; } QVariantMap map1 = result["contacts"].toMap(); qDebug()<<"page = "<<map1["page"].toString(); qDebug()<<"pages = "<<map1["pages"].toString(); qDebug()<<"per_page = "<<map1["per_page"].toString(); qDebug()<<"perpage = "<<map1["perpage"].toString(); qDebug()<<"total = "<<map1["perpage"].toString(); QList<QVariant> list1 = map1["contact"].toList(); QListIterator<QVariant> i(list1); while(i.hasNext()) { SmfContact contact; QVariantMap map2 = i.next().toMap(); qDebug()<<"nsid = "<<map2["nsid"].toString(); qDebug()<<"username = "******"username"].toString(); qDebug()<<"iconserver = "<<map2["iconserver"].toString(); qDebug()<<"iconfarm = "<<map2["iconfarm"].toString(); qDebug()<<"ignored = "<<map2["ignored"].toString(); qDebug()<<"realname = "<<map2["realname"].toString(); qDebug()<<"friend = "<<map2["friend"].toString(); qDebug()<<"family = "<<map2["family"].toString(); qDebug()<<"path_alias = "<<map2["path_alias"].toString(); qDebug()<<"location = "<<map2["location"].toString(); // Contact Name QContactName contactname; QString username = map2["username"].toString(); qDebug()<<"Username = "******"Name",nameVar); // Contact's Flickr Specific ID to QContactGuid QContactGuid guid; guid.setGuid(map2["nsid"].toString()); QVariant guidVar = QVariant::fromValue(guid); contact.setValue("Guid",guidVar); // Contact's profile image url QUrl url; if((0 == map2["iconfarm"].toInt()) && (0 == map2["iconserver"].toInt())) url = QString("http://www.flickr.com/images/buddyicon.jpg"); else { QString str("http://farm"); str.append(map2["iconfarm"].toString()); str.append(".static.flickr.com/"); str.append(map2["iconserver"].toString()); str.append("/buddyicons/"); str.append(map2["nsid"].toString()); str.append(".jpg"); url = str; } QContactAvatar avatar; qDebug()<<"Profile image URL = "<<url.toString(); avatar.setImageUrl(url); QVariant avatarVar = QVariant::fromValue(avatar); contact.setValue("Avatar",avatarVar); list.append(contact); } #endif qDebug()<<"list count = "<<list.count(); aResult->setValue(list); aRetType = SmfRequestComplete; error = SmfPluginErrNone; } else if(aOperation==SmfContactGetGroups) { response.remove(0, 14); response.chop(1); bool ok; qDebug()<<"Before Parser--"; SmfPluginUtil util; QVariant result = util.parse(response, &ok); if (!ok) { qDebug()<<"An error occurred during json parsing"; aRetType = SmfRequestError; return SmfPluginErrParsingFailed; //return 0; } QVariantMap map1 = result.toMap(); QList<SmfGroup> list; QVariantMap map2 = map1["groups"].toMap(); int page = map2["page"].toInt(&ok); qDebug()<<"PAGE = "<<map2["page"].toString(); QList<QVariant> list1 = map2["group"].toList(); QListIterator<QVariant> iter(list1); //Getting the group list from QJson Parser while(iter.hasNext()) { QVariantMap map2 = iter.next().toMap(); qDebug()<<"name = "<<map2["name"].toString(); qDebug()<<"id = "<<map2["id"].toString(); SmfGroup group; QString id(map2["id"].toString()); group.setId(id); QString grpname(map2["name"].toString()); group.setName(grpname); list.append(group); }//end While qDebug()<<"list count = "<<QString::number(list.count(),10); aResult->setValue(list); } else { qDebug()<<"Service unsupported, currently only SmfContactGetFriends !!!"; aRetType = SmfRequestError; error = SmfPluginErrServiceNotSupported; } } else if(SmfTransportOpOperationCanceledError == aTransportResult) { qDebug()<<"Operation Cancelled !!!"; error = SmfPluginErrCancelComplete; aRetType = SmfRequestComplete; } else { qDebug()<<"Transport Error !!!"; error = SmfPluginErrNetworkError; aRetType = SmfRequestError; } return error; }