Autogenerate systray icon from the kopete icon in the theme instead of using the...
[kdenetwork.git] / kopete / kopete / systemtray.cpp
blob391b75599ace9ef6e1facd2bed9b6f5c8d6afb9e
1 /*
2 systemtray.cpp - Kopete Tray Dock Icon
4 Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
5 Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
6 Copyright (c) 2003-2004 by Olivier Goffart <ogoffart@kde.org>
8 Kopete (c) 2002-2007 by the Kopete developers <kopete-devel@kde.org>
10 *************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 *************************************************************************
20 #include "systemtray.h"
22 #include <qtimer.h>
24 #include <qregexp.h>
25 #include <QMouseEvent>
26 #include <QPixmap>
27 #include <QEvent>
28 #include <QPainter>
30 #include <kaboutdata.h>
31 #include <kactioncollection.h>
32 #include <kaction.h>
33 #include <kmenu.h>
34 #include <klocale.h>
35 #include <kdebug.h>
36 #include <kiconloader.h>
37 #include "kopeteuiglobal.h"
38 #include "kopetechatsessionmanager.h"
39 #include "kopetebehaviorsettings.h"
40 #include "kopetemetacontact.h"
41 #include "kopeteaccount.h"
42 #include "kopeteaccountmanager.h"
43 #include "kopetecontact.h"
44 #include "kopetewindow.h"
45 #include <kiconeffect.h>
47 KopeteSystemTray* KopeteSystemTray::s_systemTray = 0;
49 KopeteSystemTray* KopeteSystemTray::systemTray( QWidget *parent )
51 if( !s_systemTray )
52 s_systemTray = new KopeteSystemTray( parent );
54 return s_systemTray;
57 KopeteSystemTray::KopeteSystemTray(QWidget* parent)
58 : KAnimatedSystemTrayIcon(parent)
59 , mMovie(0)
61 kDebug(14010) ;
62 setToolTip(KGlobal::mainComponent().aboutData()->shortDescription());
64 mIsBlinkIcon = false;
65 mIsBlinking = false;
66 mBlinkTimer = new QTimer(this);
67 mBlinkTimer->setObjectName("mBlinkTimer");
69 mKopeteIcon = loadIcon("kopete");
71 // Hack which allow us to disable window restoring or hiding when we should process event (BUG:157663)
72 disconnect( this, SIGNAL(activated( QSystemTrayIcon::ActivationReason )), 0 ,0 );
74 connect(contextMenu(), SIGNAL(aboutToShow()), this, SLOT(slotAboutToShowMenu()));
76 connect(mBlinkTimer, SIGNAL(timeout()), this, SLOT(slotBlink()));
77 connect(Kopete::ChatSessionManager::self() , SIGNAL(newEvent(Kopete::MessageEvent*)),
78 this, SLOT(slotNewEvent(Kopete::MessageEvent*)));
79 connect(Kopete::BehaviorSettings::self(), SIGNAL(configChanged()), this, SLOT(slotConfigChanged()));
81 connect(Kopete::AccountManager::self(),
82 SIGNAL(accountOnlineStatusChanged(Kopete::Account *,
83 const Kopete::OnlineStatus &, const Kopete::OnlineStatus &)),
84 this, SLOT(slotReevaluateAccountStates()));
86 // the slot called by default by the quit action, KSystemTray::maybeQuit(),
87 // just closes the parent window, which is hard to distinguish in that window's closeEvent()
88 // from a click on the window's close widget
89 // in the quit case, we want to quit the application
90 // in the close widget click case, we only want to hide the parent window
91 // so instead, we make it call our general purpose quit slot on the window, which causes a window close and everything else we need
92 // KDE4 - app will have to listen for quitSelected instead
93 QAction *quit = actionCollection()->action( "file_quit" );
94 quit->disconnect();
95 KopeteWindow *myParent = static_cast<KopeteWindow *>( parent );
96 connect( quit, SIGNAL( activated() ), myParent, SLOT( slotQuit() ) );
97 connect( this, SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ), SLOT( slotActivated( QSystemTrayIcon::ActivationReason ) ) );
99 setIcon(mKopeteIcon);
100 slotReevaluateAccountStates();
101 slotConfigChanged();
104 KopeteSystemTray::~KopeteSystemTray()
106 kDebug(14010) ;
107 // delete mBlinkTimer;
110 void KopeteSystemTray::slotAboutToShowMenu()
112 emit aboutToShowMenu(qobject_cast<KMenu *>(contextMenu()));
115 void KopeteSystemTray::slotActivated( QSystemTrayIcon::ActivationReason reason )
117 bool shouldProcessEvent(
118 reason == QSystemTrayIcon::MiddleClick
119 || reason == QSystemTrayIcon::DoubleClick
120 || ( reason == QSystemTrayIcon::Trigger
121 && Kopete::BehaviorSettings::self()->trayflashNotifyLeftClickOpensMessage()));
122 if ( isBlinking() && shouldProcessEvent )
124 if ( !mEventList.isEmpty() )
125 mEventList.first()->apply();
127 else if ( reason == QSystemTrayIcon::Trigger )
129 toggleActive();
133 // void KopeteSystemTray::contextMenuAboutToShow( KMenu *me )
134 // {
135 // //kDebug(14010) << "Called.";
136 // emit aboutToShowMenu( me );
137 // }
139 void KopeteSystemTray::startBlink( const QString &icon )
141 startBlink( loadIcon( icon ) );
144 void KopeteSystemTray::startBlink( const QIcon &icon )
146 mBlinkIcon = icon;
147 if ( mBlinkTimer->isActive() == false )
149 mIsBlinkIcon = true;
150 mIsBlinking = true;
151 mBlinkTimer->setSingleShot( false );
152 mBlinkTimer->start( 1000 );
154 else
156 mBlinkTimer->stop();
157 mIsBlinkIcon = true;
158 mIsBlinking = true;
159 mBlinkTimer->setSingleShot( false );
160 mBlinkTimer->start( 1000 );
164 void KopeteSystemTray::startBlink()
166 if ( !mMovie )
167 mMovie = KIconLoader::global()->loadMovie( QLatin1String( "newmessage" ), KIconLoader::Panel );
168 // KIconLoader already checked isValid()
169 if ( !mMovie) return;
171 if (!movie())
172 setMovie( mMovie );
173 startMovie();
176 void KopeteSystemTray::stopBlink()
178 if ( mMovie )
179 kDebug( 14010 ) << "stopping movie.";
180 else if ( mBlinkTimer->isActive() )
181 mBlinkTimer->stop();
183 if ( mMovie )
184 mMovie->setPaused(true);
186 mIsBlinkIcon = false;
187 mIsBlinking = false;
188 //setPixmap( mKopeteIcon );
189 slotReevaluateAccountStates();
192 void KopeteSystemTray::slotBlink()
194 setIcon( mIsBlinkIcon ? mKopeteIcon : mBlinkIcon );
196 mIsBlinkIcon = !mIsBlinkIcon;
199 void KopeteSystemTray::slotNewEvent( Kopete::MessageEvent *event )
201 if( Kopete::BehaviorSettings::self()->useMessageStack() )
202 mEventList.prepend( event );
203 else
204 mEventList.append( event );
206 connect(event, SIGNAL(done(Kopete::MessageEvent*)),
207 this, SLOT(slotEventDone(Kopete::MessageEvent*)));
209 // tray animation
210 if ( Kopete::BehaviorSettings::self()->trayflashNotify() )
211 startBlink();
214 void KopeteSystemTray::slotEventDone(Kopete::MessageEvent *event)
216 mEventList.removeAll(event);
218 if(mEventList.isEmpty())
219 stopBlink();
222 void KopeteSystemTray::slotConfigChanged()
224 // kDebug(14010) << "called.";
225 if ( Kopete::BehaviorSettings::self()->showSystemTray() )
226 show();
227 else
228 hide(); // for users without kicker or a similar docking app
231 void KopeteSystemTray::slotReevaluateAccountStates()
233 // If there is a pending message, we don't need to refresh the system tray now.
234 // This function will even be called when the animation will stop.
235 if ( mIsBlinking )
236 return;
238 Kopete::OnlineStatus highestStatus;
239 foreach ( Kopete::Account *account, Kopete::AccountManager::self()->accounts())
241 if ( account->myself() && account->myself()->onlineStatus() > highestStatus )
243 highestStatus = account->myself()->onlineStatus();
247 switch ( highestStatus.status() )
249 case Kopete::OnlineStatus::Unknown:
250 case Kopete::OnlineStatus::Offline:
251 case Kopete::OnlineStatus::Connecting:
253 QImage offlineIcon = mKopeteIcon.pixmap(22,22).toImage();
254 KIconEffect::toGray( offlineIcon, 0.85 );
255 setIcon( QPixmap::fromImage( offlineIcon ) );
256 break;
258 case Kopete::OnlineStatus::Invisible:
260 QPixmap statusOverlay = loadIcon("user-invisible").pixmap(11,11);
261 QPixmap statusIcon = mKopeteIcon.pixmap(22,22);
262 if (!statusIcon.isNull() && !statusOverlay.isNull())
264 QPainter painter(&statusIcon);
265 painter.drawPixmap(QPoint(11,11), statusOverlay);
267 setIcon( statusIcon );
268 break;
270 case Kopete::OnlineStatus::Away:
272 QPixmap statusOverlay = loadIcon("user-away").pixmap(11,11);
273 QPixmap statusIcon = mKopeteIcon.pixmap(22,22);
274 if (!statusIcon.isNull() && !statusOverlay.isNull())
276 QPainter painter(&statusIcon);
277 painter.drawPixmap(QPoint(11,11), statusOverlay);
279 setIcon( statusIcon );
280 break;
282 case Kopete::OnlineStatus::Online:
283 setIcon( mKopeteIcon );
284 break;
289 QString KopeteSystemTray::squashMessage( const Kopete::Message& msg )
291 QString msgText = msg.parsedBody();
293 QRegExp rx( "(<a.*>((http://)?(.+))</a>)" );
294 rx.setMinimal( true );
295 if ( rx.indexIn( msgText ) == -1 )
297 // no URLs in text, just pick the first 30 chars of
298 // the parsed text if necessary. We used parsed text
299 // so that things like "<knuff>" show correctly
300 // Escape it after snipping it to not snip entities
301 msgText =msg.plainBody() ;
302 if( msgText.length() > 30 )
303 msgText = msgText.left( 30 ) + QLatin1String( " ..." );
304 msgText=Kopete::Message::escape(msgText);
306 else
308 QString plainText = msg.plainBody();
309 if ( plainText.length() > 30 )
311 QString fullUrl = rx.cap( 2 );
312 QString shorterUrl;
313 if ( fullUrl.length() > 30 )
315 QString urlWithoutProtocol = rx.cap( 4 );
316 shorterUrl = urlWithoutProtocol.left( 27 )
317 + QLatin1String( "... " );
319 else
321 shorterUrl = fullUrl.left( 27 )
322 + QLatin1String( "... " );
324 // remove message text
325 msgText = QLatin1String( "... " ) +
326 rx.cap( 1 ) +
327 QLatin1String( " ..." );
328 // find last occurrence of URL (the one inside the <a> tag)
329 int revUrlOffset = msgText.lastIndexOf( fullUrl );
330 msgText.replace( revUrlOffset,
331 fullUrl.length(), shorterUrl );
334 return msgText;
337 #include "systemtray.moc"
338 // vim: set noet ts=4 sts=4 sw=4: