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 *************************************************************************
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. *
17 *************************************************************************
20 #include "systemtray.h"
25 #include <QMouseEvent>
30 #include <kaboutdata.h>
31 #include <kactioncollection.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
)
52 s_systemTray
= new KopeteSystemTray( parent
);
57 KopeteSystemTray::KopeteSystemTray(QWidget
* parent
)
58 : KAnimatedSystemTrayIcon(parent
)
62 setToolTip(KGlobal::mainComponent().aboutData()->shortDescription());
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" );
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
) ) );
100 slotReevaluateAccountStates();
104 KopeteSystemTray::~KopeteSystemTray()
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
)
133 // void KopeteSystemTray::contextMenuAboutToShow( KMenu *me )
135 // //kDebug(14010) << "Called.";
136 // emit aboutToShowMenu( me );
139 void KopeteSystemTray::startBlink( const QString
&icon
)
141 startBlink( loadIcon( icon
) );
144 void KopeteSystemTray::startBlink( const QIcon
&icon
)
147 if ( mBlinkTimer
->isActive() == false )
151 mBlinkTimer
->setSingleShot( false );
152 mBlinkTimer
->start( 1000 );
159 mBlinkTimer
->setSingleShot( false );
160 mBlinkTimer
->start( 1000 );
164 void KopeteSystemTray::startBlink()
167 mMovie
= KIconLoader::global()->loadMovie( QLatin1String( "newmessage" ), KIconLoader::Panel
);
168 // KIconLoader already checked isValid()
169 if ( !mMovie
) return;
176 void KopeteSystemTray::stopBlink()
179 kDebug( 14010 ) << "stopping movie.";
180 else if ( mBlinkTimer
->isActive() )
184 mMovie
->setPaused(true);
186 mIsBlinkIcon
= 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
);
204 mEventList
.append( event
);
206 connect(event
, SIGNAL(done(Kopete::MessageEvent
*)),
207 this, SLOT(slotEventDone(Kopete::MessageEvent
*)));
210 if ( Kopete::BehaviorSettings::self()->trayflashNotify() )
214 void KopeteSystemTray::slotEventDone(Kopete::MessageEvent
*event
)
216 mEventList
.removeAll(event
);
218 if(mEventList
.isEmpty())
222 void KopeteSystemTray::slotConfigChanged()
224 // kDebug(14010) << "called.";
225 if ( Kopete::BehaviorSettings::self()->showSystemTray() )
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.
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
) );
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
);
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
);
282 case Kopete::OnlineStatus::Online
:
283 setIcon( mKopeteIcon
);
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
);
308 QString plainText
= msg
.plainBody();
309 if ( plainText
.length() > 30 )
311 QString fullUrl
= rx
.cap( 2 );
313 if ( fullUrl
.length() > 30 )
315 QString urlWithoutProtocol
= rx
.cap( 4 );
316 shorterUrl
= urlWithoutProtocol
.left( 27 )
317 + QLatin1String( "... " );
321 shorterUrl
= fullUrl
.left( 27 )
322 + QLatin1String( "... " );
324 // remove message text
325 msgText
= QLatin1String( "... " ) +
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
);
337 #include "systemtray.moc"
338 // vim: set noet ts=4 sts=4 sw=4: