/src/libtomahawk/widgets/welcomewidget.cpp
C++ | 404 lines | 296 code | 85 blank | 23 comment | 27 complexity | bc6faefcbd59ee45c10c44070ad56c48 MD5 | raw file
1/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> === 2 * 3 * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org> 4 * Copyright 2011, Leo Franchi <lfranchi@kde.org> 5 * Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org> 6 * 7 * Tomahawk is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * Tomahawk is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21#include "WelcomeWidget.h" 22#include "ui_WelcomeWidget.h" 23 24#include "ViewManager.h" 25#include "SourceList.h" 26#include "TomahawkSettings.h" 27#include "RecentPlaylistsModel.h" 28 29#include "audio/AudioEngine.h" 30#include "playlist/AlbumModel.h" 31#include "playlist/RecentlyPlayedModel.h" 32#include "widgets/OverlayWidget.h" 33#include "utils/AnimatedSpinner.h" 34#include "utils/TomahawkUtils.h" 35#include "utils/Logger.h" 36#include "playlist/dynamic/GeneratorInterface.h" 37#include "RecentlyPlayedPlaylistsModel.h" 38 39#include <QPainter> 40 41 42#define HISTORY_PLAYLIST_ITEMS 10 43 44using namespace Tomahawk; 45 46 47class WelcomeWidgetInterface : public Tomahawk::PlaylistInterface 48{ 49 Q_OBJECT 50public: 51 explicit WelcomeWidgetInterface( WelcomeWidget* w ) 52 : PlaylistInterface() 53 , m_w( w ) 54 { 55 connect( m_w->ui->tracksView->proxyModel()->playlistInterface().data(), SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ), 56 SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ) ); 57 58 connect( m_w->ui->tracksView->proxyModel()->playlistInterface().data(), SIGNAL( shuffleModeChanged( bool ) ), 59 SIGNAL( shuffleModeChanged( bool ) ) ); 60 } 61 virtual ~WelcomeWidgetInterface() {} 62 63 virtual Tomahawk::PlaylistModes::RepeatMode repeatMode() const { return m_w->ui->tracksView->proxyModel()->playlistInterface()->repeatMode(); } 64 virtual bool shuffled() const { return m_w->ui->tracksView->proxyModel()->playlistInterface()->shuffled(); } 65 66 virtual Tomahawk::query_ptr itemAt( unsigned int position ) const { Q_UNUSED( position ); Q_ASSERT( false ); return Tomahawk::query_ptr(); } 67 virtual int indexOfResult( const Tomahawk::result_ptr& result ) const { Q_UNUSED( result ); Q_ASSERT( false ); return -1; } 68 virtual int indexOfQuery( const Tomahawk::query_ptr& query ) const { Q_UNUSED( query ); Q_ASSERT( false ); return -1; } 69 virtual Tomahawk::result_ptr currentItem() const { return m_w->ui->tracksView->proxyModel()->playlistInterface()->currentItem(); } 70 virtual Tomahawk::result_ptr siblingItem( int itemsAway, bool readOnly ) { return m_w->ui->tracksView->proxyModel()->playlistInterface()->siblingItem( itemsAway, readOnly ); } 71 virtual int trackCount() const { return m_w->ui->tracksView->proxyModel()->playlistInterface()->trackCount(); } 72 virtual QList< Tomahawk::query_ptr > tracks() { return m_w->ui->tracksView->proxyModel()->playlistInterface()->tracks(); } 73 74 virtual bool hasChildInterface( Tomahawk::playlistinterface_ptr other ) 75 { 76 return m_w->ui->tracksView->proxyModel()->playlistInterface() == other || 77 m_w->ui->tracksView->proxyModel()->playlistInterface()->hasChildInterface( other ) || 78 m_w->ui->additionsView->playlistInterface()->hasChildInterface( other ); 79 } 80 81 virtual void setRepeatMode( Tomahawk::PlaylistModes::RepeatMode mode ) 82 { 83 m_w->ui->tracksView->proxyModel()->playlistInterface()->setRepeatMode( mode ); 84 } 85 86 virtual void setShuffled( bool enabled ) 87 { 88 m_w->ui->tracksView->proxyModel()->playlistInterface()->setShuffled( enabled ); 89 } 90 91private: 92 WelcomeWidget* m_w; 93 94}; 95 96 97WelcomeWidget::WelcomeWidget( QWidget* parent ) 98 : QWidget( parent ) 99 , ui( new Ui::WelcomeWidget ) 100{ 101 ui->setupUi( this ); 102 103 ui->splitter_2->setStretchFactor( 0, 3 ); 104 ui->splitter_2->setStretchFactor( 1, 1 ); 105 ui->splitter->setChildrenCollapsible( false ); 106 ui->splitter_2->setChildrenCollapsible( false ); 107 108 RecentPlaylistsModel* model = new RecentPlaylistsModel( HISTORY_PLAYLIST_ITEMS, this ); 109 110 ui->playlistWidget->setFrameShape( QFrame::NoFrame ); 111 ui->playlistWidget->setAttribute( Qt::WA_MacShowFocusRect, 0 ); 112 113 TomahawkUtils::unmarginLayout( layout() ); 114 TomahawkUtils::unmarginLayout( ui->verticalLayout->layout() ); 115 TomahawkUtils::unmarginLayout( ui->verticalLayout_2->layout() ); 116 TomahawkUtils::unmarginLayout( ui->verticalLayout_3->layout() ); 117 TomahawkUtils::unmarginLayout( ui->verticalLayout_4->layout() ); 118 119 ui->playlistWidget->setItemDelegate( new PlaylistDelegate() ); 120 ui->playlistWidget->setModel( model ); 121 ui->playlistWidget->overlay()->resize( 380, 86 ); 122 ui->playlistWidget->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); 123 updatePlaylists(); 124 125 m_tracksModel = new RecentlyPlayedModel( ui->tracksView ); 126 ui->tracksView->proxyModel()->setStyle( PlayableProxyModel::ShortWithAvatars ); 127 ui->tracksView->overlay()->setEnabled( false ); 128 ui->tracksView->setPlaylistModel( m_tracksModel ); 129 m_tracksModel->setSource( source_ptr() ); 130 131 QFont f; 132 f.setBold( true ); 133 QFontMetrics fm( f ); 134 ui->tracksView->setMinimumWidth( fm.width( tr( "Recently played tracks" ) ) * 2 ); 135 136 m_recentAlbumsModel = new AlbumModel( ui->additionsView ); 137 ui->additionsView->setPlayableModel( m_recentAlbumsModel ); 138 ui->additionsView->proxyModel()->sort( -1 ); 139 140 m_playlistInterface = playlistinterface_ptr( new WelcomeWidgetInterface( this ) ); 141 142 connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) ); 143 connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) ); 144 connect( ui->playlistWidget, SIGNAL( activated( QModelIndex ) ), SLOT( onPlaylistActivated( QModelIndex ) ) ); 145 connect( model, SIGNAL( emptinessChanged( bool ) ), this, SLOT( updatePlaylists() ) ); 146} 147 148 149WelcomeWidget::~WelcomeWidget() 150{ 151 delete ui; 152} 153 154 155void 156WelcomeWidget::loadData() 157{ 158 m_recentAlbumsModel->addFilteredCollection( collection_ptr(), 20, DatabaseCommand_AllAlbums::ModificationTime, true ); 159} 160 161 162Tomahawk::playlistinterface_ptr 163WelcomeWidget::playlistInterface() const 164{ 165 return m_playlistInterface; 166} 167 168 169bool 170WelcomeWidget::jumpToCurrentTrack() 171{ 172 if ( ui->tracksView->jumpToCurrentTrack() ) 173 return true; 174 175 if ( ui->additionsView->jumpToCurrentTrack() ) 176 return true; 177 178 return false; 179} 180 181 182bool 183WelcomeWidget::isBeingPlayed() const 184{ 185 if ( ui->additionsView->isBeingPlayed() ) 186 return true; 187 188 return AudioEngine::instance()->currentTrackPlaylist() == ui->tracksView->playlistInterface(); 189} 190 191 192void 193WelcomeWidget::onSourcesReady() 194{ 195 foreach ( const source_ptr& source, SourceList::instance()->sources() ) 196 onSourceAdded( source ); 197} 198 199 200void 201WelcomeWidget::onSourceAdded( const Tomahawk::source_ptr& source ) 202{ 203 connect( source->collection().data(), SIGNAL( changed() ), SLOT( updateRecentAdditions() ), Qt::UniqueConnection ); 204} 205 206 207void 208WelcomeWidget::updateRecentAdditions() 209{ 210 m_recentAlbumsModel->addFilteredCollection( collection_ptr(), 20, DatabaseCommand_AllAlbums::ModificationTime, true ); 211} 212 213 214void 215WelcomeWidget::updatePlaylists() 216{ 217 int num = ui->playlistWidget->model()->rowCount( QModelIndex() ); 218 if ( num == 0 ) 219 { 220 ui->playlistWidget->overlay()->setText( tr( "No recently created playlists in your network." ) ); 221 ui->playlistWidget->overlay()->show(); 222 } 223 else 224 ui->playlistWidget->overlay()->hide(); 225} 226 227 228void 229WelcomeWidget::onPlaylistActivated( const QModelIndex& item ) 230{ 231 Tomahawk::playlist_ptr pl = item.data( RecentlyPlayedPlaylistsModel::PlaylistRole ).value< Tomahawk::playlist_ptr >(); 232 if( Tomahawk::dynplaylist_ptr dynplaylist = pl.dynamicCast< Tomahawk::DynamicPlaylist >() ) 233 ViewManager::instance()->show( dynplaylist ); 234 else 235 ViewManager::instance()->show( pl ); 236} 237 238 239void 240WelcomeWidget::changeEvent( QEvent* e ) 241{ 242 QWidget::changeEvent( e ); 243 switch ( e->type() ) 244 { 245 case QEvent::LanguageChange: 246 ui->retranslateUi( this ); 247 break; 248 249 default: 250 break; 251 } 252} 253 254 255QSize 256PlaylistDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const 257{ 258 Q_UNUSED( option ); 259 Q_UNUSED( index ); 260 261 // Calculates the size for the bold line + 3 normal lines + margins 262 int height = 2 * 6; // margins 263 QFont font = option.font; 264 QFontMetrics fm1( font ); 265 font.setPointSize( TomahawkUtils::defaultFontSize() - 1 ); 266 height += fm1.height() * 3; 267 font.setPointSize( TomahawkUtils::defaultFontSize() ); 268 QFontMetrics fm2( font ); 269 height += fm2.height(); 270 271 return QSize( 0, height ); 272} 273 274 275void 276PlaylistDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const 277{ 278 QStyleOptionViewItemV4 opt = option; 279 initStyleOption( &opt, QModelIndex() ); 280 qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter ); 281 282 if ( option.state & QStyle::State_Selected && option.state & QStyle::State_Active ) 283 { 284 opt.palette.setColor( QPalette::Text, opt.palette.color( QPalette::HighlightedText ) ); 285 } 286 287 painter->save(); 288 painter->setRenderHint( QPainter::Antialiasing ); 289 painter->setPen( opt.palette.color( QPalette::Text ) ); 290 291 QTextOption to; 292 to.setAlignment( Qt::AlignCenter ); 293 QFont font = opt.font; 294 font.setPointSize( TomahawkUtils::defaultFontSize() - 1 ); 295 296 QFont boldFont = font; 297 boldFont.setBold( true ); 298 boldFont.setPointSize( TomahawkUtils::defaultFontSize() ); 299 QFontMetrics boldFontMetrics( boldFont ); 300 301 QFont figFont = boldFont; 302 figFont.setPointSize( TomahawkUtils::defaultFontSize() - 1 ); 303 304 QPixmap icon; 305 RecentlyPlayedPlaylistsModel::PlaylistTypes type = (RecentlyPlayedPlaylistsModel::PlaylistTypes)index.data( RecentlyPlayedPlaylistsModel::PlaylistTypeRole ).toInt(); 306 if( type == RecentlyPlayedPlaylistsModel::StaticPlaylist ) 307 icon = m_playlistIcon; 308 else if( type == RecentlyPlayedPlaylistsModel::AutoPlaylist ) 309 icon = m_autoIcon; 310 else if( type == RecentlyPlayedPlaylistsModel::Station ) 311 icon = m_stationIcon; 312 313 QRect pixmapRect = option.rect.adjusted( 10, 14, -option.rect.width() + option.rect.height() - 18, -14 ); 314 icon = icon.scaled( pixmapRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation ); 315 painter->drawPixmap( pixmapRect, icon ); 316 317 if ( type != RecentlyPlayedPlaylistsModel::Station ) 318 { 319 painter->save(); 320 painter->setFont( figFont ); 321 QString tracks = index.data( RecentlyPlayedPlaylistsModel::TrackCountRole ).toString(); 322 int width = painter->fontMetrics().width( tracks ); 323// int bottomEdge = pixmapRect 324 // right edge 10px past right edge of pixmapRect 325 // bottom edge flush with bottom of pixmap 326 QRect rect( pixmapRect.right() - width, 0, width - 8, 0 ); 327 rect.adjust( -2, 0, 0, 0 ); 328 rect.setTop( pixmapRect.bottom() - painter->fontMetrics().height() - 1 ); 329 rect.setBottom( pixmapRect.bottom() + 1 ); 330 331 QColor figColor( "#464b55" ); 332 painter->setPen( figColor ); 333 painter->setBrush( figColor ); 334 335 TomahawkUtils::drawBackgroundAndNumbers( painter, tracks, rect ); 336 painter->restore(); 337 } 338 339 QRect r( option.rect.width() - option.fontMetrics.height() * 2.5 - 10, option.rect.top() + option.rect.height() / 3 - option.fontMetrics.height(), option.fontMetrics.height() * 2.5, option.fontMetrics.height() * 2.5 ); 340 QPixmap avatar = index.data( RecentlyPlayedPlaylistsModel::PlaylistRole ).value< Tomahawk::playlist_ptr >()->author()->avatar( Source::FancyStyle, r.size() ); 341 if ( avatar.isNull() ) 342 avatar = m_defaultAvatar; 343 painter->drawPixmap( r, avatar ); 344 345 painter->setFont( font ); 346 QString author = index.data( RecentlyPlayedPlaylistsModel::PlaylistRole ).value< Tomahawk::playlist_ptr >()->author()->friendlyName(); 347 if ( author.indexOf( '@' ) > 0 ) 348 author = author.mid( 0, author.indexOf( '@' ) ); 349 350 const int w = painter->fontMetrics().width( author ) + 2; 351 QRect avatarNameRect( opt.rect.width() - 10 - w, r.bottom(), w, opt.rect.bottom() - r.bottom() ); 352 painter->drawText( avatarNameRect, author, QTextOption( Qt::AlignCenter ) ); 353 354 const int leftEdge = opt.rect.width() - qMin( avatarNameRect.left(), r.left() ); 355 QString descText; 356 if ( type == RecentlyPlayedPlaylistsModel::Station ) 357 { 358 descText = index.data( RecentlyPlayedPlaylistsModel::DynamicPlaylistRole ).value< Tomahawk::dynplaylist_ptr >()->generator()->sentenceSummary(); 359 } 360 else 361 { 362 descText = index.data( RecentlyPlayedPlaylistsModel::ArtistRole ).toString(); 363 } 364 365 QColor c = painter->pen().color(); 366 if ( !( option.state & QStyle::State_Selected && option.state & QStyle::State_Active ) ) 367 { 368 painter->setPen( QColor( Qt::gray ).darker() ); 369 } 370 371 QRect rectText = option.rect.adjusted( option.fontMetrics.height() * 4.5, boldFontMetrics.height() + 6, -leftEdge - 10, -8 ); 372#ifdef Q_WS_MAC 373 rectText.adjust( 0, 1, 0, 0 ); 374#elif defined Q_WS_WIN 375 rectText.adjust( 0, 2, 0, 0 ); 376#endif 377 378 painter->drawText( rectText, descText ); 379 painter->setPen( c ); 380 painter->setFont( font ); 381 382 painter->setFont( boldFont ); 383 painter->drawText( option.rect.adjusted( option.fontMetrics.height() * 4, 6, -100, -option.rect.height() + boldFontMetrics.height() + 6 ), index.data().toString() ); 384 385 painter->restore(); 386} 387 388 389PlaylistWidget::PlaylistWidget( QWidget* parent ) 390 : QListView( parent ) 391{ 392 m_overlay = new OverlayWidget( this ); 393 /* LoadingSpinner* spinner = */ new LoadingSpinner( this ); 394} 395 396 397void 398PlaylistWidget::setModel( QAbstractItemModel* model ) 399{ 400 QListView::setModel( model ); 401 emit modelChanged(); 402} 403 404#include "WelcomeWidget.moc"