| 1 |
/**************************************************************************************** |
| 2 |
* Copyright (c) 2003 Stanislav Karchebny <berkus@users.sf.net> * |
| 3 |
* Copyright (c) 2003 Max Howell <max.howell@methylblue.com> * |
| 4 |
* Copyright (c) 2004 Enrico Ros <eros.kde@email.it> * |
| 5 |
* Copyright (c) 2006 Ian Monroe <ian@monroe.nu> * |
| 6 |
* Copyright (c) 2009,2010 Kevin Funk <krf@electrostorm.net> * |
| 7 |
* Copyright (c) 2009 Mark Kretschmann <kretschmann@kde.org> * |
| 8 |
* * |
| 9 |
* This program is free software; you can redistribute it and/or modify it under * |
| 10 |
* the terms of the GNU General Public License as published by the Free Software * |
| 11 |
* Foundation; either version 2 of the License, or (at your option) any later * |
| 12 |
* version. * |
| 13 |
* * |
| 14 |
* This program is distributed in the hope that it will be useful, but WITHOUT ANY * |
| 15 |
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * |
| 16 |
* PARTICULAR PURPOSE. See the GNU General Public License for more details. * |
| 17 |
* * |
| 18 |
* You should have received a copy of the GNU General Public License along with * |
| 19 |
* this program. If not, see <http://www.gnu.org/licenses/>. * |
| 20 |
****************************************************************************************/ |
| 21 |
|
| 22 |
#include "TrayIcon.h" |
| 23 |
|
| 24 |
#include "core/support/Amarok.h" |
| 25 |
#include "core/support/Debug.h" |
| 26 |
#include "EngineController.h" |
| 27 |
#include "amarokconfig.h" |
| 28 |
#include "GlobalCurrentTrackActions.h" |
| 29 |
#include "core/capabilities/CurrentTrackActionsCapability.h" |
| 30 |
#include "playlist/PlaylistActions.h" |
| 31 |
#include "SvgHandler.h" |
| 32 |
#include <KAboutData> |
| 33 |
#include <KAction> |
| 34 |
#include <KCmdLineArgs> |
| 35 |
#include <KLocale> |
| 36 |
#include <KMenu> |
| 37 |
#include <KStandardDirs> |
| 38 |
|
| 39 |
#include <QAction> |
| 40 |
#include <QFontMetrics> |
| 41 |
#include <QPixmap> |
| 42 |
#include <QToolTip> |
| 43 |
|
| 44 |
Amarok::TrayIcon::TrayIcon( QObject *parent ) |
| 45 |
: KStatusNotifierItem( parent ) |
| 46 |
, Engine::EngineObserver( The::engineController() ) |
| 47 |
, m_separator( 0 ) |
| 48 |
{ |
| 49 |
DEBUG_BLOCK |
| 50 |
|
| 51 |
PERF_LOG( "Beginning TrayIcon Constructor" ); |
| 52 |
KActionCollection* const ac = Amarok::actionCollection(); |
| 53 |
|
| 54 |
setStatus( KStatusNotifierItem::Active ); |
| 55 |
|
| 56 |
PERF_LOG( "Before adding actions" ); |
| 57 |
|
| 58 |
#ifdef Q_WS_MAC |
| 59 |
// Add these functions to the dock icon menu in OS X |
| 60 |
extern void qt_mac_set_dock_menu(QMenu *); |
| 61 |
qt_mac_set_dock_menu( contextMenu() ); |
| 62 |
contextMenu()->addAction( ac->action( "playlist_playmedia" ) ); |
| 63 |
contextMenu()->addSeparator(); |
| 64 |
#endif |
| 65 |
|
| 66 |
contextMenu()->addAction( ac->action( "prev" ) ); |
| 67 |
contextMenu()->addAction( ac->action( "play_pause" ) ); |
| 68 |
contextMenu()->addAction( ac->action( "stop" ) ); |
| 69 |
contextMenu()->addAction( ac->action( "next" ) ); |
| 70 |
contextMenu()->setObjectName( "TrayIconContextMenu" ); |
| 71 |
|
| 72 |
PERF_LOG( "Adding system tray icon" ); |
| 73 |
|
| 74 |
setIconByName( "amarok" ); |
| 75 |
|
| 76 |
setupToolTip( true ); |
| 77 |
|
| 78 |
connect( this, SIGNAL( scrollRequested( int, Qt::Orientation ) ), SLOT( slotScrollRequested(int, Qt::Orientation) ) ); |
| 79 |
connect( this, SIGNAL( secondaryActivateRequested( const QPoint & ) ), SLOT( slotActivated() ) ); |
| 80 |
} |
| 81 |
|
| 82 |
void |
| 83 |
Amarok::TrayIcon::setupToolTip( bool updateIcon ) |
| 84 |
{ |
| 85 |
if( m_track ) |
| 86 |
{ |
| 87 |
setToolTipTitle( The::engineController()->prettyNowPlaying() ); |
| 88 |
|
| 89 |
// check if we really need to update the icon (performance tweak) |
| 90 |
if( updateIcon ) |
| 91 |
{ |
| 92 |
if( m_track->album() && m_track->album()->hasImage() ) |
| 93 |
{ |
| 94 |
QPixmap image = The::svgHandler()->imageWithBorder( m_track->album(), KIconLoader::SizeLarge, 5 ); |
| 95 |
setToolTipIconByPixmap( image ); |
| 96 |
} |
| 97 |
else |
| 98 |
{ |
| 99 |
setToolTipIconByName( "amarok" ); |
| 100 |
} |
| 101 |
} |
| 102 |
|
| 103 |
QStringList tooltip; |
| 104 |
|
| 105 |
QString volume; |
| 106 |
if ( The::engineController()->isMuted() ) |
| 107 |
{ |
| 108 |
volume = i18n( "Muted" ); |
| 109 |
} |
| 110 |
else |
| 111 |
{ |
| 112 |
volume = QString( "%1%" ).arg( The::engineController()->volume() ); |
| 113 |
} |
| 114 |
tooltip << QString("<i>%1: %2</i>").arg( i18n( "Volume" ) ).arg( volume ); |
| 115 |
|
| 116 |
const float score = m_track->score(); |
| 117 |
if( score > 0.f ) |
| 118 |
{ |
| 119 |
tooltip << QString( "%1: %2" ).arg( i18n( "Score" ) ).arg( QString::number( score, 'f', 2 ) ); |
| 120 |
} |
| 121 |
|
| 122 |
const int rating = m_track->rating(); |
| 123 |
if( rating > 0 ) |
| 124 |
{ |
| 125 |
QString stars; |
| 126 |
for( int i = 0; i < rating / 2; ++i ) |
| 127 |
stars += QString( "<img src=\"%1\" height=\"%2\" width=\"%3\">" ) |
| 128 |
.arg( KStandardDirs::locate( "data", "amarok/images/star.png" ) ) |
| 129 |
.arg( QFontMetrics( QToolTip::font() ).height() ) |
| 130 |
.arg( QFontMetrics( QToolTip::font() ).height() ); |
| 131 |
if( rating % 2 ) |
| 132 |
stars += QString( "<img src=\"%1\" height=\"%2\" width=\"%3\">" ) |
| 133 |
.arg( KStandardDirs::locate( "data", "amarok/images/smallstar.png" ) ) |
| 134 |
.arg( QFontMetrics( QToolTip::font() ).height() ) |
| 135 |
.arg( QFontMetrics( QToolTip::font() ).height() ); |
| 136 |
|
| 137 |
tooltip << QString( "%1: %2" ).arg( i18n( "Rating" ) ).arg( stars ); |
| 138 |
} |
| 139 |
|
| 140 |
const int count = m_track->playCount(); |
| 141 |
if( count > 0 ) |
| 142 |
{ |
| 143 |
tooltip << QString( "%1: %2" ).arg( i18n( "Play Count" ) ).arg( QString::number( count ) ); |
| 144 |
} |
| 145 |
|
| 146 |
const uint lastPlayed = m_track->lastPlayed(); |
| 147 |
tooltip << QString( "%1: %2" ).arg( i18n( "Last played" ) ).arg( Amarok::verboseTimeSince( lastPlayed ) ); |
| 148 |
|
| 149 |
setToolTipSubTitle( tooltip.join("<br>") ); |
| 150 |
} |
| 151 |
else |
| 152 |
{ |
| 153 |
setToolTipIconByName( "amarok" ); |
| 154 |
setToolTipTitle( KCmdLineArgs::aboutData()->programName() ); |
| 155 |
setToolTipSubTitle( The::engineController()->prettyNowPlaying() ); |
| 156 |
} |
| 157 |
} |
| 158 |
|
| 159 |
void |
| 160 |
Amarok::TrayIcon::slotScrollRequested( int delta, Qt::Orientation orientation ) |
| 161 |
{ |
| 162 |
Q_UNUSED( orientation ) |
| 163 |
|
| 164 |
The::engineController()->increaseVolume( delta / Amarok::VOLUME_SENSITIVITY ); |
| 165 |
} |
| 166 |
|
| 167 |
void |
| 168 |
Amarok::TrayIcon::engineStateChanged( Phonon::State state, Phonon::State /*oldState*/ ) |
| 169 |
{ |
| 170 |
Meta::TrackPtr track = The::engineController()->currentTrack(); |
| 171 |
|
| 172 |
switch( state ) |
| 173 |
{ |
| 174 |
case Phonon::PlayingState: |
| 175 |
if ( m_track ) |
| 176 |
{ |
| 177 |
unsubscribeFrom( m_track ); |
| 178 |
unsubscribeFrom( m_track->album() ); |
| 179 |
} |
| 180 |
m_track = track; |
| 181 |
if ( track ) |
| 182 |
{ |
| 183 |
subscribeTo( track ); |
| 184 |
subscribeTo( track->album() ); |
| 185 |
} |
| 186 |
|
| 187 |
setOverlayIconByName( "media-playback-start" ); |
| 188 |
setupMenu(); |
| 189 |
break; |
| 190 |
|
| 191 |
case Phonon::StoppedState: |
| 192 |
m_track = 0; |
| 193 |
|
| 194 |
setOverlayIconByName( QString() ); |
| 195 |
setupMenu(); // remove custom track actions on stop |
| 196 |
break; |
| 197 |
|
| 198 |
case Phonon::PausedState: |
| 199 |
setOverlayIconByName( "media-playback-pause" ); |
| 200 |
break; |
| 201 |
|
| 202 |
case Phonon::LoadingState: |
| 203 |
case Phonon::ErrorState: |
| 204 |
case Phonon::BufferingState: |
| 205 |
setOverlayIconByName( QString() ); |
| 206 |
break; |
| 207 |
} |
| 208 |
|
| 209 |
setupToolTip( true ); |
| 210 |
} |
| 211 |
|
| 212 |
void |
| 213 |
Amarok::TrayIcon::engineNewTrackPlaying() |
| 214 |
{ |
| 215 |
m_track = The::engineController()->currentTrack(); |
| 216 |
|
| 217 |
setupToolTip( true ); |
| 218 |
setupMenu(); |
| 219 |
} |
| 220 |
|
| 221 |
void |
| 222 |
Amarok::TrayIcon::metadataChanged( Meta::TrackPtr track ) |
| 223 |
{ |
| 224 |
Q_UNUSED( track ) |
| 225 |
|
| 226 |
setupToolTip( false ); |
| 227 |
setupMenu(); |
| 228 |
} |
| 229 |
|
| 230 |
void |
| 231 |
Amarok::TrayIcon::metadataChanged( Meta::AlbumPtr album ) |
| 232 |
{ |
| 233 |
Q_UNUSED( album ) |
| 234 |
|
| 235 |
setupToolTip( true ); |
| 236 |
setupMenu(); |
| 237 |
} |
| 238 |
|
| 239 |
void |
| 240 |
Amarok::TrayIcon::engineVolumeChanged( int percent ) |
| 241 |
{ |
| 242 |
Q_UNUSED( percent ); |
| 243 |
|
| 244 |
setupToolTip( false ); |
| 245 |
} |
| 246 |
|
| 247 |
void |
| 248 |
Amarok::TrayIcon::engineMuteStateChanged( bool mute ) |
| 249 |
{ |
| 250 |
Q_UNUSED( mute ); |
| 251 |
|
| 252 |
setupToolTip( false ); |
| 253 |
} |
| 254 |
|
| 255 |
void |
| 256 |
Amarok::TrayIcon::setupMenu() |
| 257 |
{ |
| 258 |
foreach( QAction* action, m_extraActions ) |
| 259 |
contextMenu()->removeAction( action ); |
| 260 |
|
| 261 |
contextMenu()->removeAction( m_separator ); |
| 262 |
|
| 263 |
delete m_separator; |
| 264 |
|
| 265 |
if( !m_track ) |
| 266 |
return; |
| 267 |
|
| 268 |
m_extraActions.clear(); |
| 269 |
foreach( QAction *action, The::globalCurrentTrackActions()->actions() ) |
| 270 |
m_extraActions.append( action ); |
| 271 |
|
| 272 |
if ( m_track->hasCapabilityInterface( Capabilities::Capability::CurrentTrackActions ) ) |
| 273 |
{ |
| 274 |
Capabilities::CurrentTrackActionsCapability *cac = m_track->create<Capabilities::CurrentTrackActionsCapability>(); |
| 275 |
if( cac ) |
| 276 |
{ |
| 277 |
QList<QAction *> currentTrackActions = cac->customActions(); |
| 278 |
foreach( QAction *action, currentTrackActions ) |
| 279 |
m_extraActions.append( action ); |
| 280 |
} |
| 281 |
delete cac; |
| 282 |
} |
| 283 |
|
| 284 |
if ( m_extraActions.count() > 0 ) |
| 285 |
{ |
| 286 |
// remove the two bottom items, so we can push them to the button again |
| 287 |
contextMenu()->removeAction( actionCollection()->action( "file_quit" ) ); |
| 288 |
contextMenu()->removeAction( actionCollection()->action( "minimizeRestore" ) ); |
| 289 |
|
| 290 |
foreach( QAction* action, m_extraActions ) |
| 291 |
contextMenu()->addAction( action ); |
| 292 |
|
| 293 |
m_separator = contextMenu()->addSeparator(); |
| 294 |
// readd |
| 295 |
contextMenu()->addAction( actionCollection()->action( "minimizeRestore" ) ); |
| 296 |
contextMenu()->addAction( actionCollection()->action( "file_quit" ) ); |
| 297 |
} |
| 298 |
} |
| 299 |
|
| 300 |
void |
| 301 |
Amarok::TrayIcon::slotActivated() |
| 302 |
{ |
| 303 |
The::engineController()->playPause(); |
| 304 |
} |
| 305 |
|
| 306 |
#include "TrayIcon.moc" |