/src/libtomahawk/widgets/welcomewidget.cpp

http://github.com/tomahawk-player/tomahawk · 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. #include "WelcomeWidget.h"
  21. #include "ui_WelcomeWidget.h"
  22. #include "ViewManager.h"
  23. #include "SourceList.h"
  24. #include "TomahawkSettings.h"
  25. #include "RecentPlaylistsModel.h"
  26. #include "audio/AudioEngine.h"
  27. #include "playlist/AlbumModel.h"
  28. #include "playlist/RecentlyPlayedModel.h"
  29. #include "widgets/OverlayWidget.h"
  30. #include "utils/AnimatedSpinner.h"
  31. #include "utils/TomahawkUtils.h"
  32. #include "utils/Logger.h"
  33. #include "playlist/dynamic/GeneratorInterface.h"
  34. #include "RecentlyPlayedPlaylistsModel.h"
  35. #include <QPainter>
  36. #define HISTORY_PLAYLIST_ITEMS 10
  37. using namespace Tomahawk;
  38. class WelcomeWidgetInterface : public Tomahawk::PlaylistInterface
  39. {
  40. Q_OBJECT
  41. public:
  42. explicit WelcomeWidgetInterface( WelcomeWidget* w )
  43. : PlaylistInterface()
  44. , m_w( w )
  45. {
  46. connect( m_w->ui->tracksView->proxyModel()->playlistInterface().data(), SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ),
  47. SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ) );
  48. connect( m_w->ui->tracksView->proxyModel()->playlistInterface().data(), SIGNAL( shuffleModeChanged( bool ) ),
  49. SIGNAL( shuffleModeChanged( bool ) ) );
  50. }
  51. virtual ~WelcomeWidgetInterface() {}
  52. virtual Tomahawk::PlaylistModes::RepeatMode repeatMode() const { return m_w->ui->tracksView->proxyModel()->playlistInterface()->repeatMode(); }
  53. virtual bool shuffled() const { return m_w->ui->tracksView->proxyModel()->playlistInterface()->shuffled(); }
  54. virtual Tomahawk::query_ptr itemAt( unsigned int position ) const { Q_UNUSED( position ); Q_ASSERT( false ); return Tomahawk::query_ptr(); }
  55. virtual int indexOfResult( const Tomahawk::result_ptr& result ) const { Q_UNUSED( result ); Q_ASSERT( false ); return -1; }
  56. virtual int indexOfQuery( const Tomahawk::query_ptr& query ) const { Q_UNUSED( query ); Q_ASSERT( false ); return -1; }
  57. virtual Tomahawk::result_ptr currentItem() const { return m_w->ui->tracksView->proxyModel()->playlistInterface()->currentItem(); }
  58. virtual Tomahawk::result_ptr siblingItem( int itemsAway, bool readOnly ) { return m_w->ui->tracksView->proxyModel()->playlistInterface()->siblingItem( itemsAway, readOnly ); }
  59. virtual int trackCount() const { return m_w->ui->tracksView->proxyModel()->playlistInterface()->trackCount(); }
  60. virtual QList< Tomahawk::query_ptr > tracks() { return m_w->ui->tracksView->proxyModel()->playlistInterface()->tracks(); }
  61. virtual bool hasChildInterface( Tomahawk::playlistinterface_ptr other )
  62. {
  63. return m_w->ui->tracksView->proxyModel()->playlistInterface() == other ||
  64. m_w->ui->tracksView->proxyModel()->playlistInterface()->hasChildInterface( other ) ||
  65. m_w->ui->additionsView->playlistInterface()->hasChildInterface( other );
  66. }
  67. virtual void setRepeatMode( Tomahawk::PlaylistModes::RepeatMode mode )
  68. {
  69. m_w->ui->tracksView->proxyModel()->playlistInterface()->setRepeatMode( mode );
  70. }
  71. virtual void setShuffled( bool enabled )
  72. {
  73. m_w->ui->tracksView->proxyModel()->playlistInterface()->setShuffled( enabled );
  74. }
  75. private:
  76. WelcomeWidget* m_w;
  77. };
  78. WelcomeWidget::WelcomeWidget( QWidget* parent )
  79. : QWidget( parent )
  80. , ui( new Ui::WelcomeWidget )
  81. {
  82. ui->setupUi( this );
  83. ui->splitter_2->setStretchFactor( 0, 3 );
  84. ui->splitter_2->setStretchFactor( 1, 1 );
  85. ui->splitter->setChildrenCollapsible( false );
  86. ui->splitter_2->setChildrenCollapsible( false );
  87. RecentPlaylistsModel* model = new RecentPlaylistsModel( HISTORY_PLAYLIST_ITEMS, this );
  88. ui->playlistWidget->setFrameShape( QFrame::NoFrame );
  89. ui->playlistWidget->setAttribute( Qt::WA_MacShowFocusRect, 0 );
  90. TomahawkUtils::unmarginLayout( layout() );
  91. TomahawkUtils::unmarginLayout( ui->verticalLayout->layout() );
  92. TomahawkUtils::unmarginLayout( ui->verticalLayout_2->layout() );
  93. TomahawkUtils::unmarginLayout( ui->verticalLayout_3->layout() );
  94. TomahawkUtils::unmarginLayout( ui->verticalLayout_4->layout() );
  95. ui->playlistWidget->setItemDelegate( new PlaylistDelegate() );
  96. ui->playlistWidget->setModel( model );
  97. ui->playlistWidget->overlay()->resize( 380, 86 );
  98. ui->playlistWidget->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
  99. updatePlaylists();
  100. m_tracksModel = new RecentlyPlayedModel( ui->tracksView );
  101. ui->tracksView->proxyModel()->setStyle( PlayableProxyModel::ShortWithAvatars );
  102. ui->tracksView->overlay()->setEnabled( false );
  103. ui->tracksView->setPlaylistModel( m_tracksModel );
  104. m_tracksModel->setSource( source_ptr() );
  105. QFont f;
  106. f.setBold( true );
  107. QFontMetrics fm( f );
  108. ui->tracksView->setMinimumWidth( fm.width( tr( "Recently played tracks" ) ) * 2 );
  109. m_recentAlbumsModel = new AlbumModel( ui->additionsView );
  110. ui->additionsView->setPlayableModel( m_recentAlbumsModel );
  111. ui->additionsView->proxyModel()->sort( -1 );
  112. m_playlistInterface = playlistinterface_ptr( new WelcomeWidgetInterface( this ) );
  113. connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) );
  114. connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) );
  115. connect( ui->playlistWidget, SIGNAL( activated( QModelIndex ) ), SLOT( onPlaylistActivated( QModelIndex ) ) );
  116. connect( model, SIGNAL( emptinessChanged( bool ) ), this, SLOT( updatePlaylists() ) );
  117. }
  118. WelcomeWidget::~WelcomeWidget()
  119. {
  120. delete ui;
  121. }
  122. void
  123. WelcomeWidget::loadData()
  124. {
  125. m_recentAlbumsModel->addFilteredCollection( collection_ptr(), 20, DatabaseCommand_AllAlbums::ModificationTime, true );
  126. }
  127. Tomahawk::playlistinterface_ptr
  128. WelcomeWidget::playlistInterface() const
  129. {
  130. return m_playlistInterface;
  131. }
  132. bool
  133. WelcomeWidget::jumpToCurrentTrack()
  134. {
  135. if ( ui->tracksView->jumpToCurrentTrack() )
  136. return true;
  137. if ( ui->additionsView->jumpToCurrentTrack() )
  138. return true;
  139. return false;
  140. }
  141. bool
  142. WelcomeWidget::isBeingPlayed() const
  143. {
  144. if ( ui->additionsView->isBeingPlayed() )
  145. return true;
  146. return AudioEngine::instance()->currentTrackPlaylist() == ui->tracksView->playlistInterface();
  147. }
  148. void
  149. WelcomeWidget::onSourcesReady()
  150. {
  151. foreach ( const source_ptr& source, SourceList::instance()->sources() )
  152. onSourceAdded( source );
  153. }
  154. void
  155. WelcomeWidget::onSourceAdded( const Tomahawk::source_ptr& source )
  156. {
  157. connect( source->collection().data(), SIGNAL( changed() ), SLOT( updateRecentAdditions() ), Qt::UniqueConnection );
  158. }
  159. void
  160. WelcomeWidget::updateRecentAdditions()
  161. {
  162. m_recentAlbumsModel->addFilteredCollection( collection_ptr(), 20, DatabaseCommand_AllAlbums::ModificationTime, true );
  163. }
  164. void
  165. WelcomeWidget::updatePlaylists()
  166. {
  167. int num = ui->playlistWidget->model()->rowCount( QModelIndex() );
  168. if ( num == 0 )
  169. {
  170. ui->playlistWidget->overlay()->setText( tr( "No recently created playlists in your network." ) );
  171. ui->playlistWidget->overlay()->show();
  172. }
  173. else
  174. ui->playlistWidget->overlay()->hide();
  175. }
  176. void
  177. WelcomeWidget::onPlaylistActivated( const QModelIndex& item )
  178. {
  179. Tomahawk::playlist_ptr pl = item.data( RecentlyPlayedPlaylistsModel::PlaylistRole ).value< Tomahawk::playlist_ptr >();
  180. if( Tomahawk::dynplaylist_ptr dynplaylist = pl.dynamicCast< Tomahawk::DynamicPlaylist >() )
  181. ViewManager::instance()->show( dynplaylist );
  182. else
  183. ViewManager::instance()->show( pl );
  184. }
  185. void
  186. WelcomeWidget::changeEvent( QEvent* e )
  187. {
  188. QWidget::changeEvent( e );
  189. switch ( e->type() )
  190. {
  191. case QEvent::LanguageChange:
  192. ui->retranslateUi( this );
  193. break;
  194. default:
  195. break;
  196. }
  197. }
  198. QSize
  199. PlaylistDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
  200. {
  201. Q_UNUSED( option );
  202. Q_UNUSED( index );
  203. // Calculates the size for the bold line + 3 normal lines + margins
  204. int height = 2 * 6; // margins
  205. QFont font = option.font;
  206. QFontMetrics fm1( font );
  207. font.setPointSize( TomahawkUtils::defaultFontSize() - 1 );
  208. height += fm1.height() * 3;
  209. font.setPointSize( TomahawkUtils::defaultFontSize() );
  210. QFontMetrics fm2( font );
  211. height += fm2.height();
  212. return QSize( 0, height );
  213. }
  214. void
  215. PlaylistDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
  216. {
  217. QStyleOptionViewItemV4 opt = option;
  218. initStyleOption( &opt, QModelIndex() );
  219. qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter );
  220. if ( option.state & QStyle::State_Selected && option.state & QStyle::State_Active )
  221. {
  222. opt.palette.setColor( QPalette::Text, opt.palette.color( QPalette::HighlightedText ) );
  223. }
  224. painter->save();
  225. painter->setRenderHint( QPainter::Antialiasing );
  226. painter->setPen( opt.palette.color( QPalette::Text ) );
  227. QTextOption to;
  228. to.setAlignment( Qt::AlignCenter );
  229. QFont font = opt.font;
  230. font.setPointSize( TomahawkUtils::defaultFontSize() - 1 );
  231. QFont boldFont = font;
  232. boldFont.setBold( true );
  233. boldFont.setPointSize( TomahawkUtils::defaultFontSize() );
  234. QFontMetrics boldFontMetrics( boldFont );
  235. QFont figFont = boldFont;
  236. figFont.setPointSize( TomahawkUtils::defaultFontSize() - 1 );
  237. QPixmap icon;
  238. RecentlyPlayedPlaylistsModel::PlaylistTypes type = (RecentlyPlayedPlaylistsModel::PlaylistTypes)index.data( RecentlyPlayedPlaylistsModel::PlaylistTypeRole ).toInt();
  239. if( type == RecentlyPlayedPlaylistsModel::StaticPlaylist )
  240. icon = m_playlistIcon;
  241. else if( type == RecentlyPlayedPlaylistsModel::AutoPlaylist )
  242. icon = m_autoIcon;
  243. else if( type == RecentlyPlayedPlaylistsModel::Station )
  244. icon = m_stationIcon;
  245. QRect pixmapRect = option.rect.adjusted( 10, 14, -option.rect.width() + option.rect.height() - 18, -14 );
  246. icon = icon.scaled( pixmapRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
  247. painter->drawPixmap( pixmapRect, icon );
  248. if ( type != RecentlyPlayedPlaylistsModel::Station )
  249. {
  250. painter->save();
  251. painter->setFont( figFont );
  252. QString tracks = index.data( RecentlyPlayedPlaylistsModel::TrackCountRole ).toString();
  253. int width = painter->fontMetrics().width( tracks );
  254. // int bottomEdge = pixmapRect
  255. // right edge 10px past right edge of pixmapRect
  256. // bottom edge flush with bottom of pixmap
  257. QRect rect( pixmapRect.right() - width, 0, width - 8, 0 );
  258. rect.adjust( -2, 0, 0, 0 );
  259. rect.setTop( pixmapRect.bottom() - painter->fontMetrics().height() - 1 );
  260. rect.setBottom( pixmapRect.bottom() + 1 );
  261. QColor figColor( "#464b55" );
  262. painter->setPen( figColor );
  263. painter->setBrush( figColor );
  264. TomahawkUtils::drawBackgroundAndNumbers( painter, tracks, rect );
  265. painter->restore();
  266. }
  267. 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 );
  268. QPixmap avatar = index.data( RecentlyPlayedPlaylistsModel::PlaylistRole ).value< Tomahawk::playlist_ptr >()->author()->avatar( Source::FancyStyle, r.size() );
  269. if ( avatar.isNull() )
  270. avatar = m_defaultAvatar;
  271. painter->drawPixmap( r, avatar );
  272. painter->setFont( font );
  273. QString author = index.data( RecentlyPlayedPlaylistsModel::PlaylistRole ).value< Tomahawk::playlist_ptr >()->author()->friendlyName();
  274. if ( author.indexOf( '@' ) > 0 )
  275. author = author.mid( 0, author.indexOf( '@' ) );
  276. const int w = painter->fontMetrics().width( author ) + 2;
  277. QRect avatarNameRect( opt.rect.width() - 10 - w, r.bottom(), w, opt.rect.bottom() - r.bottom() );
  278. painter->drawText( avatarNameRect, author, QTextOption( Qt::AlignCenter ) );
  279. const int leftEdge = opt.rect.width() - qMin( avatarNameRect.left(), r.left() );
  280. QString descText;
  281. if ( type == RecentlyPlayedPlaylistsModel::Station )
  282. {
  283. descText = index.data( RecentlyPlayedPlaylistsModel::DynamicPlaylistRole ).value< Tomahawk::dynplaylist_ptr >()->generator()->sentenceSummary();
  284. }
  285. else
  286. {
  287. descText = index.data( RecentlyPlayedPlaylistsModel::ArtistRole ).toString();
  288. }
  289. QColor c = painter->pen().color();
  290. if ( !( option.state & QStyle::State_Selected && option.state & QStyle::State_Active ) )
  291. {
  292. painter->setPen( QColor( Qt::gray ).darker() );
  293. }
  294. QRect rectText = option.rect.adjusted( option.fontMetrics.height() * 4.5, boldFontMetrics.height() + 6, -leftEdge - 10, -8 );
  295. #ifdef Q_WS_MAC
  296. rectText.adjust( 0, 1, 0, 0 );
  297. #elif defined Q_WS_WIN
  298. rectText.adjust( 0, 2, 0, 0 );
  299. #endif
  300. painter->drawText( rectText, descText );
  301. painter->setPen( c );
  302. painter->setFont( font );
  303. painter->setFont( boldFont );
  304. painter->drawText( option.rect.adjusted( option.fontMetrics.height() * 4, 6, -100, -option.rect.height() + boldFontMetrics.height() + 6 ), index.data().toString() );
  305. painter->restore();
  306. }
  307. PlaylistWidget::PlaylistWidget( QWidget* parent )
  308. : QListView( parent )
  309. {
  310. m_overlay = new OverlayWidget( this );
  311. /* LoadingSpinner* spinner = */ new LoadingSpinner( this );
  312. }
  313. void
  314. PlaylistWidget::setModel( QAbstractItemModel* model )
  315. {
  316. QListView::setModel( model );
  317. emit modelChanged();
  318. }
  319. #include "WelcomeWidget.moc"