1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-03-31 06:02:27 +02:00

* Added direct links to Artist / Album - pages in TrackView.

This commit is contained in:
Christian Muehlhaeuser 2011-07-11 02:02:32 +02:00
parent 3d289c0f77
commit 76af86dc4b
11 changed files with 394 additions and 42 deletions

View File

View File

View File

@ -0,0 +1,170 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "musicbrainzPlugin.h"
#include "utils/tomahawkutils.h"
#include <QNetworkReply>
#include <QDomDocument>
using namespace Tomahawk::InfoSystem;
// for internal neatness
MusicBrainzPlugin::MusicBrainzPlugin()
: InfoPlugin()
{
qDebug() << Q_FUNC_INFO;
m_supportedGetTypes << Tomahawk::InfoSystem::InfoArtistReleases;
}
MusicBrainzPlugin::~MusicBrainzPlugin()
{
qDebug() << Q_FUNC_INFO;
}
void
MusicBrainzPlugin::namChangedSlot( QNetworkAccessManager *nam )
{
qDebug() << Q_FUNC_INFO;
if ( !nam )
return;
m_nam = QWeakPointer< QNetworkAccessManager >( nam );
}
void
MusicBrainzPlugin::getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
{
qDebug() << Q_FUNC_INFO;
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() )
{
emit info( requestId, requestData, QVariant() );
return;
}
InfoCriteriaHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
if ( !hash.contains( "artist" ) )
{
emit info( requestId, requestData, QVariant() );
return;
}
if ( requestData.type == InfoArtistReleases )
{
QString requestString( "http://musicbrainz.org/ws/2/artist" );
QUrl url( requestString );
url.addQueryItem( "query", hash["artist"] );
QNetworkReply* reply = m_nam.data()->get( QNetworkRequest( url ) );
reply->setProperty( "requestId", requestId );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( artistSearchSlot() ) );
}
}
bool
MusicBrainzPlugin::isValidTrackData( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
{
qDebug() << Q_FUNC_INFO;
if ( requestData.input.isNull() || !requestData.input.isValid() || !requestData.input.canConvert< QVariantMap >() )
{
emit info( requestId, requestData, QVariant() );
qDebug() << Q_FUNC_INFO << "Data null, invalid, or can't convert";
return false;
}
QVariantMap hash = requestData.input.value< QVariantMap >();
if ( hash[ "trackName" ].toString().isEmpty() )
{
emit info( requestId, requestData, QVariant() );
qDebug() << Q_FUNC_INFO << "Track name is empty";
return false;
}
if ( hash[ "artistName" ].toString().isEmpty() )
{
emit info( requestId, requestData, QVariant() );
qDebug() << Q_FUNC_INFO << "No artist name found";
return false;
}
return true;
}
void
MusicBrainzPlugin::artistSearchSlot()
{
qDebug() << Q_FUNC_INFO;
QNetworkReply* oldReply = qobject_cast<QNetworkReply*>( sender() );
if ( !oldReply )
return; //timeout will handle it
QDomDocument doc;
doc.setContent( oldReply->readAll() );
QDomNodeList domNodeList = doc.elementsByTagName( "artist" );
if ( domNodeList.isEmpty() )
{
emit info( oldReply->property( "requestId" ).toUInt(), oldReply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
QString artist_id = domNodeList.at( 0 ).toElement().attribute( "id" );
qDebug() << Q_FUNC_INFO << "FOOBAR:" << artist_id;
QString requestString( "http://musicbrainz.org/ws/2/release?status=official&type=album|ep" );
QUrl url( requestString );
url.addQueryItem( "artist", artist_id );
QNetworkReply* newReply = m_nam.data()->get( QNetworkRequest( url ) );
newReply->setProperty( "requestId", oldReply->property( "requestId" ) );
newReply->setProperty( "requestData", oldReply->property( "requestData" ) );
connect( newReply, SIGNAL( finished() ), SLOT( albumSearchSlot() ) );
}
void
MusicBrainzPlugin::albumSearchSlot()
{
qDebug() << Q_FUNC_INFO;
QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
if ( !reply )
return; //timeout will handle it
QDomDocument doc;
doc.setContent( reply->readAll() );
QDomNodeList domNodeList = doc.elementsByTagName( "title" );
if ( domNodeList.isEmpty() )
{
emit info( reply->property( "requestId" ).toUInt(), reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant() );
return;
}
QStringList albums;
for ( int i = 0; i < domNodeList.count(); i++ )
{
QString album = domNodeList.at( i ).toElement().text();
if ( !albums.contains( album ) )
albums << album;
}
qDebug() << Q_FUNC_INFO << "Found albums:" << albums;
emit info( reply->property( "requestId" ).toUInt(), reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >(), QVariant( albums ) );
}

View File

@ -0,0 +1,75 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MUSICBRAINZPLUGIN_H
#define MUSICBRAINZPLUGIN_H
#include "infosystem/infosystem.h"
#include "infosystem/infosystemworker.h"
class QNetworkReply;
namespace Tomahawk
{
namespace InfoSystem
{
class MusicBrainzPlugin : public InfoPlugin
{
Q_OBJECT
public:
MusicBrainzPlugin();
virtual ~MusicBrainzPlugin();
public slots:
void namChangedSlot( QNetworkAccessManager *nam );
protected slots:
virtual void getInfo( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
virtual void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant data )
{
Q_UNUSED( caller );
Q_UNUSED( type );
Q_UNUSED( data );
}
virtual void notInCacheSlot( uint requestId, Tomahawk::InfoSystem::InfoCriteriaHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
{
Q_UNUSED( requestId );
Q_UNUSED( criteria );
Q_UNUSED( requestData );
}
private slots:
void artistSearchSlot();
void albumSearchSlot();
private:
bool isValidTrackData( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData );
QWeakPointer< QNetworkAccessManager > m_nam;
};
}
}
#endif // MUSICBRAINZPLUGIN_H

View File

@ -65,46 +65,48 @@ enum InfoType { // as items are saved in cache, mark them here to not change the
InfoTrackTempo = 20,
InfoTrackLoudness = 21,
InfoArtistID = 22,
InfoArtistName = 23,
InfoArtistBiography = 24,
InfoArtistBlog = 25,
InfoArtistFamiliarity = 26,
InfoArtistHotttness = 27,
InfoArtistID = 25,
InfoArtistName = 26,
InfoArtistBiography = 27,
InfoArtistImages = 28, //cached -- do not change
InfoArtistNews = 29,
InfoArtistProfile = 30,
InfoArtistReviews = 31,
InfoArtistBlog = 29,
InfoArtistFamiliarity = 30,
InfoArtistHotttness = 31,
InfoArtistSongs = 32, //cached -- do not change
InfoArtistSimilars = 33, //cached -- do not change
InfoArtistTerms = 34,
InfoArtistLinks = 35,
InfoArtistVideos = 36,
InfoArtistNews = 34,
InfoArtistProfile = 35,
InfoArtistReviews = 36,
InfoArtistTerms = 37,
InfoArtistLinks = 38,
InfoArtistVideos = 39,
InfoArtistReleases = 40,
InfoAlbumID = 37,
InfoAlbumName = 38,
InfoAlbumArtist = 39,
InfoAlbumDate = 40,
InfoAlbumGenre = 41,
InfoAlbumComposer = 42,
InfoAlbumID = 42,
InfoAlbumCoverArt = 43, //cached -- do not change
InfoAlbumName = 44,
InfoAlbumArtist = 45,
InfoAlbumDate = 46,
InfoAlbumGenre = 47,
InfoAlbumComposer = 48,
InfoAlbumSongs = 49,
InfoMiscTopHotttness = 44,
InfoMiscTopTerms = 45,
InfoMiscTopHotttness = 60,
InfoMiscTopTerms = 61,
InfoSubmitNowPlaying = 46,
InfoSubmitScrobble = 47,
InfoSubmitNowPlaying = 70,
InfoSubmitScrobble = 71,
InfoNowPlaying = 48,
InfoNowPaused = 49,
InfoNowResumed = 50,
InfoNowStopped = 51,
InfoNowPlaying = 80,
InfoNowPaused = 81,
InfoNowResumed = 82,
InfoNowStopped = 83,
InfoNoInfo = 52,
InfoLove = 53,
InfoUnLove = 54,
InfoNoInfo = 90,
InfoLove = 91,
InfoUnLove = 92,
InfoNotifyUser = 55
InfoNotifyUser = 100
};
struct InfoRequestData {
@ -143,7 +145,7 @@ protected slots:
virtual void notInCacheSlot( uint requestId, Tomahawk::InfoSystem::InfoCriteriaHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) = 0;
virtual void namChangedSlot( QNetworkAccessManager *nam ) = 0;
protected:
InfoType m_type;
QSet< InfoType > m_supportedGetTypes;

View File

@ -26,6 +26,8 @@
#include "infoplugins/generic/echonestplugin.h"
#include "infoplugins/generic/musixmatchplugin.h"
#include "infoplugins/generic/lastfmplugin.h"
#include "infoplugins/generic/musicbrainzPlugin.h"
#ifdef Q_WS_MAC
#include "infoplugins/mac/adiumplugin.h"
#endif
@ -76,9 +78,13 @@ InfoSystemWorker::init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache> cac
InfoPluginPtr mmptr( new MusixMatchPlugin() );
m_plugins.append( mmptr );
registerInfoTypes( mmptr, mmptr.data()->supportedGetTypes(), mmptr.data()->supportedPushTypes() );
InfoPluginPtr mbptr( new MusicBrainzPlugin() );
m_plugins.append( mbptr );
registerInfoTypes( mbptr, mbptr.data()->supportedGetTypes(), mbptr.data()->supportedPushTypes() );
InfoPluginPtr lfmptr( new LastFmPlugin() );
m_plugins.append( lfmptr );
registerInfoTypes( lfmptr, lfmptr.data()->supportedGetTypes(), lfmptr.data()->supportedPushTypes() );
#ifdef Q_WS_MAC
InfoPluginPtr admptr( new AdiumPlugin() );
m_plugins.append( admptr );
@ -190,7 +196,7 @@ InfoSystemWorker::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData, ui
data->input = requestData.input;
data->customData = requestData.customData;
m_savedRequestMap[ requestId ] = data;
QMetaObject::invokeMethod( ptr.data(), "getInfo", Qt::QueuedConnection, Q_ARG( uint, requestId ), Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
}
@ -222,7 +228,7 @@ InfoSystemWorker::infoSlot( uint requestId, Tomahawk::InfoSystem::InfoRequestDat
qDebug() << Q_FUNC_INFO << " request was already taken care of!";
return;
}
m_requestSatisfiedMap[ requestId ] = true;
emit info( requestData, output );
@ -236,7 +242,7 @@ InfoSystemWorker::infoSlot( uint requestId, Tomahawk::InfoSystem::InfoRequestDat
void
InfoSystemWorker::checkFinished( const QString &target )
{
{
Q_FOREACH( InfoType testtype, m_dataTracker[ target ].keys() )
{
if ( m_dataTracker[ target ][ testtype ] != 0)
@ -272,7 +278,7 @@ InfoSystemWorker::checkTimeoutsTimerFired()
//doh, timed out
qDebug() << Q_FUNC_INFO << " doh, timed out for requestId " << requestId;
InfoRequestData *savedData = m_savedRequestMap[ requestId ];
InfoRequestData returnData;
returnData.caller = savedData->caller;
returnData.type = savedData->type;
@ -285,7 +291,7 @@ InfoSystemWorker::checkTimeoutsTimerFired()
m_dataTracker[ returnData.caller ][ returnData.type ] = m_dataTracker[ returnData.caller ][ returnData.type ] - 1;
qDebug() << "current count in dataTracker for target " << returnData.caller << " is " << m_dataTracker[ returnData.caller ][ returnData.type ];
m_requestSatisfiedMap[ requestId ] = true;
m_timeRequestMapper.remove( time, requestId );
if ( !m_timeRequestMapper.count( time ) )

View File

@ -36,6 +36,7 @@
#include "utils/tomahawkutils.h"
#define PLAYING_ICON QString( RESPATH "images/now-playing-speaker.png" )
#define ARROW_ICON QString( RESPATH "images/forward.png" )
using namespace Tomahawk;
@ -46,6 +47,7 @@ PlaylistItemDelegate::PlaylistItemDelegate( TrackView* parent, TrackProxyModel*
, m_model( proxy )
{
m_nowPlayingIcon = QPixmap( PLAYING_ICON );
m_arrowIcon = QPixmap( ARROW_ICON );
}
@ -94,9 +96,6 @@ PlaylistItemDelegate::prepareStyleOption( QStyleOptionViewItemV4* option, const
option->state |= QStyle::State_Selected;
}
if ( item->isPlaying() || index.column() == TrackModel::Score )
option->text.clear();
if ( option->state & QStyle::State_Selected )
{
option->palette.setColor( QPalette::Text, option->palette.color( QPalette::HighlightedText ) );
@ -229,10 +228,19 @@ PlaylistItemDelegate::paintDetailed( QPainter* painter, const QStyleOptionViewIt
QStyleOptionViewItemV4 opt = option;
prepareStyleOption( &opt, index );
opt.text.clear();
qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter );
if ( m_view->hoveredIndex().row() == index.row() && m_view->hoveredIndex().column() == index.column() &&
( index.column() == TrackModel::Artist || index.column() == TrackModel::Album ) )
{
opt.rect.setWidth( opt.rect.width() - 16 );
QRect arrowRect( opt.rect.x() + opt.rect.width(), opt.rect.y(), 14, opt.rect.height() );
painter->drawPixmap( arrowRect, m_arrowIcon );
}
painter->save();
if ( index.column() == TrackModel::Score )
{
if ( opt.state & QStyle::State_Selected )
@ -274,5 +282,14 @@ PlaylistItemDelegate::paintDetailed( QPainter* painter, const QStyleOptionViewIt
painter->drawText( r.adjusted( 0, 1, 0, 0 ), text, to );
}
}
else
{
painter->setPen( opt.palette.text().color() );
QTextOption to( Qt::AlignVCenter );
QString text = painter->fontMetrics().elidedText( index.data().toString(), Qt::ElideRight, opt.rect.width() - 3 );
painter->drawText( opt.rect.adjusted( 3, 1, 0, 0 ), text, to );
}
painter->restore();
}

View File

@ -53,6 +53,7 @@ private:
unsigned int m_removalProgress;
QPixmap m_nowPlayingIcon;
QPixmap m_arrowIcon;
TrackView* m_view;
TrackProxyModel* m_model;

View File

@ -50,6 +50,7 @@ TrackView::TrackView( QWidget* parent )
, m_dragging( false )
, m_contextMenu( new ContextMenu( this ) )
{
setMouseTracking( true );
setAlternatingRowColors( true );
setSelectionMode( QAbstractItemView::ExtendedSelection );
setSelectionBehavior( QAbstractItemView::SelectRows );
@ -435,3 +436,75 @@ TrackView::onMenuTriggered( int action )
break;
}
}
void
TrackView::leaveEvent( QEvent* event )
{
m_hoveredIndex = QModelIndex();
setCursor( Qt::ArrowCursor );
}
void
TrackView::mouseMoveEvent( QMouseEvent* event )
{
QModelIndex idx = indexAt( event->pos() );
m_hoveredIndex = idx;
if ( idx.column() == TrackModel::Artist || idx.column() == TrackModel::Album )
{
if ( event->pos().x() > header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) - 16 &&
event->pos().x() < header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) )
{
setCursor( Qt::PointingHandCursor );
return;
}
}
setCursor( Qt::ArrowCursor );
}
void
TrackView::mousePressEvent( QMouseEvent* event )
{
QModelIndex idx = indexAt( event->pos() );
if ( event->pos().x() > header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) - 16 &&
event->pos().x() < header()->sectionViewportPosition( idx.column() ) + header()->sectionSize( idx.column() ) )
{
TrackModelItem* item = proxyModel()->itemFromIndex( proxyModel()->mapToSource( idx ) );
switch ( idx.column() )
{
case TrackModel::Artist:
{
if ( item->query()->results().count() )
{
ViewManager::instance()->show( item->query()->results().first()->artist() );
}
else
{
ViewManager::instance()->show( Artist::get( item->query()->artist() ) );
}
break;
}
case TrackModel::Album:
{
if ( item->query()->results().count() )
{
ViewManager::instance()->show( item->query()->results().first()->album() );
}
else
{
//TODO
}
break;
}
default:
break;
}
}
}

View File

@ -56,6 +56,7 @@ explicit TrackView( QWidget* parent = 0 );
OverlayWidget* overlay() const { return m_overlay; }
Tomahawk::ContextMenu* contextMenu() const { return m_contextMenu; }
QModelIndex hoveredIndex() const { return m_hoveredIndex; }
QModelIndex contextMenuIndex() const { return m_contextMenuIndex; }
void setContextMenuIndex( const QModelIndex& idx ) { m_contextMenuIndex = idx; }
@ -74,6 +75,9 @@ protected:
virtual void dragMoveEvent( QDragMoveEvent* event );
virtual void dropEvent( QDropEvent* event );
void mouseMoveEvent( QMouseEvent* event );
void mousePressEvent( QMouseEvent* event );
void leaveEvent( QEvent* event );
void paintEvent( QPaintEvent* event );
void keyPressEvent( QKeyEvent* event );
@ -96,6 +100,7 @@ private:
bool m_dragging;
QRect m_dropRect;
QModelIndex m_hoveredIndex;
QModelIndex m_contextMenuIndex;
Tomahawk::ContextMenu* m_contextMenu;
};

View File

@ -95,9 +95,9 @@ ArtistInfoWidget::load( const artist_ptr& artist )
requestData.input = artist->name();
requestData.type = Tomahawk::InfoSystem::InfoArtistBiography;
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( artistInfo );
requestData.type = Tomahawk::InfoSystem::InfoArtistImages;
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
@ -106,6 +106,9 @@ ArtistInfoWidget::load( const artist_ptr& artist )
requestData.type = Tomahawk::InfoSystem::InfoArtistSongs;
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
requestData.type = Tomahawk::InfoSystem::InfoArtistReleases;
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
}