source: psi/trunk/src/avatars.cpp@ 86

Last change on this file since 86 was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 9.9 KB
Line 
1#include <qpixmap.h>
2#include <qbuffer.h>
3#include <qcstring.h>
4#include <qdatetime.h>
5#include <qsize.h>
6#include <qfile.h>
7
8#include "xmpp.h"
9#include "avatars.h"
10#include "common.h"
11#include "iconset.h"
12#include "psiaccount.h"
13#include "profiles.h"
14#include "vcardfactory.h"
15
16#define MAX_AVATAR_SIZE 64
17
18//------------------------------------------------------------------------------
19
20//------------------------------------------------------------------------------
21// Avatar: Base class for avatars.
22//------------------------------------------------------------------------------
23
24Avatar::Avatar()
25{
26}
27
28
29Avatar::~Avatar()
30{
31}
32
33int Avatar::maxSize()
34{
35 return (option.avatarsSize > MAX_AVATAR_SIZE ? MAX_AVATAR_SIZE : option.avatarsSize);
36}
37
38void Avatar::setImage(const QImage& i)
39{
40
41 if (i.width() > maxSize() || i.height() > option.avatarsSize)
42 pixmap_.convertFromImage(i.smoothScale(maxSize(),maxSize(),QImage::ScaleMin));
43 else
44 pixmap_.convertFromImage(i);
45}
46
47void Avatar::setImage(const QByteArray& ba)
48{
49 setImage(QImage(ba));
50}
51
52void Avatar::setImage(const QPixmap& p)
53{
54 if (p.width() > maxSize() || p.height() > maxSize())
55 setImage(p.convertToImage());
56 else
57 pixmap_ = p;
58}
59
60void Avatar::resetImage()
61{
62 pixmap_ = QPixmap();
63}
64
65
66//------------------------------------------------------------------------------
67
68//------------------------------------------------------------------------------
69// VCardAvatar: Avatars coming from VCards of contacts.
70//------------------------------------------------------------------------------
71
72class VCardAvatar : public QObject, public Avatar
73{
74 Q_OBJECT
75
76public:
77 VCardAvatar(AvatarFactory* factory, const Jid& jid);
78 QPixmap getPixmap();
79
80signals:
81 void avatarChanged(const Jid&);
82
83private:
84 Jid jid_;
85 AvatarFactory* factory_;
86 const VCard* lastVCard_; // Never dereference this, might point to dead object
87};
88
89
90VCardAvatar::VCardAvatar(AvatarFactory* factory, const Jid& jid) :
91 jid_(jid), factory_(factory)
92{
93 const VCard* vcard = VCardFactory::vcard(jid_);
94 if (vcard && vcard->photo()) {
95 setImage(vcard->photo());
96 }
97 lastVCard_ = vcard;
98}
99
100
101QPixmap VCardAvatar::getPixmap()
102{
103 // Try to find an avatar if the current one is empty
104 // FIXME: The pixmap shouldn't be updated by active polling, but by
105 // some signal from the VCard factory when the vcard is updated.
106 const VCard* vcard = VCardFactory::vcard(jid_);
107 if (lastVCard_ != vcard) {
108 if (vcard && vcard->photo()) {
109 setImage(vcard->photo());
110 }
111 else
112 resetImage();
113 lastVCard_ = vcard;
114 emit avatarChanged(jid_);
115 }
116
117 return pixmap();
118}
119
120
121//------------------------------------------------------------------------------
122
123//------------------------------------------------------------------------------
124// FileAvatar: Avatars coming from local files.
125//------------------------------------------------------------------------------
126
127class FileAvatar : public Avatar
128{
129public:
130 FileAvatar(const Jid& jid);
131 void import(const QString& file);
132 void removeFromDisk();
133 bool exists();
134 QPixmap getPixmap();
135 const Jid& getJid() const
136 { return jid_; }
137
138protected:
139 bool isDirty() const;
140 QString getFileName() const;
141 void refresh();
142 QDateTime lastModified() const
143 { return lastModified_; }
144
145private:
146 QDateTime lastModified_;
147 Jid jid_;
148};
149
150
151FileAvatar::FileAvatar(const Jid& jid) : jid_(jid)
152{
153}
154
155void FileAvatar::import(const QString& file)
156{
157 if (QFileInfo(file).exists()) {
158 // Check if the manual dir exists
159 if (!QDir(AvatarFactory::getAvatarsDir()).exists())
160 QDir("").mkdir(AvatarFactory::getAvatarsDir());
161 if (!QDir(AvatarFactory::getManualDir()).exists())
162 QDir("").mkdir(AvatarFactory::getManualDir());
163
164 QFile source_file(file);
165 QFile target_file(getFileName());
166 if (source_file.open(IO_ReadOnly) && target_file.open(IO_WriteOnly)) {
167 // Copy all the data
168 char data[4096];
169 while (!source_file.atEnd()) {
170 Q_LONG read = source_file.readBlock(data,4096);
171 target_file.writeBlock(data,read);
172 }
173 }
174 }
175}
176
177void FileAvatar::removeFromDisk()
178{
179 QFile f(getFileName());
180 f.remove();
181}
182
183bool FileAvatar::exists()
184{
185 return QFileInfo(getFileName()).exists();
186}
187
188QPixmap FileAvatar::getPixmap()
189{
190 refresh();
191 return pixmap();
192}
193
194void FileAvatar::refresh()
195{
196 if (isDirty()) {
197 if (QFileInfo(getFileName()).exists()) {
198 QImage img(getFileName());
199 setImage(QImage(getFileName()));
200 }
201 else
202 resetImage();
203 }
204}
205
206
207QString FileAvatar::getFileName() const
208{
209 QString f = getJid().bare();
210 f.replace('@',"_at_");
211 return QDir(AvatarFactory::getManualDir()).filePath(f);
212}
213
214
215bool FileAvatar::isDirty() const
216{
217 return (pixmap().isNull()
218 || !QFileInfo(getFileName()).exists()
219 || QFileInfo(getFileName()).lastModified() > lastModified());
220}
221
222
223//------------------------------------------------------------------------------
224
225//------------------------------------------------------------------------------
226// ClientAvatar: Avatar representing the logo of a specific client.
227//------------------------------------------------------------------------------
228
229class ClientAvatar : public Avatar
230{
231public:
232 ClientAvatar(const QString& name);
233
234protected:
235 static ClientAvatar getClientAvatar(const QString& client);
236 static QMap<QString,ClientAvatar*> client_avatars;
237};
238
239
240ClientAvatar::ClientAvatar(const QString& name)
241{
242 //printf("%s\n",name.latin1());
243 QPixmap p;
244 if (name == "Psi")
245 p = IconsetFactory::icon("psi/psiMac").pixmap();
246 else if (name == "gaim")
247 p = IconsetFactory::icon("client/gaim").pixmap();
248 else if (name == "Gabber")
249 p = IconsetFactory::icon("client/gabber").pixmap();
250 else if (name == "Gossip")
251 p = IconsetFactory::icon("client/gossip").pixmap();
252 else if (name == "Exodus")
253 p = IconsetFactory::icon("client/exodus").pixmap();
254 else if (name == "Pandion")
255 p = IconsetFactory::icon("client/pandion").pixmap();
256 else if (name == "Nitro")
257 p = IconsetFactory::icon("client/nitro").pixmap();
258 else if (name == "Kopete")
259 p = IconsetFactory::icon("client/kopete").pixmap();
260 else if (name == "Tkabber")
261 p = IconsetFactory::icon("client/tkabber").pixmap();
262 else if (name == "MSN Transport")
263 p = IconsetFactory::icon("client/msn").pixmap();
264 else if (name == "AIM Transport")
265 p = IconsetFactory::icon("client/aim").pixmap();
266
267 // Clients with an ugly version string come last
268 else if (name.contains("Gadu-Gadu"))
269 p = IconsetFactory::icon("client/gadu").pixmap();
270 else if (name.contains("Miranda"))
271 p = IconsetFactory::icon("client/miranda").pixmap();
272 else if (name.contains("JAJC"))
273 p = IconsetFactory::icon("client/jajc").pixmap();
274 else if (name.contains("Trillian"))
275 p = IconsetFactory::icon("client/trillian").pixmap();
276 else if (name.contains("Yahoo"))
277 p = IconsetFactory::icon("client/yahoo").pixmap();
278 else if (name.contains("JIT"))
279 p = IconsetFactory::icon("client/icq").pixmap();
280 //else
281 // p = IconsetFactory::icon("client/unknown").pixmap();
282
283 setImage(p);
284}
285
286
287//------------------------------------------------------------------------------
288
289//------------------------------------------------------------------------------
290// Avatar factory
291//------------------------------------------------------------------------------
292
293AvatarFactory::AvatarFactory(PsiAccount* pa) : pa_(pa)
294{
295 VCardFactory::registerVCardChanged(this,SLOT(updateAvatar(const Jid&)));
296}
297
298
299QPixmap AvatarFactory::getAvatar(const Jid& jid, const QString& resource)
300{
301 // Compute the avatar of the user
302 Avatar* av = retrieveAvatar(jid,resource);
303
304 // If the avatar changed since the previous request, notify everybody of this
305 if (av != active_avatars_[jid.full()]) {
306 active_avatars_[jid.full()] = av;
307 active_avatars_[jid.bare()] = av;
308 emit avatarChanged(jid);
309 }
310
311 return (av ? av->getPixmap() : QPixmap());
312}
313
314Avatar* AvatarFactory::retrieveAvatar(const Jid& jid, const QString& client)
315{
316 // printf("Retrieving avatar of %s\n", jid.full().latin1());
317
318 // Try finding a file avatar.
319 //printf("File avatar\n");
320 if (!file_avatars_.contains(jid.bare())) {
321 //printf("File avatar not yet loaded\n");
322 file_avatars_[jid.bare()] = new FileAvatar(jid);
323 }
324 //printf("Trying file avatar\n");
325 if (!file_avatars_[jid.bare()]->isEmpty())
326 return file_avatars_[jid.bare()];
327
328 // Try finding an avatar in the VCard
329 //printf("VCard avatar\n");
330 if (!vcard_avatars_.contains(jid.bare())) {
331 //printf("VCard avatar not yet loaded\n");
332 vcard_avatars_[jid.bare()] = new VCardAvatar(this, jid);
333 connect(vcard_avatars_[jid.bare()],SIGNAL(avatarChanged(const Jid&)),this,SLOT(updateAvatar(const Jid&)));
334 }
335 //printf("Trying VCard avatar\n");
336 if (!vcard_avatars_[jid.bare()]->isEmpty()) {
337 return vcard_avatars_[jid.bare()];
338 }
339
340 // Return the client avatar
341 if (client.isEmpty()) {
342 return 0;
343 }
344 else {
345 if (!client_avatars_.contains(client)) {
346 // printf("Client avatar not yet loaded\n");
347 client_avatars_[client] = new ClientAvatar(client);
348 }
349 return client_avatars_[client];
350 }
351}
352
353QPixmap AvatarFactory::getSelfAvatar()
354{
355 return getAvatar(account()->jid(),"");
356}
357
358void AvatarFactory::updateAvatar(const Jid& j)
359{
360 // FIXME: Maybe we should really look up the client version
361 getAvatar(j,"");
362
363 // FIXME: This signal might be emitted twice (first time from getAvatar()).
364 emit avatarChanged(j);
365}
366
367void AvatarFactory::importManualAvatar(const Jid& j, const QString& fileName)
368{
369 FileAvatar(j).import(fileName);
370 emit avatarChanged(j);
371}
372
373void AvatarFactory::removeManualAvatar(const Jid& j)
374{
375 FileAvatar(j).removeFromDisk();
376 // TODO: Remove from caches. Maybe create a clearManualAvatar() which
377 // removes the file but doesn't remove the avatar from caches (since it'll
378 // be created again whenever the FileAvatar is requested)
379 emit avatarChanged(j);
380}
381
382bool AvatarFactory::hasManualAvatar(const Jid& j)
383{
384 return FileAvatar(j).exists();
385}
386
387QString AvatarFactory::getAvatarsDir()
388{
389 QDir avatars(pathToProfile(activeProfile) + "/avatars");
390 if (!avatars.exists()) {
391 QDir profile(pathToProfile(activeProfile));
392 profile.mkdir("avatars");
393 }
394
395 return avatars.path();
396}
397
398QString AvatarFactory::getManualDir()
399{
400 return getAvatarsDir() + "/manual";
401}
402
403//------------------------------------------------------------------------------
404
405#include "avatars.moc"
Note: See TracBrowser for help on using the repository browser.