PageRenderTime 307ms CodeModel.GetById 100ms app.highlight 95ms RepoModel.GetById 106ms app.codeStats 1ms

/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
 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"