• 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
kopeteonlinestatusmanager.cpp
Go to the documentation of this file.
1 /*
2  kopeteonlinestatusmanager.cpp
3 
4  Copyright (c) 2004 by Olivier Goffart <ogoffart@kde.fr>
5  Copyright (c) 2003 by Will Stephenson <wstephenson@kde.org>
6 
7  Kopete (c) 2003-2007 by the Kopete developers <kopete-devel@kde.org>
8 
9  *************************************************************************
10  * *
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU Lesser General Public *
13  * License as published by the Free Software Foundation; either *
14  * version 2 of the License, or (at your option) any later version. *
15  * *
16  *************************************************************************
17 */
18 
19 #include "kopeteonlinestatusmanager.h"
20 
21 #include "kopeteprotocol.h"
22 #include "kopetebehaviorsettings.h"
23 
24 #include <kiconloader.h>
25 #include <kiconeffect.h>
26 #include <kglobalsettings.h>
27 #include <kdebug.h>
28 #include <kicon.h>
29 
30 #include <algorithm> // for min
31 
32 namespace Kopete {
33 
34 
35 class OnlineStatusManager::Private
36 {
37 public:
38  struct QMapDummyValue
39  {
40  };
41 
42  typedef QMap< OnlineStatus , QMapDummyValue > RegisteredStatusMap;
43 
44  QPixmap *nullPixmap;
45  QMap< Protocol* , RegisteredStatusMap > registeredStatus;
46  QHash< QString, QPixmap* > iconCache;
47 };
48 
49 OnlineStatusManager *OnlineStatusManager::self()
50 {
51  static OnlineStatusManager s;
52  return &s;
53 }
54 
55 OnlineStatusManager::OnlineStatusManager()
56  : d( new Private )
57 {
58  // no autodelete, removing everything in destructor
59 // d->iconCache.setAutoDelete( true );
60  d->nullPixmap = new QPixmap;
61  connect( KGlobalSettings::self(), SIGNAL(iconChanged(int)), this, SLOT(slotIconsChanged()) );
62 }
63 
64 OnlineStatusManager::~OnlineStatusManager()
65 {
66  QHashIterator<QString, QPixmap*> it(d->iconCache);
67  while ( it.hasNext() )
68  {
69  it.next();
70  delete it.value();
71  }
72 
73  delete d->nullPixmap;
74  delete d;
75 }
76 
77 void OnlineStatusManager::slotIconsChanged()
78 {
79  // shall we delete all of em first ?
80  d->iconCache.clear();
81  emit iconsChanged();
82 }
83 
84 void OnlineStatusManager::registerOnlineStatus( const OnlineStatus &status )
85 {
86  d->registeredStatus[status.protocol()].insert( status, Private::QMapDummyValue() );
87 }
88 
89 OnlineStatus OnlineStatusManager::onlineStatus(Protocol * protocol, Categories category) const
90 {
91  /* Each category has a number which is a power of two, so it is possible to have several categories per online status
92  * the logaritm in base two if this number, which represent the bit which is equal to 1 in the number is chosen to be in a tree
93  * 1 (0 is reserved for Offline)
94  * / \
95  * 2 3
96  * / \ / \
97  * 4 5 6 7
98  * /\ / \ / \ / \
99  * 8 9 10 11 12 13 14 15
100  * To get the parent of a key, one just divide per two the number
101  */
102 
103  const Private::RegisteredStatusMap protocolMap=d->registeredStatus[protocol];
104 
105  int categ_nb=-1; //the logaritm of category
106  uint category_=category;
107  while(category_)
108  {
109  category_ >>= 1;
110  categ_nb++;
111  } //that code will give the log +1
112 
113  do
114  {
115  Private::RegisteredStatusMap::ConstIterator it;
116  for ( it = protocolMap.begin(); it != protocolMap.end(); ++it )
117  {
118  unsigned int catgs=it.key().categories();
119  if(catgs & (1<<(categ_nb)))
120  return it.key();
121  }
122  //no status found in this category, try the previous one.
123  categ_nb=(int)(categ_nb/2);
124  } while (categ_nb > 0);
125 
126  kWarning() << "No status in the category " << category << " for the protocol " << protocol->displayName();
127  return OnlineStatus();
128 }
129 
130 OnlineStatusManager::Category OnlineStatusManager::initialStatus() const
131 {
132  Kopete::OnlineStatusManager::Category statusValue = Kopete::OnlineStatusManager::Offline;
133  switch( Kopete::BehaviorSettings::self()->initialStatus() )
134  {
135  case Kopete::BehaviorSettings::EnumInitialStatus::Offline:
136  statusValue = Kopete::OnlineStatusManager::Offline;
137  break;
138  case Kopete::BehaviorSettings::EnumInitialStatus::Online:
139  statusValue = Kopete::OnlineStatusManager::Online;
140  break;
141  case Kopete::BehaviorSettings::EnumInitialStatus::Away:
142  statusValue = Kopete::OnlineStatusManager::Away;
143  break;
144  case Kopete::BehaviorSettings::EnumInitialStatus::Busy:
145  statusValue = Kopete::OnlineStatusManager::Busy;
146  break;
147  case Kopete::BehaviorSettings::EnumInitialStatus::Invisible:
148  statusValue = Kopete::OnlineStatusManager::Invisible;
149  break;
150  }
151 
152  return statusValue;
153 }
154 
155 QString OnlineStatusManager::fingerprint( const OnlineStatus &statusFor, const QString& icon, int size, QColor color, bool idle)
156 {
157  // create a 'fingerprint' to use as a hash key
158  // fingerprint consists of description/icon name/color/overlay name/size/idle state
159  return QString::fromLatin1("%1/%2/%3/%4/%5/%6")
160  .arg( statusFor.description() )
161  .arg( icon )
162  .arg( color.name() )
163  .arg( statusFor.overlayIcons().join( QString::fromLatin1( "," ) ) )
164  .arg( size )
165  .arg( idle ? 'i' : 'a' );
166 }
167 
168 QPixmap OnlineStatusManager::cacheLookupByObject( const OnlineStatus &statusFor, const QString& icon, int size, QColor color, bool idle)
169 {
170  QString fp = fingerprint( statusFor, icon, size, color, idle );
171 
172  //kDebug(14010) << "finger print:" << fp << ", icon: " << icon;
173  // look it up in the cache
174  QPixmap *theIcon = d->iconCache.value(fp);
175  if ( !theIcon )
176  {
177  // cache miss
178  kDebug(14010) << "Missed " << fp << " in icon cache!";
179  theIcon = renderIcon( statusFor, icon, size, color, idle);
180  d->iconCache[fp] = theIcon;
181  }
182  return *theIcon;
183 }
184 
185 QPixmap OnlineStatusManager::cacheLookupByMimeSource( const QString &mimeSource )
186 {
187  // look it up in the cache
188  const QPixmap *theIcon= d->iconCache.find( mimeSource ).value();
189  if ( !theIcon )
190  {
191  // need to return an invalid pixmap
192  theIcon = d->nullPixmap;
193  }
194  return *theIcon;
195 }
196 
197 // This code was forked from the broken KImageEffect::blendOnLower, but it's
198 // been so heavily fixed and rearranged it's hard to recognise that now.
199 static void blendOnLower( const QImage &upper_, QImage &lower, const QPoint &offset )
200 {
201  if ( upper_.width() <= 0 || upper_.height() <= 0 )
202  return;
203  if ( lower.width() <= 0 || lower.height() <= 0 )
204  return;
205  if ( offset.x() < 0 || offset.x() >= lower.width() )
206  return;
207  if ( offset.y() < 0 || offset.y() >= lower.height() )
208  return;
209 
210  QImage upper = upper_;
211  if ( upper.depth() != 32 )
212  upper = upper.convertToFormat( QImage::Format_RGB32 );
213  if ( lower.depth() != 32 )
214  lower = lower.convertToFormat( QImage::Format_RGB32 );
215 
216  const int cx = offset.x();
217  const int cy = offset.y();
218  const int cw = std::min( upper.width() + cx, lower.width() );
219  const int ch = std::min( upper.height() + cy, lower.height() );
220  const int m = 255;
221 
222  for ( int j = cy; j < ch; ++j )
223  {
224  QRgb *u = (QRgb*)upper.scanLine(j - cy);
225  QRgb *l = (QRgb*)lower.scanLine(j) + cx;
226 
227  for( int k = cx; k < cw; ++u, ++l, ++k )
228  {
229  int ua = qAlpha(*u);
230  if ( !ua )
231  continue;
232 
233  int la = qAlpha(*l);
234 
235  int d = ua * m + la * (m - ua);
236  uchar r = uchar( ( qRed(*u) * ua * m + qRed(*l) * la * (m - ua) ) / d );
237  uchar g = uchar( ( qGreen(*u) * ua * m + qGreen(*l) * la * (m - ua) ) / d );
238  uchar b = uchar( ( qBlue(*u) * ua * m + qBlue(*l) * la * (m - ua) ) / d );
239  uchar a = uchar( ( ua * ua * m + la * la * (m - ua) ) / d );
240  *l = qRgba( r, g, b, a );
241  }
242  }
243 }
244 
245 // Get bounding box of image via alpha channel
246 static QRect getBoundingBox( const QImage& image )
247 {
248  const int width = image.width();
249  const int height = image.height();
250  if ( width <= 0 || height <= 0 )
251  return QRect();
252 
253  // scan image from left to right and top to bottom
254  // to get upper left corner of bounding box
255  int x1 = width - 1;
256  int y1 = height - 1;
257  for ( int j = 0; j < height; ++j )
258  {
259  QRgb *i = (QRgb*)image.scanLine(j);
260 
261  for( int k = 0; k < width; ++i, ++k )
262  {
263  if ( qAlpha(*i) )
264  {
265  x1 = std::min( x1, k );
266  y1 = std::min( y1, j );
267  break;
268  }
269  }
270  }
271 
272  // scan image from right to left and bottom to top
273  // to get lower right corner of bounding box
274  int x2 = 0;
275  int y2 = 0;
276  for ( int j = height-1; j >= 0; --j )
277  {
278  QRgb *i = (QRgb*)image.scanLine(j) + width-1;
279 
280  int k;
281  for( k = width-1; k >= 0; --i, --k )
282  {
283  if ( qAlpha(*i) )
284  {
285  x2 = std::max( x2, k );
286  y2 = std::max( y2, j );
287  break;
288  }
289  }
290  if ( qAlpha(*i) )
291  {
292  x2 = std::max( x2, k );
293  y2 = std::max( y2, j );
294  break;
295  }
296  }
297  return QRect( x1, y1, std::max( 0, x2-x1+1 ), std::max( 0, y2-y1+1 ) );
298 }
299 
300 // Get offset for upperImage to blend it in the i%4-th corner of lowerImage:
301 // bottom right, bottom left, top left, top right
302 static QPoint getOffsetForCorner( const QImage& upperImage, const QImage& lowerImage, const int i )
303 {
304  const int dX = lowerImage.width() - upperImage.width();
305  const int dY = lowerImage.height() - upperImage.height();
306  const int corner = i % 4;
307  QPoint offset;
308  switch( corner ) {
309  case 0:
310  // bottom right
311  offset = QPoint( dX, dY );
312  break;
313  case 1:
314  // bottom left
315  offset = QPoint( 0, dY );
316  break;
317  case 2:
318  // top left
319  offset = QPoint( 0, 0 );
320  break;
321  case 3:
322  // top right
323  offset = QPoint( dX, 0 );
324  break;
325  }
326  return offset;
327 }
328 
329 QPixmap* OnlineStatusManager::renderIcon( const OnlineStatus &statusFor, const QString& baseIcon, int size, QColor color, bool idle) const
330 {
331  // create an icon suiting the status from the base icon
332  // use reasonable defaults if not provided or protocol not set
333 
334  //kDebug( 14010) << "overlayIcons size: " << statusFor.overlayIcons().count();
335 
336  // NOTE: overlayIcons car be empty
337  if ( !statusFor.overlayIcons().empty() && baseIcon == statusFor.overlayIcons().first() )
338  {
339  kWarning( 14010 ) << "Base and overlay icons are the same - icon effects will not be visible.";
340  }
341 
342  QPixmap* basis = new QPixmap( KIcon(baseIcon).pixmap(size) );
343 
344  // Colorize
345  if ( color.isValid() )
346  *basis = KIconEffect().apply( *basis, KIconEffect::Colorize, 1, color, 0);
347 
348  // Note that we do this before compositing the overlay, since we want
349  // that to be colored in this case.
350  if ( statusFor.internalStatus() == Kopete::OnlineStatus::AccountOffline || statusFor.status() == Kopete::OnlineStatus::Offline )
351  {
352  *basis = KIconEffect().apply( *basis, KIconEffect::ToGray , 0.85, QColor() , false );
353  }
354 
355  //composite the iconOverlay for this status and the supplied baseIcon
356  QStringList overlays = statusFor.overlayIcons();
357  if ( !( overlays.isEmpty() ) ) // otherwise leave the basis as-is
358  {
359  KIconLoader *loader = KIconLoader::global();
360 
361  int i = 0;
362  for( QStringList::iterator it = overlays.begin(), end = overlays.end(); it != end; ++it )
363  {
364  QPixmap overlay = loader->loadIcon(*it, KIconLoader::NoGroup, size,
365  KIconLoader::DefaultState, QStringList(), 0L, /*canReturnNull=*/ true );
366 
367  if ( !overlay.isNull() )
368  {
369  // we want to preserve the alpha channels of both basis and overlay.
370  // there's no way to do this in Qt. In fact, there's no way to do this
371  // in KDE since KImageEffect is so badly broken.
372  QImage basisImage = basis->toImage();
373  QImage overlayImage = overlay.toImage();
374  QPoint offset;
375  if ( (*it).endsWith( QString::fromLatin1( "_overlay" ) ) )
376  {
377  // it is possible to have more than one overlay icon
378  // to avoid overlapping we place them in different corners
379  overlayImage = overlayImage.copy( getBoundingBox( overlayImage ) );
380  offset = getOffsetForCorner( overlayImage, basisImage, i );
381  ++i;
382  }
383  blendOnLower( overlayImage, basisImage, offset );
384  *basis = QPixmap::fromImage( basisImage );
385  }
386  }
387  }
388 
389  // no need to scale if the icon is already of the required size (assuming height == width!)
390  if ( basis->width() != size )
391  {
392  QImage scaledImg = basis->toImage().scaled( size, size , Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
393  *basis = QPixmap::fromImage( scaledImg );
394  }
395 
396  // if idle, apply effects
397  if ( idle )
398  KIconEffect::semiTransparent( *basis );
399 
400  return basis;
401 }
402 
403 QList<OnlineStatus> OnlineStatusManager::registeredStatusList( Protocol *protocol ) const
404 {
405  return d->registeredStatus.value( protocol ).keys();
406 }
407 
408 KIcon OnlineStatusManager::pixmapForCategory( Categories category )
409 {
410  switch ( category )
411  {
412  case Kopete::OnlineStatusManager::Online:
413  return KIcon("user-online");
414  case Kopete::OnlineStatusManager::FreeForChat:
415  return KIcon("user-online");
416  case Kopete::OnlineStatusManager::Away:
417  return KIcon("user-away");
418  case Kopete::OnlineStatusManager::Idle:
419  return KIcon("user-away");
420  case Kopete::OnlineStatusManager::ExtendedAway:
421  return KIcon("user-away-extended");
422  case Kopete::OnlineStatusManager::Busy:
423  return KIcon("user-busy");
424  case Kopete::OnlineStatusManager::Invisible:
425  return KIcon("user-invisible");
426  case Kopete::OnlineStatusManager::Offline:
427  return KIcon("user-offline");
428  default:
429  return KIcon("user-identity");
430  }
431 }
432 
433 } //END namespace Kopete
434 
435 #include "kopeteonlinestatusmanager.moc"
436 
437 // vim: set noet ts=4 sts=4 sw=4:
438 
QImage::scanLine
uchar * scanLine(int i)
Kopete::OnlineStatus::overlayIcons
QStringList overlayIcons() const
Return the list of overlay icons.
Definition: kopeteonlinestatus.cpp:257
Kopete::OnlineStatus
Definition: kopeteonlinestatus.h:68
QImage::convertToFormat
QImage convertToFormat(Format format, QFlags< Qt::ImageConversionFlag > flags) const
status
OnlineStatus::StatusType status
Definition: kopeteonlinestatus.cpp:103
Kopete::blendOnLower
static void blendOnLower(const QImage &upper_, QImage &lower, const QPoint &offset)
Definition: kopeteonlinestatusmanager.cpp:199
QPixmap::width
int width() const
QColor::name
QString name() const
Kopete::OnlineStatus::description
QString description() const
Return the description.
Definition: kopeteonlinestatus.cpp:262
Kopete::OnlineStatusManager::~OnlineStatusManager
~OnlineStatusManager()
Definition: kopeteonlinestatusmanager.cpp:64
Kopete::BehaviorSettings::EnumInitialStatus::Invisible
Definition: kopetebehaviorsettings.h:20
Kopete::OnlineStatusManager::ExtendedAway
Definition: kopeteonlinestatusmanager.h:61
QHashIterator::hasNext
bool hasNext() const
Kopete::Protocol
base class of every protocol.
Definition: kopeteprotocol.h:62
QImage::depth
int depth() const
Kopete::Plugin::displayName
QString displayName() const
Returns the display name of this plugin.
Definition: kopeteplugin.cpp:52
QMap
Kopete::OnlineStatus::protocol
Protocol * protocol() const
Return the protocol this applies to.
Definition: kopeteonlinestatus.cpp:267
Kopete::OnlineStatusManager::Category
Category
Kopete will uses categories to have a more general system than simply globally away.
Definition: kopeteonlinestatusmanager.h:59
Kopete::OnlineStatus::Offline
State where you really cannot be contacted.
Definition: kopeteonlinestatus.h:98
Kopete::OnlineStatusManager::Idle
Definition: kopeteonlinestatusmanager.h:61
Kopete::OnlineStatus::AccountOffline
The account this contact belongs to is offline.
Definition: kopeteonlinestatus.h:147
QPixmap::fromImage
QPixmap fromImage(const QImage &image, QFlags< Qt::ImageConversionFlag > flags)
QPoint
QStringList::join
QString join(const QString &separator) const
Kopete::OnlineStatusManager::onlineStatus
OnlineStatus onlineStatus(Protocol *protocol, Categories category) const
return the status of the protocol which is in the category category
Definition: kopeteonlinestatusmanager.cpp:89
QImage::copy
QImage copy(const QRect &rectangle) const
QPoint::x
int x() const
QPoint::y
int y() const
Kopete::getBoundingBox
static QRect getBoundingBox(const QImage &image)
Definition: kopeteonlinestatusmanager.cpp:246
QRect
Kopete::OnlineStatusManager::iconsChanged
void iconsChanged()
Kopete::OnlineStatusManager::initialStatus
Kopete::OnlineStatusManager::Category initialStatus() const
This returns status from config as Kopete::OnlineStatusManager::Category.
Definition: kopeteonlinestatusmanager.cpp:130
QHash< QString, QPixmap * >
QImage::width
int width() const
kopeteprotocol.h
QList::isEmpty
bool isEmpty() const
QHashIterator
Kopete::BehaviorSettings::EnumInitialStatus::Away
Definition: kopetebehaviorsettings.h:20
Kopete::OnlineStatusManager::OnlineStatus
friend class OnlineStatus
Definition: kopeteonlinestatusmanager.h:131
Kopete::OnlineStatusManager::pixmapForCategory
static KIcon pixmapForCategory(Categories category)
return KIcon for given category
Definition: kopeteonlinestatusmanager.cpp:408
Kopete::BehaviorSettings::EnumInitialStatus::Busy
Definition: kopetebehaviorsettings.h:20
QString
QList
QMap::end
iterator end()
QColor
QList::iterator
QMap::begin
iterator begin()
QStringList
QPixmap
Kopete::OnlineStatusManager::Busy
Definition: kopeteonlinestatusmanager.h:63
QList::end
iterator end()
QPixmap::isNull
bool isNull() const
QHashIterator::next
Item next()
Kopete::OnlineStatusManager::Invisible
Definition: kopeteonlinestatusmanager.h:61
QImage
Kopete::OnlineStatusManager::registeredStatusList
QList< OnlineStatus > registeredStatusList(Protocol *protocol) const
return the registered statuses for given protocol
Definition: kopeteonlinestatusmanager.cpp:403
Kopete::OnlineStatusManager::FreeForChat
Definition: kopeteonlinestatusmanager.h:63
Kopete::getOffsetForCorner
static QPoint getOffsetForCorner(const QImage &upperImage, const QImage &lowerImage, const int i)
Definition: kopeteonlinestatusmanager.cpp:302
Kopete::BehaviorSettings::EnumInitialStatus::Online
Definition: kopetebehaviorsettings.h:20
Kopete::OnlineStatusManager::Online
Definition: kopeteonlinestatusmanager.h:67
Kopete::OnlineStatusManager::Away
Definition: kopeteonlinestatusmanager.h:65
Kopete::BehaviorSettings::self
static BehaviorSettings * self()
Definition: kopetebehaviorsettings.cpp:23
Kopete::OnlineStatusManager::registerOnlineStatus
void registerOnlineStatus(const OnlineStatus &status)
You need to register each status an account can be.
Definition: kopeteonlinestatusmanager.cpp:84
QString::fromLatin1
QString fromLatin1(const char *str, int size)
QImage::height
int height() const
Kopete::OnlineStatusManager::self
static OnlineStatusManager * self()
Definition: kopeteonlinestatusmanager.cpp:49
QPixmap::toImage
QImage toImage() const
QHashIterator::value
const T & value() const
QMap::ConstIterator
typedef ConstIterator
Kopete::OnlineStatusManager
OnlineStatusManager is a singleton which manage OnlineStatus.
Definition: kopeteonlinestatusmanager.h:42
Kopete::OnlineStatusManager::Offline
Definition: kopeteonlinestatusmanager.h:68
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
kopetebehaviorsettings.h
Kopete::BehaviorSettings::EnumInitialStatus::Offline
Definition: kopetebehaviorsettings.h:20
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QList::begin
iterator begin()
QImage::scaled
QImage scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const
kopeteonlinestatusmanager.h
QColor::isValid
bool isValid() const
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