Example #1
0
void
LovedTracksItem::activate()
{
    if ( !m_lovedTracksPage )
    {
        SourceItem* par = dynamic_cast< SourceItem* >( parent() );
        PlaylistViewPage* pv = new PlaylistViewPage( ViewManager::instance()->widget() );
        pv->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::LovedPlaylist, TomahawkUtils::Original, QSize( 128, 128 ) ) );

        TopLovedTracksModel* raModel = new TopLovedTracksModel( pv );
        raModel->setTitle( text() );

        TrackItemDelegate* del = new TrackItemDelegate( TrackItemDelegate::LovedTracks, pv->view()->trackView(), pv->view()->trackView()->proxyModel() );
        pv->view()->trackView()->setPlaylistItemDelegate( del );

        pv->view()->trackView()->setEmptyTip( tr( "Sorry, we could not find any of your Favorites!" ) );
        if ( !par )
        {
            raModel->setDescription( tr( "The most loved tracks from all your friends" ) );
            pv->view()->setGuid( QString( "lovedtracks" ) );
        }
        else
        {
            if ( par->source()->isLocal() )
                raModel->setDescription( tr( "All of your loved tracks" ) );
            else
                raModel->setDescription( tr( "All of %1's loved tracks" ).arg( par->source()->friendlyName() ) );

            pv->view()->setGuid( QString( "lovedtracks/%1" ).arg( par->source()->nodeId() ) );
        }

        pv->view()->trackView()->setPlayableModel( raModel );
        raModel->setSource( !par ? source_ptr() : par->source() );

        m_lovedTracksPage = pv;
    }

    ViewManager::instance()->show( m_lovedTracksPage );
    model()->linkSourceItemToPage( this, m_lovedTracksPage );
}
Example #2
0
QSize
SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
    SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
    SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );

    if ( type == SourcesModel::Source || type == SourcesModel::ScriptCollection )
    {
        SourceItem* colItem = qobject_cast< SourceItem* >( item );
        return QSize( option.rect.width(), ( colItem && colItem->source() && colItem->source()->isLocal() ) ? 0 : option.fontMetrics.height() * 3.2 );
    }
    else if ( type == SourcesModel::Divider )
    {
        return QSize( option.rect.width(), TomahawkUtils::DpiScaler::scaledY( m_parent, 6 ) );
    }
    else if ( type == SourcesModel::Group )
    {
        const int groupSpacer = index.row() > 0 ? option.fontMetrics.height() * 2.5 : option.fontMetrics.height() * 1.8;
        return QSize( option.rect.width(), option.fontMetrics.height() + groupSpacer );
    }
    else
        return QSize( option.rect.width(), option.fontMetrics.height() * 1.8 ); //QStyledItemDelegate::sizeHint( option, index ) );
}
Example #3
0
void
SourceTreeView::setupMenus()
{
    m_playlistMenu.clear();
    m_roPlaylistMenu.clear();
    m_latchMenu.clear();
    m_privacyMenu.clear();

    bool readonly = true;
    SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();

    if ( type == SourcesModel::StaticPlaylist || type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station )
    {
        const PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex );
        const playlist_ptr playlist = item->playlist();

        if ( !playlist.isNull() )
        {
            readonly = !playlist->author()->isLocal();
        }
    }

    QAction* latchOnAction = ActionCollection::instance()->getAction( "latchOn" );
    m_latchMenu.addAction( latchOnAction );

    m_privacyMenu.addAction( ActionCollection::instance()->getAction( "togglePrivacy" ) );

    if ( type == SourcesModel::Collection )
    {
        SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex );
        source_ptr source = item->source();
        if ( !source.isNull() )
        {
            if ( m_latchManager->isLatched( source ) )
            {
                QAction *latchOffAction = ActionCollection::instance()->getAction( "latchOff" );
                m_latchMenu.addAction( latchOffAction );
                connect( latchOffAction, SIGNAL( triggered() ), SLOT( latchOff() ) );
                m_latchMenu.addSeparator();
                QAction *latchRealtimeAction = ActionCollection::instance()->getAction( "realtimeFollowingAlong" );
                latchRealtimeAction->setChecked( source->playlistInterface()->latchMode() == Tomahawk::PlaylistModes::RealTime );
                m_latchMenu.addAction( latchRealtimeAction );
                connect( latchRealtimeAction, SIGNAL( toggled( bool ) ), SLOT( latchModeToggled( bool ) ) );
            }
        }
    }

    QAction *loadPlaylistAction = ActionCollection::instance()->getAction( "loadPlaylist" );
    m_playlistMenu.addAction( loadPlaylistAction );
    QAction *renamePlaylistAction = ActionCollection::instance()->getAction( "renamePlaylist" );
    m_playlistMenu.addAction( renamePlaylistAction );
    m_playlistMenu.addSeparator();

    QAction *copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) );
    QAction *deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) );

    QString addToText;
    if ( type == SourcesModel::StaticPlaylist )
        addToText = tr( "Add to my Playlists" );
    if ( type == SourcesModel::AutomaticPlaylist )
        addToText = tr( "Add to my Automatic Playlists" );
    else if ( type == SourcesModel::Station )
        addToText = tr( "Add to my Stations" );

    QAction *addToLocalAction = m_roPlaylistMenu.addAction( addToText );

    m_roPlaylistMenu.addAction( copyPlaylistAction );
    deletePlaylistAction->setEnabled( !readonly );
    renamePlaylistAction->setEnabled( !readonly );
    addToLocalAction->setEnabled( readonly );

    // Handle any custom actions registered for playlists
    if ( type == SourcesModel::StaticPlaylist && !readonly &&
        !ActionCollection::instance()->getAction( ActionCollection::LocalPlaylists ).isEmpty() )
    {
        m_playlistMenu.addSeparator();

        const PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex );
        const playlist_ptr playlist = item->playlist();
        foreach ( QAction* action, ActionCollection::instance()->getAction( ActionCollection::LocalPlaylists ) )
        {
            if ( QObject* notifier = ActionCollection::instance()->actionNotifier( action ) )
            {
                QMetaObject::invokeMethod( notifier, "aboutToShow", Qt::DirectConnection, Q_ARG( QAction*, action ), Q_ARG( Tomahawk::playlist_ptr, playlist ) );
            }

            action->setProperty( "payload", QVariant::fromValue< playlist_ptr >( playlist ) );
            m_playlistMenu.addAction( action );
        }
Example #4
0
void
SourceTreeView::setupMenus()
{
    m_playlistMenu.clear();
    m_roPlaylistMenu.clear();
    m_latchMenu.clear();
    m_privacyMenu.clear();

    bool readonly = true;
    SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();
    if ( type == SourcesModel::StaticPlaylist || type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station )
    {

        PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex );
        playlist_ptr playlist = item->playlist();
        if ( !playlist.isNull() )
        {
            readonly = !playlist->author()->isLocal();
        }
    }

    QAction* latchOnAction = ActionCollection::instance()->getAction( "latchOn" );
    m_latchMenu.addAction( latchOnAction );

    m_privacyMenu.addAction( ActionCollection::instance()->getAction( "togglePrivacy" ) );

    if ( type == SourcesModel::Collection )
    {
        SourceItem* item = itemFromIndex< SourceItem >( m_contextMenuIndex );
        source_ptr source = item->source();
        if ( !source.isNull() )
        {
            if ( m_latchManager->isLatched( source ) )
            {
                QAction *latchOffAction = ActionCollection::instance()->getAction( "latchOff" );
                m_latchMenu.addAction( latchOffAction );
                connect( latchOffAction, SIGNAL( triggered() ), SLOT( latchOff() ) );
                m_latchMenu.addSeparator();
                QAction *latchRealtimeAction = ActionCollection::instance()->getAction( "realtimeFollowingAlong" );
                latchRealtimeAction->setChecked( source->playlistInterface()->latchMode() == Tomahawk::PlaylistInterface::RealTime );
                m_latchMenu.addAction( latchRealtimeAction );
                connect( latchRealtimeAction, SIGNAL( toggled( bool ) ), SLOT( latchModeToggled( bool ) ) );
            }
        }
    }

    QAction *loadPlaylistAction = ActionCollection::instance()->getAction( "loadPlaylist" );
    m_playlistMenu.addAction( loadPlaylistAction );
    QAction *renamePlaylistAction = ActionCollection::instance()->getAction( "renamePlaylist" );
    m_playlistMenu.addAction( renamePlaylistAction );
    m_playlistMenu.addSeparator();

    QAction *copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) );
    QAction *deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) );

    QString addToText = QString( "Add to my %1" );
    if ( type == SourcesModel::StaticPlaylist )
        addToText = addToText.arg( "Playlists" );
    if ( type == SourcesModel::AutomaticPlaylist )
        addToText = addToText.arg( "Automatic Playlists" );
    else if ( type == SourcesModel::Station )
        addToText = addToText.arg( "Stations" );

    QAction *addToLocalAction = m_roPlaylistMenu.addAction( tr( addToText.toUtf8(), "Adds the given playlist, dynamic playlist, or station to the users's own list" ) );

    m_roPlaylistMenu.addAction( copyPlaylistAction );
    deletePlaylistAction->setEnabled( !readonly );
    renamePlaylistAction->setEnabled( !readonly );
    addToLocalAction->setEnabled( readonly );

    if ( type == SourcesModel::StaticPlaylist )
        copyPlaylistAction->setText( tr( "&Export Playlist" ) );

    connect( loadPlaylistAction,   SIGNAL( triggered() ), SLOT( loadPlaylist() ) );
    connect( renamePlaylistAction, SIGNAL( triggered() ), SLOT( renamePlaylist() ) );
    connect( deletePlaylistAction, SIGNAL( triggered() ), SLOT( deletePlaylist() ) );
    connect( copyPlaylistAction,   SIGNAL( triggered() ), SLOT( copyPlaylistLink() ) );
    connect( addToLocalAction,     SIGNAL( triggered() ), SLOT( addToLocal() ) );
    connect( latchOnAction,        SIGNAL( triggered() ), SLOT( latchOnOrCatchUp() ), Qt::QueuedConnection );
}
Example #5
0
bool
SourceDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
{
    QMouseEvent* mEvent = 0;
    switch ( event->type() )
    {
//        case QEvent::MouseTrackingChange:
        case QEvent::MouseButtonDblClick:
        case QEvent::MouseButtonPress:
        case QEvent::MouseButtonRelease:
        case QEvent::MouseMove:
            mEvent = static_cast< QMouseEvent* >( event );
        default:
            break;
    }

    bool hoveringTrack = false;
    if ( m_trackRects.contains( index ) && mEvent )
    {
        const QRect trackRect = m_trackRects[ index ];
        hoveringTrack = trackRect.contains( mEvent->pos() );

        if ( hoveringTrack )
        {
            if ( m_trackHovered != index )
            {
                m_trackHovered = index;
                QMetaObject::invokeMethod( m_parent, "update", Qt::QueuedConnection, Q_ARG( QModelIndex, index ) );
            }
        }
    }
    if ( !hoveringTrack )
    {
        if ( m_trackHovered.isValid() )
            QMetaObject::invokeMethod( m_parent, "update", Qt::QueuedConnection, Q_ARG( QModelIndex, m_trackHovered ) );

        m_trackHovered = QPersistentModelIndex();
    }

    bool lockRectContainsClick = false, headphonesRectContainsClick = false;
    if ( m_headphoneRects.contains( index ) && mEvent )
    {
        const QRect headphoneRect = m_headphoneRects[ index ];
        headphonesRectContainsClick = headphoneRect.contains( mEvent->pos() );
    }
    if ( m_lockRects.contains( index ) && mEvent )
    {
        const QRect lockRect = m_lockRects[ index ];
        lockRectContainsClick = lockRect.contains( mEvent->pos() );
    }

    if ( event->type() == QEvent::MouseMove )
    {
        if ( hoveringTrack || lockRectContainsClick || headphonesRectContainsClick )
            m_parent->setCursor( Qt::PointingHandCursor );
        else
            m_parent->setCursor( Qt::ArrowCursor );
    }

    if ( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonPress )
    {
        SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
        if ( type == SourcesModel::TemporaryPage || type == SourcesModel::DeletablePage || type == SourcesModel::RemovablePage )
        {
            SourceTreeItem* gpi = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
            Q_ASSERT( gpi );

            QStyleOptionViewItemV4 o = option;
            initStyleOption( &o, index );
            const int padding = m_margin / 8;
            const QRect r( o.rect.right() - padding - m_iconHeight, padding + o.rect.y(), m_iconHeight, m_iconHeight );

            if ( r.contains( mEvent->pos() ) )
            {
                if ( event->type() == QEvent::MouseButtonRelease && mEvent->button() == Qt::LeftButton )
                {
                    gpi->removeFromList();

                    // Send a new mouse event to the view, since if the mouse is now over another item's delete area we want it to show up
                    QMouseEvent* ev = new QMouseEvent( QEvent::MouseMove, m_parent->viewport()->mapFromGlobal( QCursor::pos() ), Qt::NoButton, Qt::NoButton, Qt::NoModifier );
                    QApplication::postEvent( m_parent->viewport(), ev );
                }

                return true;
            }
        }
        else if ( type == SourcesModel::Source )
        {
            SourceItem* colItem = qobject_cast< SourceItem* >( index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >() );
            Q_ASSERT( colItem );

            if ( hoveringTrack && colItem->source() && colItem->source()->currentTrack() )
            {
                if ( event->type() == QEvent::MouseButtonRelease && mEvent->button() == Qt::LeftButton )
                {
                    ViewManager::instance()->show( colItem->source()->currentTrack() );
                    return true;
                }
                else if ( event->type() == QEvent::MouseButtonPress && mEvent->button() == Qt::RightButton )
                {
                    Tomahawk::ContextMenu* contextMenu = new Tomahawk::ContextMenu( m_parent );
                    contextMenu->setQuery( colItem->source()->currentTrack() );
                    contextMenu->exec( QCursor::pos() );
                    return true;
                }
            }

            if ( !colItem->source().isNull() && !colItem->source()->currentTrack().isNull() && !colItem->source()->isLocal() )
            {
                if ( headphonesRectContainsClick || lockRectContainsClick )
                {
                    if ( event->type() == QEvent::MouseButtonRelease && mEvent->button() == Qt::LeftButton )
                    {
                        if ( headphonesRectContainsClick )
                        {
                            if ( index.data( SourcesModel::LatchedOnRole ).toBool() )
                                // unlatch
                                emit latchOff( colItem->source() );
                            else
                                emit latchOn( colItem->source() );
                        }
                        else // it's in the lock rect
                            emit toggleRealtimeLatch( colItem->source(), !index.data( SourcesModel::LatchedRealtimeRole ).toBool() );
                    }
                    return true;
                }
            }
        }
        else if ( event->type() == QEvent::MouseButtonRelease && mEvent->button() == Qt::LeftButton && type == SourcesModel::StaticPlaylist )
        {
            PlaylistItem* plItem = qobject_cast< PlaylistItem* >( index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >() );
            Q_ASSERT( plItem );

            if ( plItem->canSubscribe() && !plItem->subscribedIcon().isNull() )
            {
                const int padding = m_margin / 16;
                const int imgWidth = option.rect.height() - 2 * padding;
                const QRect subRect( option.rect.right() - padding - imgWidth, option.rect.top() + padding, imgWidth, imgWidth );

                if ( subRect.contains( mEvent->pos() ) )
                {
                    // Toggle playlist subscription
                    plItem->setSubscribed( !plItem->subscribed() );
                }
            }
        }
    }

    // We emit our own clicked() signal instead of relying on QTreeView's, because that is fired whether or not a delegate accepts
    // a mouse press event. Since we want to swallow click events when they are on headphones other action items, here we make sure we only
    // emit if we really want to
    if ( event->type() == QEvent::MouseButtonRelease && mEvent->button() == Qt::LeftButton )
    {
        if ( m_lastClicked == -1 )
        {
            m_lastClicked = QDateTime::currentMSecsSinceEpoch();
            emit clicked( index );
        }
        else
        {
            qint64 elapsed = QDateTime::currentMSecsSinceEpoch() - m_lastClicked;
            if ( elapsed < QApplication::doubleClickInterval() )
            {
                m_lastClicked = -1;
                emit doubleClicked( index );
            } else
            {
                m_lastClicked = QDateTime::currentMSecsSinceEpoch();
                emit clicked( index );
            }
        }
    }

    return QStyledItemDelegate::editorEvent( event, model, option, index );
}
Example #6
0
void
SourceDelegate::paintSource( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
    painter->save();
    painter->setPen( Qt::black );
    QFont font = painter->font();
    font.setPointSize( TomahawkUtils::defaultFontSize() );
    painter->setFont( font );

    SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();
    SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );

    const int iconRectVertMargin = m_margin / 4;
    const QRect iconRect = option.rect.adjusted( m_margin / 2 + m_margin / 4, iconRectVertMargin, -option.rect.width() + option.rect.height() + m_margin / 4, -iconRectVertMargin );
    QString name = index.data().toString();
    QPixmap avatar;
    int figWidth = 0;
    bool isPlaying = false;
    QString desc;
    QString tracks;

    bool shouldDrawDropHint = false;

    if ( type == SourcesModel::Source )
    {
        // If the user is about to drop a track on a peer
        QRect itemsRect = option.rect;
        QPoint cursorPos = m_parent->mapFromGlobal( QCursor::pos() );
        bool cursorInRect = itemsRect.contains( cursorPos );
        if ( cursorInRect && m_dropHoverIndex.isValid() && m_dropHoverIndex == index )
            shouldDrawDropHint = true;

        SourceItem* colItem = qobject_cast< SourceItem* >( item );
        Q_ASSERT( colItem );
        bool status = !( !colItem->source() || !colItem->source()->isOnline() );

        if ( colItem->source() && !colItem->source()->isLocal() )
        {
            if ( status )
            {
                tracks = QString::number( colItem->source()->trackCount() );
                if ( shouldDrawDropHint )
                    figWidth = iconRect.width();
                name = colItem->source()->friendlyName();
            }

            avatar = colItem->pixmap( iconRect.size() );
            isPlaying = !colItem->source()->currentTrack().isNull();
            desc = colItem->source()->textStatus();
            if ( colItem->source().isNull() )
                desc = tr( "All available tracks" );
        }
    }
    else if ( type == SourcesModel::ScriptCollection )
    {
        ScriptCollectionItem* scItem = qobject_cast< ScriptCollectionItem* >( item );
        Q_ASSERT( scItem );

        if ( !scItem->collection().isNull() )
        {
            int trackCount = scItem->collection()->trackCount();
            if ( trackCount >= 0 )
            {
                tracks = QString::number( trackCount );
                figWidth = painter->fontMetrics().width( tracks );
            }
            name = scItem->collection()->itemName();
        }

        avatar = scItem->icon().pixmap( iconRect.size() );
        desc = qobject_cast< Tomahawk::ScriptCollection* >( scItem->collection().data() )->description();
    }

    painter->setOpacity( 1.0 );
    painter->drawPixmap( iconRect, avatar );

    QRect textRect = option.rect.adjusted( iconRect.width() + m_margin, m_margin / 6 + m_margin / 32, -figWidth - ( figWidth ? m_margin : 0 ), 0 );
    QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() );
    {
        QTextOption to;
        to.setWrapMode( QTextOption::NoWrap );
        painter->setOpacity( 0.7 );
        painter->drawText( textRect, text, to );
    }

    textRect = option.rect.adjusted( iconRect.width() + m_margin, option.rect.height() / 2, -figWidth - ( figWidth ? m_margin : 0 ), -m_margin / 4 );

    if ( type == SourcesModel::Source )
    {
        SourceItem* colItem = qobject_cast< SourceItem* >( item );
        Q_ASSERT( colItem );

        bool privacyOn = TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::FullyPrivate;
        if ( !colItem->source().isNull() && colItem->source()->isLocal() && privacyOn )
        {
            QRect pmRect = textRect;
            pmRect.setRight( pmRect.left() + pmRect.height() );
            ActionCollection::instance()->getAction( "togglePrivacy" )->icon().paint( painter, pmRect );
            textRect.adjust( pmRect.width() + m_margin / 8, 0, 0, 0 );
        }
        if ( ( isPlaying || ( !colItem->source().isNull() && colItem->source()->isLocal() ) ) && !shouldDrawDropHint )
        {
            // Show a listen icon
            TomahawkUtils::ImageType listenAlongPixmap = TomahawkUtils::Invalid;
            TomahawkUtils::ImageType realtimeListeningAlongPixmap = TomahawkUtils::Invalid;
            if ( index.data( SourcesModel::LatchedOnRole ).toBool() )
            {
                // Currently listening along
                listenAlongPixmap = TomahawkUtils::HeadphonesOn;
                if ( !colItem->source()->isLocal() )
                {
                    realtimeListeningAlongPixmap =
                        colItem->source()->playlistInterface()->latchMode() == Tomahawk::PlaylistModes::RealTime ?
                            TomahawkUtils::PadlockClosed : TomahawkUtils::PadlockOpen;
                }
            }
            else if ( !colItem->source()->isLocal() )
            {
                listenAlongPixmap = TomahawkUtils::HeadphonesOff;
            }

            if ( listenAlongPixmap != TomahawkUtils::Invalid )
            {
                QRect pmRect = textRect;
                pmRect.setRight( pmRect.left() + pmRect.height() );
                painter->drawPixmap( pmRect, TomahawkUtils::defaultPixmap( listenAlongPixmap, TomahawkUtils::Original, pmRect.size() ) );
                textRect.adjust( pmRect.width() + m_margin / 8, 0, 0, 0 );

                m_headphoneRects[ index ] = pmRect;
            }
            else
                m_headphoneRects.remove( index );

            if ( realtimeListeningAlongPixmap != TomahawkUtils::Invalid )
            {
                QRect pmRect = textRect;
                pmRect.setRight( pmRect.left() + pmRect.height() );
                painter->drawPixmap( pmRect, TomahawkUtils::defaultPixmap( realtimeListeningAlongPixmap, TomahawkUtils::Original, pmRect.size() ) );
                textRect.adjust( pmRect.width() + m_margin / 8, 0, 0, 0 );

                m_lockRects[ index ] = pmRect;
            }
            else
                m_lockRects.remove( index );
        }
    }

    painter->save();
    if ( m_trackHovered == index )
    {
        QFont font = painter->font();
        font.setUnderline( true );
        painter->setFont( font );
    }
    textRect.adjust( 0, 0, 0, m_margin / 16 );

    if ( shouldDrawDropHint )
    {
        desc = tr( "Drop to send tracks" );
    }

    text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() - m_margin / 4 );
    {
        QTextOption to( Qt::AlignVCenter );
        to.setWrapMode( QTextOption::NoWrap );

        painter->setOpacity( 0.4 );
        painter->drawText( textRect, text, to );
    }
    painter->restore();

    bool shouldPaintTrackCount = false;
    if ( type == SourcesModel::Source )
    {
        SourceItem* colItem = qobject_cast< SourceItem* >( item );
        Q_ASSERT( colItem );

        if ( colItem->source() && colItem->source()->currentTrack() && colItem->source()->state() == Tomahawk::SYNCED )
            m_trackRects[ index ] = textRect.adjusted( 0, 0, -textRect.width() + painter->fontMetrics().width( text ), 0 );
        else
            m_trackRects.remove( index );
    }
    else if ( type == SourcesModel::ScriptCollection )
    {
        if ( !tracks.isEmpty() )
            shouldPaintTrackCount = true;
    }

    if ( shouldPaintTrackCount || shouldDrawDropHint )
    {
        if ( shouldDrawDropHint )
        {
            const QRect figRect = option.rect.adjusted( option.rect.width() - figWidth - iconRectVertMargin, iconRectVertMargin, -iconRectVertMargin, -iconRectVertMargin );
            painter->drawPixmap( figRect, TomahawkUtils::defaultPixmap( TomahawkUtils::Inbox, TomahawkUtils::Original, figRect.size() ) );
        }
        else
        {
            const QRect figRect = option.rect.adjusted( option.rect.width() - figWidth - m_margin / 2, 0, -m_margin / 2, 0 );
            painter->drawText( figRect, tracks, QTextOption( Qt::AlignVCenter | Qt::AlignRight ) );
        }
    }

    painter->restore();
}