• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdenetwork API Reference
  • KDE Home
  • Contact Us
 

kopete/libkopete

  • sources
  • kde-4.14
  • kdenetwork
  • kopete
  • libkopete
kopeteavatarmanager.cpp
Go to the documentation of this file.
1 /*
2  kopeteavatarmanager.cpp - Global avatar manager
3 
4  Copyright (c) 2007 by MichaĆ«l Larouche <larouche@kde.org>
5 
6  Kopete (c) 2002-2007 by the Kopete developers <kopete-devel@kde.org>
7 
8  *************************************************************************
9  * *
10  * This library is free software; you can redistribute it and/or *
11  * modify it under the terms of the GNU Lesser General Public *
12  * License as published by the Free Software Foundation; either *
13  * version 2 of the License, or (at your option) any later version. *
14  * *
15  *************************************************************************
16 */
17 #include "kopeteavatarmanager.h"
18 
19 // Qt includes
20 #include <QtCore/QLatin1String>
21 #include <QtCore/QBuffer>
22 #include <QtCore/QCoreApplication>
23 #include <QtCore/QFile>
24 #include <QtCore/QPointer>
25 #include <QtCore/QStringList>
26 #include <QtCore/QDir>
27 #include <QtGui/QPainter>
28 #include <QtGui/QImageReader>
29 
30 // KDE includes
31 #include <kdebug.h>
32 #include <kstandarddirs.h>
33 #include <kconfig.h>
34 #include <kcodecs.h>
35 #include <kurl.h>
36 #include <kio/job.h>
37 #include <kio/netaccess.h>
38 #include <klocale.h>
39 
40 // Kopete includes
41 #include <kopetecontact.h>
42 #include <kopeteprotocol.h>
43 #include <kopeteaccount.h>
44 
45 namespace Kopete
46 {
47 
48 //BEGIN AvatarManager
49 AvatarManager *AvatarManager::s_self = 0;
50 
51 AvatarManager *AvatarManager::self()
52 {
53  if( !s_self )
54  {
55  s_self = new AvatarManager;
56  }
57  return s_self;
58 }
59 
60 class AvatarManager::Private
61 {
62 public:
63  KUrl baseDir;
64 
69  void createDirectory(const KUrl &directory);
70 
75  QImage scaleImage(const QImage &source);
76 };
77 
78 static const QString UserDir("User");
79 static const QString ContactDir("Contacts");
80 static const QString AvatarConfig("avatarconfig.rc");
81 
82 
83 AvatarManager::AvatarManager(QObject *parent)
84  : QObject(parent), d(new Private)
85 {
86  // Locate avatar data dir on disk
87  d->baseDir = KUrl( KStandardDirs::locateLocal("appdata", QLatin1String("avatars") ) );
88 
89  // Create directory on disk, if necessary
90  d->createDirectory( d->baseDir );
91 }
92 
93 AvatarManager::~AvatarManager()
94 {
95  s_self = 0L;
96  delete d;
97 }
98 
99 Kopete::AvatarManager::AvatarEntry AvatarManager::add(Kopete::AvatarManager::AvatarEntry newEntry)
100 {
101  Q_ASSERT(!newEntry.name.isEmpty());
102 
103  KUrl avatarUrl(d->baseDir);
104 
105  // First find where to save the file
106  switch(newEntry.category)
107  {
108  case AvatarManager::User:
109  avatarUrl.addPath( UserDir );
110  d->createDirectory( avatarUrl );
111  break;
112  case AvatarManager::Contact:
113  avatarUrl.addPath( ContactDir );
114  d->createDirectory( avatarUrl );
115  // Use the account id for sub directory
116  if( newEntry.contact && newEntry.contact->account() )
117  {
118  QString accountName = newEntry.contact->account()->accountId();
119  QString protocolName = newEntry.contact->account()->protocol()->pluginId();
120  avatarUrl.addPath( protocolName );
121  d->createDirectory( avatarUrl );
122  avatarUrl.addPath( accountName );
123  d->createDirectory( avatarUrl );
124  }
125  break;
126  default:
127  break;
128  }
129 
130  KUrl dataUrl(avatarUrl);
131 
132  kDebug(14010) << "Base directory: " << avatarUrl.toLocalFile();
133 
134  // Second, open the avatar configuration in current directory.
135  KUrl configUrl = avatarUrl;
136  configUrl.addPath( AvatarConfig );
137 
138  QByteArray data = newEntry.data;
139  QImage avatar = newEntry.image;
140 
141  if (!data.isNull())
142  {
143  avatar.loadFromData(data);
144  }
145  else if(!newEntry.dataPath.isEmpty()){
146  QFile f(newEntry.dataPath);
147  f.open(QIODevice::ReadOnly);
148  data = f.readAll();
149  f.close();
150 
151  avatar.loadFromData(data);
152  }
153  else if(!avatar.isNull()){
154  QByteArray tempArray;
155  QBuffer tempBuffer(&tempArray);
156  tempBuffer.open( QIODevice::WriteOnly );
157  avatar.save(&tempBuffer, "PNG");
158 
159  data = tempArray;
160  }
161  else if(!newEntry.path.isEmpty()){
162  avatar = QImage(newEntry.path);
163 
164  QFile f(newEntry.path);
165  f.open(QIODevice::ReadOnly);
166  data = f.readAll();
167  f.close();
168  }
169  else
170  {
171  kDebug() << "Warning: No valid image source!";
172  }
173 
174  // Scale avatar
175  avatar = d->scaleImage(avatar);
176 
177  QString avatarFilename;
178 
179  // for the contact avatar, save it with the contactId + .png
180  if (newEntry.category == AvatarManager::Contact && newEntry.contact)
181  {
182  avatarFilename = KIO::encodeFileName(newEntry.contact->contactId()) + ".png";
183  }
184  else
185  {
186  // Find MD5 hash for filename
187  // MD5 always contain ASCII caracteres so it is more save for a filename.
188  // Name can use UTF-8 characters.
189  QByteArray tempArray;
190  QBuffer tempBuffer(&tempArray);
191  tempBuffer.open( QIODevice::WriteOnly );
192  avatar.save(&tempBuffer, "PNG");
193  KMD5 context(tempArray);
194  avatarFilename = context.hexDigest() + QLatin1String(".png");
195  }
196 
197  // Save image on disk
198  kDebug(14010) << "Saving " << avatarFilename << " on disk.";
199  avatarUrl.addPath( avatarFilename );
200 
201  if( !avatar.save( avatarUrl.toLocalFile(), "PNG") )
202  {
203  kDebug(14010) << "Saving of scaled avatar to " << avatarUrl.toLocalFile() << " failed !";
204  return AvatarEntry();
205  }
206 
207  QString dataFilename;
208 
209  // for the contact avatar, save it with the contactId + .png
210  if (newEntry.category == AvatarManager::Contact && newEntry.contact)
211  {
212  dataFilename = KIO::encodeFileName(newEntry.contact->contactId()) + QLatin1String("_");
213  }
214 
215  dataFilename += KMD5(data).hexDigest();
216 
217  QBuffer buffer(&data);
218  buffer.open(QIODevice::ReadOnly);
219  QImageReader ir(&buffer);
220  dataFilename += QLatin1String(".") + QLatin1String(ir.format());
221 
222  // Save (original) data on disk
223  dataUrl.addPath(dataFilename);
224  QFile f(dataUrl.toLocalFile());
225  if (!f.open(QIODevice::WriteOnly))
226  {
227  kDebug(14010) << "Saving of original avatar to " << dataUrl.toLocalFile() << " failed !";
228  return AvatarEntry();
229  }
230  f.write(data);
231  f.flush();
232  f.close();
233 
234  // Save metadata of image
235  KConfigGroup avatarConfig(KSharedConfig::openConfig( configUrl.toLocalFile(), KConfig::SimpleConfig), newEntry.name );
236 
237  avatarConfig.writeEntry( "Filename", avatarFilename );
238  avatarConfig.writeEntry( "DataFilename", dataFilename );
239  avatarConfig.writeEntry( "Category", int(newEntry.category) );
240 
241  avatarConfig.sync();
242 
243  // Add final path to the new entry for avatarAdded signal
244  newEntry.path = avatarUrl.toLocalFile();
245  newEntry.dataPath = dataUrl.toLocalFile();
246 
247  emit avatarAdded(newEntry);
248 
249  return newEntry;
250 }
251 
252 bool AvatarManager::remove(Kopete::AvatarManager::AvatarEntry entryToRemove)
253 {
254  // We need name and path to remove an avatar from the storage.
255  if( entryToRemove.name.isEmpty() && entryToRemove.path.isEmpty() )
256  return false;
257 
258  // We don't allow removing avatars from Contact category
259  if( entryToRemove.category & Kopete::AvatarManager::Contact )
260  return false;
261 
262  // Delete the image file first, file delete is more likely to fail than config group remove.
263  if( KIO::NetAccess::del(KUrl(entryToRemove.path),0) )
264  {
265  kDebug(14010) << "Removing avatar from config.";
266 
267  KUrl configUrl(d->baseDir);
268  configUrl.addPath( UserDir );
269  configUrl.addPath( AvatarConfig );
270 
271  KConfigGroup avatarConfig ( KSharedConfig::openConfig( configUrl.toLocalFile(), KConfig::SimpleConfig ), entryToRemove.name );
272  avatarConfig.deleteGroup();
273  avatarConfig.sync();
274 
275  emit avatarRemoved(entryToRemove);
276 
277  return true;
278  }
279 
280  return false;
281 }
282 
283 bool AvatarManager::exists(Kopete::AvatarManager::AvatarEntry entryToCheck)
284 {
285  if( entryToCheck.name.isEmpty() )
286  return false;
287  return exists(entryToCheck.name);
288 }
289 
290 bool AvatarManager::exists(const QString &avatarName)
291 {
292  KUrl configUrl(d->baseDir);
293  configUrl.addPath( UserDir );
294  configUrl.addPath( AvatarConfig );
295 
296  KConfigGroup avatarConfig ( KSharedConfig::openConfig( configUrl.toLocalFile(), KConfig::SimpleConfig ), avatarName );
297  kDebug(14010) << "Checking if an avatar exists: " << avatarName;
298  if(!avatarConfig.exists()){
299  return false;
300  }
301  return true;
302 }
303 
304 void AvatarManager::Private::createDirectory(const KUrl &directory)
305 {
306  if( !QFile::exists(directory.toLocalFile()) )
307  {
308  kDebug(14010) << "Creating directory: " << directory.toLocalFile();
309  if( !KIO::NetAccess::mkdir(directory,0) )
310  {
311  kDebug(14010) << "Directory " << directory.toLocalFile() <<" creating failed.";
312  }
313  }
314 }
315 
316 QImage AvatarManager::Private::scaleImage(const QImage &source)
317 {
318  if (source.isNull())
319  {
320  return QImage();
321  }
322 
323  //make an empty image and fill with transparent color
324  QImage result(96, 96, QImage::Format_ARGB32);
325  result.fill(0);
326 
327  QPainter paint(&result);
328  float x = 0, y = 0;
329 
330  // scale and center the image
331  if( source.width() > 96 || source.height() > 96 )
332  {
333  const QImage scaled = source.scaled( 96, 96, Qt::KeepAspectRatio, Qt::SmoothTransformation );
334 
335  x = (96 - scaled.width()) / 2.0;
336  y = (96 - scaled.height()) / 2.0;
337 
338  paint.translate(x, y);
339  paint.drawImage(QPoint(0, 0), scaled);
340  } else {
341  x = (96 - source.width()) / 2.0;
342  y = (96 - source.height()) / 2.0;
343 
344  paint.translate(x, y);
345  paint.drawImage(QPoint(0, 0), source);
346  }
347 
348  return result;
349 }
350 
351 //END AvatarManager
352 
353 //BEGIN AvatarQueryJob
354 class AvatarQueryJob::Private
355 {
356 public:
357  Private(AvatarQueryJob *parent)
358  : queryJob(parent), category(AvatarManager::All)
359  {}
360 
361  QPointer<AvatarQueryJob> queryJob;
362  AvatarManager::AvatarCategory category;
363  QList<AvatarManager::AvatarEntry> avatarList;
364  KUrl baseDir;
365 
366  void listAvatarDirectory(const QString &path);
367 };
368 
369 AvatarQueryJob::AvatarQueryJob(QObject *parent)
370  : KJob(parent), d(new Private(this))
371 {
372 
373 }
374 
375 AvatarQueryJob::~AvatarQueryJob()
376 {
377  delete d;
378 }
379 
380 void AvatarQueryJob::setQueryFilter(Kopete::AvatarManager::AvatarCategory category)
381 {
382  d->category = category;
383 }
384 
385 void AvatarQueryJob::start()
386 {
387  d->baseDir = KUrl( KStandardDirs::locateLocal("appdata", QLatin1String("avatars") ) );
388 
389  if( d->category & Kopete::AvatarManager::User )
390  {
391  d->listAvatarDirectory( UserDir );
392  }
393  if( d->category & Kopete::AvatarManager::Contact )
394  {
395  KUrl contactUrl(d->baseDir);
396  contactUrl.addPath( ContactDir );
397 
398  const QDir contactDir(contactUrl.toLocalFile());
399  const QStringList subdirsList = contactDir.entryList( QDir::AllDirs | QDir::NoDotAndDotDot );
400  foreach(const QString &subdir, subdirsList)
401  {
402  d->listAvatarDirectory( ContactDir + QDir::separator() + subdir );
403  }
404  }
405 
406  // Finish the job
407  emitResult();
408 }
409 
410 QList<Kopete::AvatarManager::AvatarEntry> AvatarQueryJob::avatarList() const
411 {
412  return d->avatarList;
413 }
414 
415 void AvatarQueryJob::Private::listAvatarDirectory(const QString &relativeDirectory)
416 {
417  KUrl avatarDirectory = baseDir;
418  avatarDirectory.addPath(relativeDirectory);
419 
420  kDebug(14010) << "Listing avatars in " << avatarDirectory.toLocalFile();
421 
422  // Look for Avatar configuration
423  KUrl avatarConfigUrl = avatarDirectory;
424  avatarConfigUrl.addPath( AvatarConfig );
425  if( QFile::exists(avatarConfigUrl.toLocalFile()) )
426  {
427  KConfig *avatarConfig = new KConfig( avatarConfigUrl.toLocalFile(), KConfig::SimpleConfig);
428  // Each avatar entry in configuration is a group
429  const QStringList groupEntryList = avatarConfig->groupList();
430  foreach(const QString &groupEntry, groupEntryList)
431  {
432  KConfigGroup cg(avatarConfig, groupEntry);
433 
434  Kopete::AvatarManager::AvatarEntry listedEntry;
435  listedEntry.name = groupEntry;
436  listedEntry.category = static_cast<Kopete::AvatarManager::AvatarCategory>( cg.readEntry("Category", 0) );
437 
438  const QString filename = cg.readEntry( "Filename", QString() );
439  KUrl avatarPath(avatarDirectory);
440  avatarPath.addPath( filename );
441  listedEntry.path = avatarPath.toLocalFile();
442 
443  const QString dataFilename = cg.readEntry( "DataFilename", QString() );
444  KUrl dataPath(avatarDirectory);
445  dataPath.addPath( dataFilename );
446  listedEntry.dataPath = dataPath.toLocalFile();
447 
448  avatarList << listedEntry;
449  }
450  delete avatarConfig;
451  }
452 }
453 
454 //END AvatarQueryJob
455 
456 }
457 
458 #include "kopeteavatarmanager.moc"
Kopete::Account::protocol
Protocol * protocol() const
Definition: kopeteaccount.cpp:216
Kopete::AvatarQueryJob::AvatarQueryJob
AvatarQueryJob(QObject *parent=0)
Definition: kopeteavatarmanager.cpp:369
QImage::loadFromData
bool loadFromData(const uchar *data, int len, const char *format)
Kopete::AvatarManager::AvatarEntry::contact
Kopete::Contact * contact
contact is used when adding a new contact avatar. AvatarManager use it to create the final url...
Definition: kopeteavatarmanager.h:134
Kopete::AvatarManager::AvatarEntry::category
AvatarManager::AvatarCategory category
category in which the avatar belong
Definition: kopeteavatarmanager.h:135
Kopete::AvatarManager::AvatarEntry::dataPath
QString dataPath
path is the full path to the data on disk
Definition: kopeteavatarmanager.h:133
Kopete::AvatarManager::AvatarEntry::image
QImage image
image is used when adding a new avatar, AvatarManager will write the image on disk.
Definition: kopeteavatarmanager.h:131
Kopete::AvatarManager::AvatarEntry
struct Kopete::AvatarManager::AvatarEntry AvatarEntry
A single entry in AvatarManager.
kopeteaccount.h
QByteArray
Kopete::Contact::contactId
QString contactId
Definition: kopetecontact.h:70
Kopete::AvatarManager::avatarRemoved
void avatarRemoved(Kopete::AvatarManager::AvatarEntry entryRemoved)
An avatar was removed from storage.
QImage::save
bool save(const QString &fileName, const char *format, int quality) const
QByteArray::isNull
bool isNull() const
QPointer
Kopete::Contact::account
Account * account() const
Get the account that this contact belongs to.
Definition: kopetecontact.cpp:538
QBuffer
Kopete::AvatarQueryJob::~AvatarQueryJob
~AvatarQueryJob()
Definition: kopeteavatarmanager.cpp:375
QPoint
QImage::isNull
bool isNull() const
QFile::exists
bool exists() const
QDir::separator
QChar separator()
QFile
Kopete::AvatarManager::AvatarEntry::name
QString name
name is a friendly name to identity the avatar
Definition: kopeteavatarmanager.h:129
QObject
QImage::width
int width() const
Kopete::Account::accountId
QString accountId
Definition: kopeteaccount.h:77
Kopete::Plugin::pluginId
QString pluginId() const
Get the plugin id.
Definition: kopeteplugin.cpp:46
Kopete::AvatarManager::User
User defined avatar.
Definition: kopeteavatarmanager.h:115
kopeteprotocol.h
QPainter
QString::isEmpty
bool isEmpty() const
QIODevice::readAll
QByteArray readAll()
Kopete::AvatarManager::remove
bool remove(Kopete::AvatarManager::AvatarEntry entryToRemove)
Remove an avatar from the storage.
Definition: kopeteavatarmanager.cpp:252
kopeteavatarmanager.h
QBuffer::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > flags)
QImageReader
Kopete::AvatarManager::self
static AvatarManager * self()
Get the only instance of AvatarManager.
Definition: kopeteavatarmanager.cpp:51
Kopete::AvatarConfig
static const QString AvatarConfig("avatarconfig.rc")
QString
QList
QFile::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
Kopete::AvatarManager::avatarAdded
void avatarAdded(Kopete::AvatarManager::AvatarEntry newEntry)
An avatar was added into the storage.
QStringList
Kopete::AvatarManager::AvatarEntry::data
QByteArray data
original data used to construct the image
Definition: kopeteavatarmanager.h:132
QFile::close
virtual void close()
QImage
Kopete::AvatarQueryJob::avatarList
QList< Kopete::AvatarManager::AvatarEntry > avatarList() const
Get the avatar list based on the query.
Definition: kopeteavatarmanager.cpp:410
QDir
Kopete::AvatarManager::AvatarEntry
A single entry in AvatarManager.
Definition: kopeteavatarmanager.h:127
QLatin1String
Kopete::AvatarManager::add
Kopete::AvatarManager::AvatarEntry add(Kopete::AvatarManager::AvatarEntry newEntry)
Add an new avatar to the storage.
Definition: kopeteavatarmanager.cpp:99
Kopete::ContactDir
static const QString ContactDir("Contacts")
Kopete::UserDir
static const QString UserDir("User")
Kopete::AvatarManager::AvatarEntry::path
QString path
path is the full path to the image on disk
Definition: kopeteavatarmanager.h:130
Kopete::AvatarManager::Contact
Avatar from a contact.
Definition: kopeteavatarmanager.h:116
Kopete::AvatarQueryJob::start
virtual void start()
Definition: kopeteavatarmanager.cpp:385
Kopete::AvatarQueryJob::setQueryFilter
void setQueryFilter(Kopete::AvatarManager::AvatarCategory category)
Set the filter for the avatar job.
Definition: kopeteavatarmanager.cpp:380
Kopete::AvatarManager::exists
bool exists(Kopete::AvatarManager::AvatarEntry avatarToCheck)
Check if an avatar exists.
Definition: kopeteavatarmanager.cpp:283
QImage::height
int height() const
NetworkStatus::All
Definition: networkstatuscommon.h:11
Kopete::AvatarManager::~AvatarManager
~AvatarManager()
Definition: kopeteavatarmanager.cpp:93
QImageReader::format
QByteArray format() const
KJob
kopetecontact.h
QImage::scaled
QImage scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const
Kopete::AvatarManager
Manage the avatar storage.
Definition: kopeteavatarmanager.h:106
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:29:19 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kopete/libkopete

Skip menu "kopete/libkopete"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdenetwork API Reference

Skip menu "kdenetwork API Reference"
  • kget
  • kopete
  •   kopete
  •   libkopete
  • krdc
  • krfb

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal