Esempio n. 1
0
void
SourceDelegate::paintDecorations( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
    SourcesModel::RowType type = static_cast< SourcesModel::RowType >( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() );
    SourceTreeItem* item = index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >();

    // Paint the speaker icon next to the currently-playing playlist
    const bool playable = ( type == SourcesModel::StaticPlaylist ||
        type == SourcesModel::AutomaticPlaylist ||
        type == SourcesModel::Station ||
        type == SourcesModel::TemporaryPage ||
        type == SourcesModel::LovedTracksPage ||
        type == SourcesModel::Collection ||
        type == SourcesModel::GenericPage );
    const bool playing = ( AudioEngine::instance()->isPlaying() || AudioEngine::instance()->isPaused() );

    if ( playable && playing && item->isBeingPlayed() )
    {
        const int iconW = option.rect.height() - m_margin / 4;
        const QRect iconRect( m_margin / 4, option.rect.y() + m_margin / 8, iconW, iconW );
        const QPixmap speaker = TomahawkUtils::defaultPixmap( TomahawkUtils::NowPlayingSpeakerDark, TomahawkUtils::Original, iconRect.size() );

        painter->drawPixmap( iconRect, speaker );
    }
}
Esempio n. 2
0
bool
SourcesModel::removeItem( const source_ptr& source )
{
//    qDebug() << "Removing source item from SourceTree:" << source->username();

    QModelIndex idx;
    int rows = rowCount();
    for ( int row = 0; row < rows; row++ )
    {
        QModelIndex idx = index( row, 0 );
        SourceTreeItem* item = indexToTreeItem( idx );
        if ( item )
        {
            if ( item->source() == source )
            {
                qDebug() << "Found removed source item:" << item->source()->userName();
                invisibleRootItem()->removeRow( row );

                onItemOffline( idx );

                delete item;
                return true;
            }
        }
    }

    return false;
}
Esempio n. 3
0
void
SourcesModel::onItemOffline( const QModelIndex& idx )
{
    qDebug() << Q_FUNC_INFO;

    SourceTreeItem* item = indexToTreeItem( idx );
    if ( item )
        item->onOffline();
}
Esempio n. 4
0
void
SourceTreeView::onItemActivated( const QModelIndex& index )
{
    if ( !index.isValid() || !index.flags().testFlag( Qt::ItemIsEnabled ) )
        return;

    SourceTreeItem* item = itemFromIndex< SourceTreeItem >( index );
    item->activate();
}
bool
SourcesProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
{
    if ( !m_filtered )
        return true;
    
    SourceTreeItem* sti = m_model->indexToTreeItem( sourceModel()->index( sourceRow, 0, sourceParent ) );
    if ( sti )
    {
        if ( sti->source().isNull() || sti->source()->isOnline() )
            return true;
    }

    return false;
}
Esempio n. 6
0
QModelIndex
SourcesModel::parent( const QModelIndex& child ) const
{
    if( !child.isValid() )
    {
        return QModelIndex();
    }

    SourceTreeItem* node = itemFromIndex( child );
    SourceTreeItem* parent = node->parent();
    if( parent == m_rootItem )
        return QModelIndex();

    return createIndex( rowForItem( parent ), 0, parent );
}
Esempio n. 7
0
void
SourceTreeView::dropEvent( QDropEvent* event )
{
    bool accept = false;
    const QPoint pos = event->pos();
    const QModelIndex index = indexAt( pos );

    if ( event->mimeData()->hasFormat( "application/tomahawk.query.list" ) )
    {
        const QPoint pos = event->pos();
        const QModelIndex index = indexAt( pos );

        if ( index.isValid() )
        {
            if ( SourcesModel::indexType( index ) == SourcesModel::PlaylistSource )
            {
                playlist_ptr playlist = SourcesModel::indexToPlaylist( index );
                if ( !playlist.isNull() && playlist->author()->isLocal() )
                {
                    accept = true;
                    QByteArray itemData = event->mimeData()->data( "application/tomahawk.query.list" );
                    QDataStream stream( &itemData, QIODevice::ReadOnly );
                    QList<Tomahawk::query_ptr> queries;

                    while ( !stream.atEnd() )
                    {
                        qlonglong qptr;
                        stream >> qptr;

                        Tomahawk::query_ptr* query = reinterpret_cast<Tomahawk::query_ptr*>(qptr);
                        if ( query && !query->isNull() )
                        {
                            qDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track();
                            queries << *query;
                        }
                    }

                    qDebug() << "on playlist:" << playlist->title() << playlist->guid();

                    SourceTreeItem* treeItem = SourcesModel::indexToTreeItem( index );
                    if ( treeItem )
                    {
                        QString rev = treeItem->currentlyLoadedPlaylistRevision( playlist->guid() );
                        playlist->addEntries( queries, rev );
                    }
                }
            }
        }
Esempio n. 8
0
QModelIndex
SourcesModel::index( int row, int column, const QModelIndex& parent ) const
{
    if( row < 0 || column < 0 )
        return QModelIndex();

    if( hasIndex( row, column, parent ) )
    {
        SourceTreeItem *parentNode = itemFromIndex( parent );
        SourceTreeItem *childNode = parentNode->children().at( row );
        return createIndex( row, column, childNode );
    }

    return QModelIndex();

}
Esempio n. 9
0
QModelIndex
SourcesModel::collectionToIndex( const Tomahawk::collection_ptr& collection )
{
    for ( int i = 0; i < rowCount(); i++ )
    {
        QModelIndex idx = index( i, 0 );
        SourcesModel::SourceType type = SourcesModel::indexType( idx );
        if ( type == SourcesModel::CollectionSource )
        {
            SourceTreeItem* sti = SourcesModel::indexToTreeItem( idx );
            if ( sti && !sti->source().isNull() && sti->source()->collection().data() == collection.data() )
                return idx;
        }
    }

    return QModelIndex();
}
Esempio n. 10
0
bool
SourcesModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
{
    SourceTreeItem* item = 0;
//    qDebug() << "Got mime data dropped:" << row << column << parent << itemFromIndex( parent )->text();
    if( row == -1 && column == -1 )
        item = itemFromIndex( parent );
    else if( column == 0 )
        item = itemFromIndex( index( row, column, parent ) );
    else if( column == -1 ) // column is -1, that means the drop is happening "below" the indices. that means we actually want the one before it
        item = itemFromIndex( index( row - 1, 0, parent ) );

    Q_ASSERT( item );

//    qDebug() << "Dropping on:" << item->text();
    return item->dropMimeData( data, action );
}
Esempio n. 11
0
void
SourceTreeView::onItemActivated( const QModelIndex& index )
{
    if ( !index.isValid() )
        return;

    SourcesModel::SourceType type = SourcesModel::indexType( index );
    if ( type == SourcesModel::CollectionSource )
    {
        SourceTreeItem* item = SourcesModel::indexToTreeItem( index );
        if ( item )
        {
            if ( item->source().isNull() )
            {
                PlaylistManager::instance()->showSuperCollection();
            }
            else
            {
                qDebug() << "SourceTreeItem toggled:" << item->source()->userName();

                PlaylistManager::instance()->show( item->source()->collection() );
            }
        }
    }
    else if ( type == SourcesModel::PlaylistSource )
    {
        playlist_ptr playlist = SourcesModel::indexToPlaylist( index );
        if ( !playlist.isNull() )
        {
            qDebug() << "Playlist activated:" << playlist->title();

            PlaylistManager::instance()->show( playlist );
        }
    }
    else if ( type == SourcesModel::DynamicPlaylistSource )
    {
        dynplaylist_ptr playlist = SourcesModel::indexToDynamicPlaylist( index );
        if ( !playlist.isNull() )
        {
            qDebug() << "Dynamic Playlist activated:" << playlist->title();

            PlaylistManager::instance()->show( playlist );
        }
    }
}
Esempio n. 12
0
QModelIndex
SourcesModel::indexFromItem( SourceTreeItem* item ) const
{
    if( !item || !item->parent() ) // should never happen..
        return QModelIndex();

    // reconstructs a modelindex from a sourcetreeitem that is somewhere in the tree
    // traverses the item to the root node, then rebuilds the qmodeindices from there back down
    // each int is the row of that item in the parent.
    /**
     * In this diagram, if the \param item is G, childIndexList will contain [0, 2, 0]
     *
     *    A
     *      D
     *      E
     *      F
     *        G
     *        H
     *    B
     *    C
     *
     **/
    QList< int > childIndexList;
    SourceTreeItem* curItem = item;
    while( curItem != m_rootItem ) {
        int row  = rowForItem( curItem );
        if( row < 0 ) // something went wrong, bail
            return QModelIndex();

        childIndexList << row;

        curItem = curItem->parent();
    }
//     qDebug() << "build child index list:" << childIndexList;
    // now rebuild the qmodelindex we need
    QModelIndex idx;
    for( int i = childIndexList.size() - 1; i >= 0 ; i-- ) {
        idx = index( childIndexList[ i ], 0, idx );
    }
//     qDebug() << "Got index from item:" << idx << idx.data( Qt::DisplayRole ).toString();
//     qDebug() << "parent:" << idx.parent();
    return idx;
}
Esempio n. 13
0
bool
SourcesModel::appendItem( const source_ptr& source )
{
    SourceTreeItem* item = new SourceTreeItem( source, this );
    connect( item, SIGNAL( clicked( QModelIndex ) ), this, SIGNAL( clicked( QModelIndex ) ) );

//    qDebug() << "Appending source item:" << item->source()->username();
    invisibleRootItem()->appendRow( item->columns() );

    if ( !source.isNull() )
    {
        connect( source.data(), SIGNAL( offline() ), SLOT( onSourceChanged() ) );
        connect( source.data(), SIGNAL( online() ), SLOT( onSourceChanged() ) );
        connect( source.data(), SIGNAL( stats( QVariantMap ) ), SLOT( onSourceChanged() ) );
        connect( source.data(), SIGNAL( playbackStarted( Tomahawk::query_ptr ) ), SLOT( onSourceChanged() ) );
        connect( source.data(), SIGNAL( stateChanged() ), SLOT( onSourceChanged() ) );
    }
    
    return true; // FIXME
}
Esempio n. 14
0
void
SourcesModel::onSourceChanged()
{
    Source* src = qobject_cast< Source* >( sender() );
    
    for ( int i = 0; i < rowCount(); i++ )
    {
        QModelIndex idx = index( i, 0 );

        if ( indexType( idx ) == CollectionSource )
        {
            SourceTreeItem* sti = indexToTreeItem( idx );
            if ( sti )
            {
                if ( sti->source().data() == src )
                {
                    emit dataChanged( idx, idx );
                }
            }
        }
    }
}
Esempio n. 15
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 );
}
Esempio n. 16
0
bool
SourcesModel::setData( const QModelIndex& index, const QVariant& value, int role )
{
    SourceTreeItem* item = itemFromIndex( index );
    return item->setData( value, role );
}