QContact does not return the correct thumbnail On N950?
-
Hi everybody,
I am trying to get the contact thumbnail from a QContact on N950 but.
I couldn't get it. i used the following code
@QContactThumbnail thumb = contact.detail(QContactThumbnail::DefinitionName);
QImage thumbnail = thumb.thumbnail();@but the image always null
can any body help, please?
-
Hi,
It's possible that the backend hasn't synthesized a thumbnail for that contact's avatar. Does the QContactAvatar detail contain any data? Is the QContactThumbnail which is returned a null/default-constructed QContactThumbnail, or does it have some fields filled?
Cheers,
Chris. -
I used the QContactAvatar and it was working perfectly.
I got another problem when i change the avatar, and check if it is changed or not, i find it not changed.
but when i restart my application i find it changed. -
Hrm, now that one is a trickier problem. On the n950 the backend used is the qtcontacts-tracker backend (ie, all data is pushed to the global Tracker RDF datastore), and it may very well be that the backend does some "change batching" (ie, when you write a value, it may not write the value until it has a series of changes to write to the datastore, for performance reasons -- especially if the write is inherently asynchronous (e.g., over dbus) or otherwise prohibitively expensive).
Do you receive the contactsChanged() or dataChanged() signal from the manager after the write operation returns? Are you using the synchronous or asynchronous API? To be honest, this sounds like a bug in the qtcontacts-tracker backend, so please do file a bug-report; but as a temporary workaround, please make sure that you use the asynchronous request classes to access/mutate contact data on the n950, and check that the change has been made to the datastore when the finished() signal is emitted by the request.
Cheers,
Chris. -
Hi chriadam,
I started to use the asynchronous method to get the contact instead of using QContactFetchRequest
I note that the contactsChanged signal is emitted, but it has been emitted after the image provider requests the image(avatar).
So i will try to rerquest the image after the signal is emitted.
here are a log databq. QImage ContactsImageProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize)
contact id= 100618
if(!contact.isEmpty())
if(!imageUrl.isEmpty())
image path = "/home/developer/.cache/contacts/photos/da39a3ee5e6b4b0d3255bfef95601890afd80709.png"
void ContactManager::onContactsChanged(const QList<QContactLocalId> contacts)Thank you
-
I tried to get the image after the contact is changed.
I found that the QContactAvatar contains a URL but when i create an image from that url i always
get a null image.the image path was "/home/developer/.cache/contacts/photos/8642ee1bd0fa99f9300ae9d40ef7e103e1a96166.png"
-
Hmm, that's very strange behaviour.
By the way, by "asynchronous API" I did mean the QContactFetchRequest (and QContactSaveRequest etc) classes - if you were using those already, that's good.
But this problem that you're seeing is beyond my knowledge. I've forwarded the question on to the relevant developers, but IMO you should file a bug at bugreports.qt.nokia.com so that the issue can be tracked and resolved properly.
Cheers,
Chris. -
Hello mismael,
qtcontacts-tracker does not fill the QContactThumbnail detail, although it supports saving it (it will, as you described, write it to a file). For loading avatars, please use QContactAvatar. “/home/developer/.cache/contacts/photos/8642ee1bd0fa99f9300ae9d40ef7e103e1a96166.png” is a quite suspicious path, since it should be "/home/user". Make sure your apps always run as user "user", qtcontacts-tracker does not care, but if you run the app alternatively as user & developer, you'll end up with files scattered in many directories. I'm pretty sure avatar saving works, since the contacts application is using it :)
Should you have more questions about qtcontacts-tracker, feel free to drop by on IRC, freenode/#qtcontacts-tracker.Cheers
Adrien
-
Hi abustany,
I tried to run the application as a user bu the problem still exist.
the application successfully saves the image but it can not get it again until i turn the application off and open it again.
here is the source code that i use to save the image
@int ContactManager::saveContactImage(const int contactId, const QImage & image)
{
if(!image.isNull())
{
QContact myContact = contact(contactId);
QContactThumbnail thumb = createThumbnail(myContact, image);
myContact.saveDetail(&thumb);
m_contactSaveRequest.setManager(this);
m_contactSaveRequest.setContact(myContact);
m_contactSaveRequest.start();#if defined (LOG_FEATURE)
qDebug()<< error();
#endif
}
return 0;
}void ContactManager::onContactSaveResultAvailable()
{
#ifdef LOG_FEATURE
qDebug()<<"void ContactManager::onContactSaveResultAvailable()";
qDebug()<<"error code ="<< m_contactSaveRequest.error();
#endif
if(m_contactSaveRequest.error() == QContactManager::NoError){
qDebug()<<"Contact saved";
emit avatarChanged(m_contactSaveRequest.contacts().at(0).localId());
}
}@and here is image provider that i use to get the avatar
@#ifdef LOG_FEATURE
qDebug()<<"QImage ContactsImageProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize)";
#endif
QString index = id;
index.remove("+");const QContact contact = m_contactManager->getContact(index.toInt());
#ifdef LOG_FEATURE
qDebug()<<"contact id= "<< contact.id().localId();
#endif
if(!contact.isEmpty())
{
#ifdef LOG_FEATURE
qDebug()<<"if(!contact.isEmpty())";
#endif
QContactAvatar avatar = contact.detail<QContactAvatar>();
QUrl imageUrl = avatar.imageUrl();
if(!imageUrl.isEmpty()){
#ifdef LOG_FEATURE
qDebug()<<"if(!imageUrl.isEmpty())";
qDebug()<<"image path ="<< imageUrl.path();
#endif
QImage image(imageUrl.path());
if(!image.isNull())
{
#ifdef LOG_FEATURE
qDebug()<<"if(!image.isNull())";
#endif
return image;
}
}
else{
#ifdef LOG_FEATURE
qDebug()<<"else";
#endif
QContactThumbnail thumb = contact.detail(QContactThumbnail::DefinitionName);
QImage thumbnail = thumb.thumbnail();
if(!thumbnail.isNull())
{
#ifdef LOG_FEATURE
qDebug()<<"if(!thumbnail.isNull())";
#endif
return thumbnail.scaled(QSize(75, 75), Qt::KeepAspectRatio, Qt::FastTransformation);
}
}
}
#ifdef Q_OS_SYMBIAN
return QImage(QLatin1String("qml/contactface/gfx/red/person.png"));
#else
return QImage(QLatin1String("/opt/FaceOff/qml/contactface/gfx/red/person.png"));
#endif
@and here the log messages that i got:
bq. void ContactManager::saveContactImage(const int contactId, QString path)
libqtcontacts-tracker: engine.cpp:784:WARNING /!\ - AVOID CALLING THIS FUNCTION FROM PRODUCTION CODE!!!
QContactManager::contact() is blocking on D-Bus roundtrip while accessing
tracker. Please consider using batch API (QContactManager::contacts()),
or even better use the asynchronous QContactFetchRequest API, instead of
fetching contacts one by one.
Please note that reading 100 ids and 100 contact by ids is ~100 times
slower than reading 100 contacts at once with QContactFetchRequest.
Offending application is /opt/FaceOff/bin/FaceOff [31598].0
QImage ContactsImageProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize)
contact id= 100618
if(!contact.isEmpty())
if(!imageUrl.isEmpty())
image path = "/home/user/.cache/contacts/photos/da39a3ee5e6b4b0d3255bfef95601890afd80709.png"
void ContactManager::onContactSaveResultAvailable()
error code = 0
Contact saved
QImage ContactsImageProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize)
contact id= 100618
if(!contact.isEmpty())
if(!imageUrl.isEmpty())
image path = "/home/user/.cache/contacts/photos/da39a3ee5e6b4b0d3255bfef95601890afd80709.png"
void ContactManager::onContactsChanged(const QList<QContactLocalId> contacts)thank you very much
-
Hi,
A few remarks:
- As the warning says, you probably want to avoid calling a sync API (contact()) in a GUI app (unless it's in a separate thread).
- You can use Q_FUNC_INFO to get the function name & proto, instead of doing things like qDebug()<<"QImage ContactsImageProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize)";
- Reading your debug log, I can read "image path = .....", so it seems you get the correct path, and the QImage is loaded correctly. Note that every time you save a contact, you have to reload it to get all the changes. But if you just change the avatar, reloading it should not be needed since the updated QContactDetail is already present in the QContact.
-
Hi abustany,
Thank you very much for the remarks.
but the image is not loaded correctly.
the image always null as you can see in the source code.
here is an enhanced version of the code.
// contactsImageProvider.cpp
@#ifdef LOG_FEATURE
qDebug()<<Q_FUNC_INFO;
#endif
QString index = id;
index.remove("+");const QContact * contact = m_contactManager->getContact(index.toInt());
#ifdef LOG_FEATURE
qDebug()<<"contact id= "<< contact->id().localId();
#endif
if(!contact->isEmpty())
{
#ifdef LOG_FEATURE
qDebug()<<"if(!contact.isEmpty())";
#endif
QContactAvatar avatar = contact->detail<QContactAvatar>();
QUrl imageUrl = avatar.imageUrl();
if(!imageUrl.isEmpty()){
#ifdef LOG_FEATURE
qDebug()<<"if(!imageUrl.isEmpty())";
qDebug()<<"image path ="<< imageUrl.path();
#endif
QImage image(imageUrl.path());
if(!image.isNull())
{
#ifdef LOG_FEATURE
qDebug()<<"if(!image.isNull())";
#endif
return image;
}
}
else{
#ifdef LOG_FEATURE
qDebug()<<"else";
#endif
QContactThumbnail thumb = contact->detail(QContactThumbnail::DefinitionName);
QImage thumbnail = thumb.thumbnail();
if(!thumbnail.isNull())
{
#ifdef LOG_FEATURE
qDebug()<<"if(!thumbnail.isNull())";
#endif
return thumbnail.scaled(QSize(75, 75), Qt::KeepAspectRatio, Qt::FastTransformation);
}
}
}
#ifdef Q_OS_SYMBIAN
return QImage(QLatin1String("qml/contactface/gfx/red/person.png"));
#else
return QImage(QLatin1String("/opt/FaceOff/qml/contactface/gfx/red/person.png"));
#endif@
//contactManager.cpp
@int ContactManager::saveContactImage(const int contactId, const QImage & image)
{
#ifdef LOG_FEATURE
qDebug()<< Q_FUNC_INFO;
#endif
if(!image.isNull())
{
QContact * myContact = getContact(contactId);
QContactThumbnail thumb = createThumbnail(*myContact, image);
myContact->saveDetail(&thumb);
m_contactSaveRequest.setManager(this);
m_contactSaveRequest.setContact(*myContact);
m_contactSaveRequest.start();#if defined (LOG_FEATURE)
qDebug()<< error();
#endif
}
return 0;
}
QContact * ContactManager::getContact(const int index)
{
if(index >= 0 && index < m_contacts.count())
{
return &m_contacts[index];
}
}@
and here are the log messages.
bq. int ContactManager::saveContactImage(int, const QImage&)
0
void ContactManager::onContactSaveResultAvailable()
error code = 0
Contact saved
virtual QImage ContactsImageProvider::requestImage(const QString&, QSize*, const QSize&)
contact id= 100618
if(!contact.isEmpty())
if(!imageUrl.isEmpty())
image path = "/home/user/.cache/contacts/photos/da39a3ee5e6b4b0d3255bfef95601890afd80709.png"
void ContactManager::onContactsChanged(const QList<QContactLocalId> contacts)if the process was successful I should get the following line
qDebug()<<"if(!image.isNull())";after the line
if(!imageUrl.isEmpty())but this is not the case.
-
ok my bad I had misread the log. Did you check that the image pointed by the url exists, and is a "real" image?
Note: returning a pointer to a QContact object from your methods makes little sense. QContact is implicitly shared, so copying it around is cheap. If you want to be able to modify the returned contact, maybe return a reference, but a pointer should never be needed.