1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-04-13 20:41:58 +02:00

* Added ArtistInfoWidget, our new Artist page and ViewManager's default show(artist) action.

This commit is contained in:
Christian Muehlhaeuser 2011-07-03 02:18:28 +02:00
parent 8017bcacc7
commit dc095ec963
28 changed files with 832 additions and 105 deletions

View File

@ -173,7 +173,7 @@ set( libSources
widgets/overlaywidget.cpp
widgets/HeaderLabel.cpp
widgets/infowidgets/sourceinfowidget.cpp
# widgets/infowidgets/ArtistInfoWidget.cpp
widgets/infowidgets/ArtistInfoWidget.cpp
kdsingleapplicationguard/kdsingleapplicationguard.cpp
kdsingleapplicationguard/kdsharedmemorylocker.cpp
@ -342,7 +342,7 @@ set( libHeaders
widgets/overlaywidget.h
widgets/HeaderLabel.h
widgets/infowidgets/sourceinfowidget.h
# widgets/infowidgets/ArtistInfoWidget.h
widgets/infowidgets/ArtistInfoWidget.h
kdsingleapplicationguard/kdsingleapplicationguard.h
)
@ -364,7 +364,7 @@ set( libUI ${libUI}
widgets/searchwidget.ui
widgets/welcomewidget.ui
widgets/infowidgets/sourceinfowidget.ui
# widgets/infowidgets/ArtistInfoWidget.ui
widgets/infowidgets/ArtistInfoWidget.ui
playlist/topbar/topbar.ui
playlist/infobar/infobar.ui
)

View File

@ -26,9 +26,27 @@
using namespace Tomahawk;
Artist::Artist() {}
Artist::~Artist() {}
Artist::Artist()
{
}
Artist::~Artist()
{
}
artist_ptr
Artist::get( const QString& name, bool autoCreate )
{
int artid = Database::instance()->impl()->artistId( name, autoCreate );
if ( artid < 1 )
return artist_ptr();
return Artist::get( artid, name );
}
artist_ptr
Artist::get( unsigned int id, const QString& name )

View File

@ -1,5 +1,5 @@
/* === 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
@ -36,6 +36,7 @@ class DLLEXPORT Artist : public QObject, public PlaylistInterface
Q_OBJECT
public:
static artist_ptr get( const QString& name, bool autoCreate = false );
static artist_ptr get( unsigned int id, const QString& name );
Artist( unsigned int id, const QString& name );
@ -54,7 +55,7 @@ public:
virtual bool hasNextItem();
virtual Tomahawk::result_ptr currentItem() const { return m_currentItem; }
virtual PlaylistInterface::RepeatMode repeatMode() const { return PlaylistInterface::NoRepeat; }
virtual bool shuffled() const { return false; }
@ -72,7 +73,7 @@ signals:
void sourceTrackCountChanged( unsigned int tracks );
void nextTrackReady();
private slots:
void onTracksAdded( const QList<Tomahawk::query_ptr>& tracks );

View File

@ -69,6 +69,8 @@ private slots:
void setIsReadyTrue() { m_ready = true; }
private:
DatabaseImpl* impl() const { return m_impl; }
bool m_ready;
DatabaseImpl* m_impl;
DatabaseWorker* m_workerRW;
@ -77,6 +79,8 @@ private:
int m_maxConcurrentThreads;
static Database* s_instance;
friend class Tomahawk::Artist;
};
#endif // DATABASE_H

View File

@ -148,14 +148,16 @@ DatabaseCommand_AddFiles::exec( DatabaseImpl* dbi )
if( !source()->isLocal() )
url = QString( "servent://%1\t%2" ).arg( source()->userName() ).arg( url );
bool isnew;
artistid = dbi->artistId( artist, isnew );
bool autoCreate = true;
artistid = dbi->artistId( artist, autoCreate );
if ( artistid < 1 )
continue;
trackid = dbi->trackId( artistid, track, isnew );
autoCreate = true; // artistId overwrites autoCreate (reference)
trackid = dbi->trackId( artistid, track, autoCreate );
if ( trackid < 1 )
continue;
albumid = dbi->albumId( artistid, album, isnew );
autoCreate = true; // trackId overwrites autoCreate (reference)
albumid = dbi->albumId( artistid, album, autoCreate );
// Now add the association
query_filejoin.bindValue( 0, fileid );

View File

@ -33,31 +33,32 @@ DatabaseCommand_LoadSocialActions::exec( DatabaseImpl* dbi )
{
qDebug() << Q_FUNC_INFO;
Q_ASSERT( !source().isNull() );
TomahawkSqlQuery query = dbi->newquery();
QVariant srcid = source()->isLocal() ? QVariant( QVariant::Int ) : source()->id();
bool isnew;
int artid = dbi->artistId( m_artist, isnew );
bool autoCreate = true;
int artid = dbi->artistId( m_artist, autoCreate );
if( artid < 1 )
return;
int trkid = dbi->trackId( artid, m_track, isnew );
autoCreate = true; // artistId overwrites autoCreate (reference)
int trkid = dbi->trackId( artid, m_track, autoCreate );
if( trkid < 1 )
return;
QString whereToken;
whereToken = QString( "WHERE id IS %1" ).arg( trkid );
QString sql = QString(
"SELECT k, v, timestamp, source "
"FROM social_attributes %1 "
"ORDER BY timestamp ASC" ).arg( whereToken );
query.prepare( sql );
query.exec();
QList< Tomahawk::SocialAction > allSocialActions;
while ( query.next() ) {
Tomahawk::SocialAction action;
@ -65,10 +66,10 @@ DatabaseCommand_LoadSocialActions::exec( DatabaseImpl* dbi )
action.value = query.value( 1 ); // comment
action.timestamp = query.value( 2 ); // timestamp
action.source = query.value( 3 ); // source
allSocialActions.append( action );
}
m_result->setAllSocialActions( allSocialActions );
}

View File

@ -80,12 +80,13 @@ DatabaseCommand_LogPlayback::exec( DatabaseImpl* dbi )
query.bindValue( 0, srcid );
bool isnew;
int artid = dbi->artistId( m_artist, isnew );
bool autoCreate = true;
int artid = dbi->artistId( m_artist, autoCreate );
if( artid < 1 )
return;
int trkid = dbi->trackId( artid, m_track, isnew );
autoCreate = true; // artistId overwrites autoCreate (reference)
int trkid = dbi->trackId( artid, m_track, autoCreate );
if( trkid < 1 )
return;

View File

@ -45,21 +45,22 @@ DatabaseCommand_SocialAction::exec( DatabaseImpl* dbi )
Q_ASSERT( !source().isNull() );
TomahawkSqlQuery query = dbi->newquery();
query.prepare( "INSERT INTO social_attributes(id, source, k, v, timestamp) "
"VALUES (?, ?, ?, ?, ?)" );
QVariant srcid = source()->isLocal() ? QVariant( QVariant::Int ) : source()->id();
bool isnew;
int artid = dbi->artistId( m_artist, isnew );
bool autoCreate = true;
int artid = dbi->artistId( m_artist, autoCreate );
if( artid < 1 )
return;
int trkid = dbi->trackId( artid, m_track, isnew );
autoCreate = true; // artistId overwrites autoCreate (reference)
int trkid = dbi->trackId( artid, m_track, autoCreate );
if( trkid < 1 )
return;
query.bindValue( 0, trkid );
query.bindValue( 1, srcid );
query.bindValue( 2, m_action );

View File

@ -224,7 +224,7 @@ DatabaseImpl::file( int fid )
"WHERE file.id = file_join.file AND file.id = %1" )
.arg( fid ) );
if( query.next() )
if ( query.next() )
{
Tomahawk::source_ptr s;
@ -266,10 +266,10 @@ DatabaseImpl::file( int fid )
int
DatabaseImpl::artistId( const QString& name_orig, bool& isnew )
DatabaseImpl::artistId( const QString& name_orig, bool& autoCreate )
{
isnew = false;
if( m_lastart == name_orig )
bool isnew = false;
if ( m_lastart == name_orig )
return m_lastartid;
int id = 0;
@ -279,31 +279,36 @@ DatabaseImpl::artistId( const QString& name_orig, bool& isnew )
query.prepare( "SELECT id FROM artist WHERE sortname = ?" );
query.addBindValue( sortname );
query.exec();
if( query.next() )
if ( query.next() )
{
id = query.value( 0 ).toInt();
}
if( id )
if ( id )
{
m_lastart = name_orig;
m_lastartid = id;
return id;
}
// not found, insert it.
query.prepare( "INSERT INTO artist(id,name,sortname) VALUES(NULL,?,?)" );
query.addBindValue( name_orig );
query.addBindValue( sortname );
if( !query.exec() )
if ( autoCreate )
{
qDebug() << "Failed to insert artist:" << name_orig;
return 0;
// not found, insert it.
query.prepare( "INSERT INTO artist(id,name,sortname) VALUES(NULL,?,?)" );
query.addBindValue( name_orig );
query.addBindValue( sortname );
if ( !query.exec() )
{
qDebug() << "Failed to insert artist:" << name_orig;
return 0;
}
id = query.lastInsertId().toInt();
isnew = true;
m_lastart = name_orig;
m_lastartid = id;
}
id = query.lastInsertId().toInt();
isnew = true;
m_lastart = name_orig;
m_lastartid = id;
autoCreate = isnew;
return id;
}

View File

@ -53,7 +53,7 @@ public:
TomahawkSqlQuery newquery() { return TomahawkSqlQuery( db ); }
QSqlDatabase& database() { return db; }
int artistId( const QString& name_orig, bool& isnew );
int artistId( const QString& name_orig, bool& autoCreate );
int trackId( int artistid, const QString& name_orig, bool& isnew );
int albumId( int artistid, const QString& name_orig, bool& isnew );

View File

@ -46,7 +46,7 @@ LastFmPlugin::LastFmPlugin()
: InfoPlugin()
, m_scrobbler( 0 )
{
m_supportedGetTypes << InfoAlbumCoverArt << InfoArtistImages;
m_supportedGetTypes << InfoAlbumCoverArt << InfoArtistImages << InfoArtistSimilars << InfoArtistSongs;
m_supportedPushTypes << InfoSubmitScrobble << InfoSubmitNowPlaying << InfoLove << InfoUnLove;
/*
@ -94,10 +94,10 @@ void
LastFmPlugin::namChangedSlot( QNetworkAccessManager *nam )
{
qDebug() << Q_FUNC_INFO;
if ( !nam )
return;
QNetworkAccessManager* currNam = lastfm::nam();
TomahawkUtils::NetworkProxyFactory* oldProxyFactory = dynamic_cast< TomahawkUtils::NetworkProxyFactory* >( nam->proxyFactory() );
@ -106,7 +106,7 @@ LastFmPlugin::namChangedSlot( QNetworkAccessManager *nam )
qDebug() << "Could not get old proxyFactory!";
return;
}
currNam->setConfiguration( nam->configuration() );
currNam->setNetworkAccessible( nam->networkAccessible() );
TomahawkUtils::NetworkProxyFactory* newProxyFactory = new TomahawkUtils::NetworkProxyFactory();
@ -142,6 +142,14 @@ LastFmPlugin::getInfo( const QString caller, const Tomahawk::InfoSystem::InfoTyp
fetchCoverArt( caller, type, input, customData );
break;
case InfoArtistSimilars:
fetchSimilarArtists( caller, type, input, customData );
break;
case InfoArtistSongs:
fetchTopTracks( caller, type, input, customData );
break;
default:
dataError( caller, type, input, customData );
}
@ -242,7 +250,7 @@ LastFmPlugin::sendLoveSong( const InfoType type, QVariant input )
bool ok;
track.setDuration( hash["duration"].toUInt( &ok ) );
track.setSource( lastfm::Track::Player );
if ( type == Tomahawk::InfoSystem::InfoLove )
{
track.love();
@ -254,6 +262,52 @@ LastFmPlugin::sendLoveSong( const InfoType type, QVariant input )
}
void
LastFmPlugin::fetchSimilarArtists( const QString &caller, const InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData )
{
qDebug() << Q_FUNC_INFO;
if ( !input.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() )
{
dataError( caller, type, input, customData );
return;
}
InfoCriteriaHash hash = input.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
if ( !hash.contains( "artist" ) )
{
dataError( caller, type, input, customData );
return;
}
Tomahawk::InfoSystem::InfoCriteriaHash criteria;
criteria["artist"] = hash["artist"];
emit getCachedInfo( criteria, 2419200000, caller, type, input, customData );
}
void
LastFmPlugin::fetchTopTracks( const QString &caller, const InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData )
{
qDebug() << Q_FUNC_INFO;
if ( !input.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() )
{
dataError( caller, type, input, customData );
return;
}
InfoCriteriaHash hash = input.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
if ( !hash.contains( "artist" ) )
{
dataError( caller, type, input, customData );
return;
}
Tomahawk::InfoSystem::InfoCriteriaHash criteria;
criteria["artist"] = hash["artist"];
emit getCachedInfo( criteria, 2419200000, caller, type, input, customData );
}
void
LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData )
{
@ -315,6 +369,32 @@ LastFmPlugin::notInCacheSlot( const QHash<QString, QString> criteria, const QStr
switch ( type )
{
case InfoArtistSimilars:
{
lastfm::Artist a( criteria["artist"] );
QNetworkReply* reply = a.getSimilar();
reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) );
reply->setProperty( "origData", input );
reply->setProperty( "caller", caller );
reply->setProperty( "type", (uint)(type) );
connect( reply, SIGNAL( finished() ), SLOT( similarArtistsReturned() ) );
return;
}
case InfoArtistSongs:
{
lastfm::Artist a( criteria["artist"] );
QNetworkReply* reply = a.getTopTracks();
reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) );
reply->setProperty( "origData", input );
reply->setProperty( "caller", caller );
reply->setProperty( "type", (uint)(type) );
connect( reply, SIGNAL( finished() ), SLOT( topTracksReturned() ) );
return;
}
case InfoAlbumCoverArt:
{
QString artistName = criteria["artist"];
@ -336,7 +416,7 @@ LastFmPlugin::notInCacheSlot( const QHash<QString, QString> criteria, const QStr
{
QString artistName = criteria["artist"];
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=artist.imageredirect&artist=%1&autocorrect=1&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b";
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=artist.imageredirect&artist=%1&autocorrect=1&size=large&api_key=7a90f6672a04b809ee309af169f34b8b";
QNetworkRequest req( imgurl.arg( artistName ) );
QNetworkReply* reply = lastfm::nam()->get( req );
reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) );
@ -358,6 +438,75 @@ LastFmPlugin::notInCacheSlot( const QHash<QString, QString> criteria, const QStr
}
void
LastFmPlugin::similarArtistsReturned()
{
qDebug() << Q_FUNC_INFO;
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
QMap< int, QString > similarArtists = lastfm::Artist::getSimilar( reply );
QStringList al;
QStringList sl;
foreach ( const QString& a, similarArtists.values() )
{
qDebug() << "Got sim-artist:" << a;
al << a;
}
InfoCustomData returnedData;
returnedData["artists"] = al;
returnedData["score"] = sl;
InfoCustomData customData = reply->property( "customData" ).value< Tomahawk::InfoSystem::InfoCustomData >();
InfoType type = (Tomahawk::InfoSystem::InfoType)(reply->property( "type" ).toUInt());
emit info(
reply->property( "caller" ).toString(),
type,
reply->property( "origData" ),
returnedData,
customData
);
InfoCriteriaHash origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCriteriaHash >();
Tomahawk::InfoSystem::InfoCriteriaHash criteria;
criteria["artist"] = origData["artist"];
// emit updateCache( criteria, 2419200000, type, returnedData );
}
void
LastFmPlugin::topTracksReturned()
{
qDebug() << Q_FUNC_INFO;
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
QStringList topTracks = lastfm::Artist::getTopTracks( reply );
foreach ( const QString& t, topTracks )
{
qDebug() << "Got top-track:" << t;
}
InfoCustomData returnedData;
returnedData["tracks"] = topTracks;
InfoCustomData customData = reply->property( "customData" ).value< Tomahawk::InfoSystem::InfoCustomData >();
InfoType type = (Tomahawk::InfoSystem::InfoType)(reply->property( "type" ).toUInt());
emit info(
reply->property( "caller" ).toString(),
type,
reply->property( "origData" ),
returnedData,
customData
);
InfoCriteriaHash origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCriteriaHash >();
Tomahawk::InfoSystem::InfoCriteriaHash criteria;
criteria["artist"] = origData["artist"];
//emit updateCache( criteria, 2419200000, type, returnedData );
}
void
LastFmPlugin::coverArtReturned()
{

View File

@ -49,6 +49,8 @@ public slots:
void onAuthenticated();
void coverArtReturned();
void artistImagesReturned();
void similarArtistsReturned();
void topTracksReturned();
void namChangedSlot( QNetworkAccessManager *nam );
@ -57,17 +59,19 @@ protected slots:
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData );
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data );
private:
void fetchCoverArt( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
void fetchArtistImages( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
void fetchSimilarArtists( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
void fetchTopTracks( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
void createScrobbler();
void nowPlaying( const QVariant &input );
void scrobble();
void sendLoveSong( const InfoType type, QVariant input );
void dataError( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
void sendLoveSong( const InfoType type, QVariant input );
lastfm::MutableTrack m_track;
lastfm::Audioscrobbler* m_scrobbler;

View File

@ -242,6 +242,8 @@ ArtistView::onScrollTimeout()
for ( int i = left.row(); i < max; i++ )
{
TreeModelItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( m_proxyModel->index( i, 0 ) ) );
if ( item->artist().isNull() )
continue;
Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
trackInfo["artist"] = item->artist()->name();

View File

@ -1,5 +1,5 @@
/* === 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
@ -43,18 +43,25 @@ InfoBar::InfoBar( QWidget* parent )
boldFont.setPixelSize( 12 );
ui->descriptionLabel->setFont( boldFont );
ui->descriptionLabel->setMargin( 10 );
QFont regFont = ui->longDescriptionLabel->font();
regFont.setPixelSize( 11 );
ui->longDescriptionLabel->setFont( regFont );
QPalette whitePal = ui->captionLabel->palette();
whitePal.setColor( QPalette::Foreground, Qt::white );
ui->captionLabel->setPalette( whitePal );
ui->descriptionLabel->setPalette( whitePal );
ui->longDescriptionLabel->setPalette( whitePal );
ui->captionLabel->setMargin( 6 );
ui->descriptionLabel->setMargin( 6 );
ui->longDescriptionLabel->setMargin( 6 );
ui->captionLabel->setText( QString() );
ui->captionLabel->setMargin( 6 );
ui->descriptionLabel->setText( QString() );
ui->longDescriptionLabel->setText( QString() );
ui->imageLabel->setText( QString() );
setAutoFillBackground( true );
@ -81,6 +88,13 @@ InfoBar::setDescription( const QString& s )
}
void
InfoBar::setLongDescription( const QString& s )
{
ui->longDescriptionLabel->setText( s );
}
void
InfoBar::setPixmap( const QPixmap& p )
{

View File

@ -1,5 +1,5 @@
/* === 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
@ -39,8 +39,9 @@ public:
public slots:
void setCaption( const QString& s );
void setDescription( const QString& s );
void setLongDescription( const QString& s );
void setPixmap( const QPixmap& p );
protected:
void changeEvent( QEvent* e );
void resizeEvent( QResizeEvent* e );

View File

@ -36,7 +36,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>32</width>
<width>16</width>
<height>20</height>
</size>
</property>
@ -65,7 +65,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>32</width>
<width>16</width>
<height>20</height>
</size>
</property>
@ -73,10 +73,13 @@
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="ElidedLabel" name="captionLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -89,7 +92,7 @@
<item>
<widget class="ElidedLabel" name="descriptionLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -101,6 +104,73 @@
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>16</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<widget class="QLabel" name="longDescriptionLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>62</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>62</height>
</size>
</property>
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
@ -111,7 +181,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>32</width>
<width>16</width>
<height>20</height>
</size>
</property>

View File

@ -378,6 +378,22 @@ TreeModel::addAllCollections()
}
void
TreeModel::addArtists( const artist_ptr& artist )
{
qDebug() << Q_FUNC_INFO;
if ( artist.isNull() )
return;
emit loadingStarted();
QList<Tomahawk::artist_ptr> artists;
artists << artist;
onArtistsAdded( artists );
}
void
TreeModel::addAlbums( const artist_ptr& artist, const QModelIndex& parent )
{
@ -494,21 +510,24 @@ TreeModel::onArtistsAdded( const QList<Tomahawk::artist_ptr>& artists )
void
TreeModel::onAlbumsAdded( const QList<Tomahawk::album_ptr>& albums, const QVariant& data )
{
qDebug() << Q_FUNC_INFO << albums.count();
qDebug() << Q_FUNC_INFO << albums.count() << data.toInt();
if ( !albums.count() )
return;
QModelIndex parent = index( data.toUInt(), 0, QModelIndex() );
QModelIndex parent = index( data.toInt(), 0, QModelIndex() );
TreeModelItem* parentItem = itemFromIndex( parent );
// the -1 is because we fake a rowCount of 1 to trigger Qt calling fetchMore()
int c = rowCount( parent ) - 1;
QPair< int, int > crows;
int c = rowCount( parent );
crows.first = c;
crows.second = c + albums.count() - 1;
if ( crows.second > 0 )
emit beginInsertRows( parent, crows.first + 1, crows.second );
if ( parent.isValid() )
crows.second -= 1;
qDebug() << crows.first << crows.second;
if ( !parent.isValid() || crows.second > 0 )
emit beginInsertRows( parent, crows.first, crows.second );
TreeModelItem* albumitem = 0;
foreach( const album_ptr& album, albums )
@ -528,7 +547,7 @@ TreeModel::onAlbumsAdded( const QList<Tomahawk::album_ptr>& albums, const QVaria
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
}
if ( crows.second > 0 )
if ( !parent.isValid() || crows.second > 0 )
emit endInsertRows();
else
emit dataChanged( albumitem->index, albumitem->index.sibling( albumitem->index.row(), columnCount( QModelIndex() ) - 1 ) );

View File

@ -80,6 +80,7 @@ public:
void addCollection( const Tomahawk::collection_ptr& collection );
void addFilteredCollection( const Tomahawk::collection_ptr& collection, unsigned int amount, DatabaseCommand_AllArtists::SortOrder order );
void addArtists( const Tomahawk::artist_ptr& artist );
void addAlbums( const Tomahawk::artist_ptr& artist, const QModelIndex& parent );
void addTracks( const Tomahawk::album_ptr& album, const QModelIndex& parent );

View File

@ -1,5 +1,5 @@
/* === 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
@ -98,19 +98,29 @@ ElidedLabel::setElideMode( Qt::TextElideMode mode )
}
}
void
void
ElidedLabel::setMargin( int margin )
{
m_margin = margin;
}
int
int
ElidedLabel::margin() const
{
return m_margin;
}
void
ElidedLabel::setFont( const QFont& font )
{
QWidget::setFont( font );
updateLabel();
}
void
ElidedLabel::init( const QString& txt )
{
@ -134,8 +144,7 @@ QSize
ElidedLabel::sizeHint() const
{
const QFontMetrics& fm = fontMetrics();
QSize size( fm.width( m_text ), fm.height() );
return size;
return QSize( fm.width( m_text ) + m_margin * 2, fm.height() + m_margin * 2 );
}
@ -164,7 +173,7 @@ ElidedLabel::paintEvent( QPaintEvent* event )
QPainter p( this );
QRect r = contentsRect();
r.adjust( m_margin, m_margin, -m_margin, -m_margin );
const QString elidedText = fontMetrics().elidedText( m_text, m_mode, r.width() );
p.drawText( r, m_align, elidedText );
}

View File

@ -1,5 +1,5 @@
/* === 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
@ -44,9 +44,11 @@ public:
Qt::TextElideMode elideMode() const;
void setElideMode( Qt::TextElideMode mode );
void setFont( const QFont& font );
void setMargin( int margin );
int margin() const;
virtual QSize sizeHint() const;
virtual QSize minimumSizeHint() const;
@ -65,7 +67,7 @@ protected:
virtual void mousePressEvent( QMouseEvent* event );
virtual void mouseReleaseEvent( QMouseEvent* event );
virtual void paintEvent( QPaintEvent* event );
private:
QTime m_time;
QString m_text;

View File

@ -25,8 +25,6 @@
#include "utils/animatedsplitter.h"
#include "infobar/infobar.h"
#include "topbar/topbar.h"
#include "widgets/infowidgets/sourceinfowidget.h"
#include "widgets/welcomewidget.h"
#include "treemodel.h"
#include "collectionflatmodel.h"
@ -47,6 +45,7 @@
#include "widgets/welcomewidget.h"
#include "widgets/infowidgets/sourceinfowidget.h"
#include "widgets/infowidgets/ArtistInfoWidget.h"
#include "widgets/newplaylistwidget.h"
#define FILTER_TIMEOUT 280
@ -217,28 +216,19 @@ ViewManager::show( const Tomahawk::dynplaylist_ptr& playlist )
Tomahawk::ViewPage*
ViewManager::show( const Tomahawk::artist_ptr& artist )
{
PlaylistView* view;
ArtistInfoWidget* swidget;
if ( !m_artistViews.contains( artist ) )
{
view = new PlaylistView();
PlaylistModel* model = new PlaylistModel();
view->setPlaylistModel( model );
view->setFrameShape( QFrame::NoFrame );
view->setAttribute( Qt::WA_MacShowFocusRect, 0 );
model->append( artist );
m_artistViews.insert( artist, view );
swidget = new ArtistInfoWidget( artist );
m_artistViews.insert( artist, swidget );
}
else
{
view = m_artistViews.value( artist );
swidget = m_artistViews.value( artist );
}
setPage( view );
emit numSourcesChanged( 1 );
return view;
setPage( swidget );
return swidget;
}
@ -367,8 +357,6 @@ ViewManager::show( const Tomahawk::source_ptr& source )
}
setPage( swidget );
emit numSourcesChanged( 1 );
return swidget;
}
@ -617,9 +605,15 @@ ViewManager::setPage( ViewPage* page, bool trackHistory )
if( obj->metaObject()->indexOfSignal( "descriptionChanged(QString)" ) > -1 )
connect( obj, SIGNAL( descriptionChanged( QString ) ), m_infobar, SLOT( setDescription( QString ) ), Qt::UniqueConnection );
if( obj->metaObject()->indexOfSignal( "longDescriptionChanged(QString)" ) > -1 )
connect( obj, SIGNAL( longDescriptionChanged( QString ) ), m_infobar, SLOT( setLongDescription( QString ) ), Qt::UniqueConnection );
if( obj->metaObject()->indexOfSignal( "nameChanged(QString)" ) > -1 )
connect( obj, SIGNAL( nameChanged( QString ) ), m_infobar, SLOT( setCaption( QString ) ), Qt::UniqueConnection );
if( obj->metaObject()->indexOfSignal( "pixmapChanged(QPixmap)" ) > -1 )
connect( obj, SIGNAL( pixmapChanged( QPixmap ) ), m_infobar, SLOT( setPixmap( QPixmap ) ), Qt::UniqueConnection );
if( obj->metaObject()->indexOfSignal( "destroyed(QWidget*)" ) > -1 )
connect( obj, SIGNAL( destroyed( QWidget* ) ), SLOT( onWidgetDestroyed( QWidget* ) ), Qt::UniqueConnection );
}
@ -724,6 +718,7 @@ ViewManager::updateView()
m_infobar->setCaption( currentPage()->title() );
m_infobar->setDescription( currentPage()->description() );
m_infobar->setLongDescription( currentPage()->longDescription() );
m_infobar->setPixmap( currentPage()->pixmap() );
// turn on shuffle/repeat mode for the new playlist view if specified in config

View File

@ -33,6 +33,7 @@
class AnimatedSplitter;
class AlbumModel;
class AlbumView;
class ArtistInfoWidget;
class ArtistView;
class CollectionModel;
class CollectionFlatModel;
@ -190,7 +191,7 @@ private:
QHash< Tomahawk::collection_ptr, CollectionView* > m_collectionViews;
QHash< Tomahawk::collection_ptr, ArtistView* > m_treeViews;
QHash< Tomahawk::collection_ptr, AlbumView* > m_collectionAlbumViews;
QHash< Tomahawk::artist_ptr, PlaylistView* > m_artistViews;
QHash< Tomahawk::artist_ptr, ArtistInfoWidget* > m_artistViews;
QHash< Tomahawk::album_ptr, PlaylistView* > m_albumViews;
QHash< Tomahawk::playlist_ptr, PlaylistView* > m_playlistViews;
QHash< Tomahawk::source_ptr, SourceInfoWidget* > m_sourceViews;

View File

@ -42,6 +42,7 @@ public:
virtual QString title() const = 0;
virtual QString description() const = 0;
virtual QString longDescription() const { return QString(); }
virtual QPixmap pixmap() const { return QPixmap( RESPATH "icons/tomahawk-icon-128x128.png" ); }
virtual bool showStatsBar() const { return true; }
@ -56,6 +57,8 @@ public:
/** subclasses implementing ViewPage can emit the following signals:
* nameChanged( const QString& )
* descriptionChanged( const QString& )
* longDescriptionChanged( const QString& )
* pixmapChanged( const QPixmap& )
* destroyed( QWidget* widget );
*
* See DynamicWidget for an example

View File

@ -0,0 +1,222 @@
/* === 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 "ArtistInfoWidget.h"
#include "ui_ArtistInfoWidget.h"
#include "utils/tomahawkutils.h"
#include "viewmanager.h"
#include "playlist/treemodel.h"
#include "playlist/playlistmodel.h"
#include "database/databasecommand_alltracks.h"
#include "database/databasecommand_allalbums.h"
#include "widgets/overlaywidget.h"
static QString s_aiInfoIdentifier = QString( "ArtistInfoWidget" );
using namespace Tomahawk;
ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* parent )
: QWidget( parent )
, ui( new Ui::ArtistInfoWidget )
, m_artist( artist )
{
ui->setupUi( this );
ui->albums->setFrameShape( QFrame::NoFrame );
ui->albums->setAttribute( Qt::WA_MacShowFocusRect, 0 );
ui->relatedArtists->setFrameShape( QFrame::NoFrame );
ui->relatedArtists->setAttribute( Qt::WA_MacShowFocusRect, 0 );
ui->topHits->setFrameShape( QFrame::NoFrame );
ui->topHits->setAttribute( Qt::WA_MacShowFocusRect, 0 );
TomahawkUtils::unmarginLayout( layout() );
m_albumsModel = new TreeModel( ui->albums );
ui->albums->setTreeModel( m_albumsModel );
m_relatedModel = new TreeModel( ui->relatedArtists );
ui->relatedArtists->setTreeModel( m_relatedModel );
m_topHitsModel = new PlaylistModel( ui->topHits );
m_topHitsModel->setStyle( TrackModel::Short );
ui->topHits->setTrackModel( m_topHitsModel );
m_pixmap = QPixmap( RESPATH "images/no-album-art-placeholder.png" ).scaledToWidth( 48, Qt::SmoothTransformation );
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
SLOT( infoSystemInfo( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ) );
connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) );
load( artist );
}
ArtistInfoWidget::~ArtistInfoWidget()
{
delete ui;
}
void
ArtistInfoWidget::load( const artist_ptr& artist )
{
m_title = artist->name();
m_albumsModel->addAlbums( artist, QModelIndex() );
Tomahawk::InfoSystem::InfoCriteriaHash artistInfo;
artistInfo["artist"] = artist->name();
InfoSystem::InfoTypeMap infoMap;
InfoSystem::InfoCustomData hash;
infoMap[InfoSystem::InfoArtistBiography] = artist->name();
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo(
s_aiInfoIdentifier, infoMap, hash );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo(
s_aiInfoIdentifier, Tomahawk::InfoSystem::InfoArtistImages,
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( artistInfo ), Tomahawk::InfoSystem::InfoCustomData() );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo(
s_aiInfoIdentifier, Tomahawk::InfoSystem::InfoArtistSimilars,
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( artistInfo ), Tomahawk::InfoSystem::InfoCustomData() );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo(
s_aiInfoIdentifier, Tomahawk::InfoSystem::InfoArtistSongs,
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( artistInfo ), Tomahawk::InfoSystem::InfoCustomData() );
}
void
ArtistInfoWidget::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData )
{
Q_UNUSED( input );
Q_UNUSED( customData );
if ( caller != s_aiInfoIdentifier )
{
// qDebug() << "Info of wrong type or not with our identifier";
return;
}
qDebug() << Q_FUNC_INFO << caller << type << s_aiInfoIdentifier;
InfoSystem::InfoCriteriaHash trackInfo;
trackInfo = input.value< InfoSystem::InfoCriteriaHash >();
if ( output.canConvert< Tomahawk::InfoSystem::InfoCustomData >() )
{
if ( trackInfo["artist"] != m_artist->name() )
{
qDebug() << "Returned info was for:" << trackInfo["artist"] << "- was looking for:" << m_artist->name();
return;
}
}
InfoSystem::InfoCustomData returnedData = output.value< Tomahawk::InfoSystem::InfoCustomData >();
switch ( type )
{
case InfoSystem::InfoArtistBiography:
{
InfoSystem::InfoGenericMap bmap = output.value< Tomahawk::InfoSystem::InfoGenericMap >();
foreach ( const QString& source, bmap.keys() )
{
if ( m_longDescription.isEmpty() || source == "last.fm" )
m_longDescription = bmap[source]["text"];
}
emit longDescriptionChanged( m_longDescription );
break;
}
case InfoSystem::InfoArtistSongs:
{
const QStringList tracks = returnedData["tracks"].toStringList();
int i = 0;
foreach ( const QString& track, tracks )
{
query_ptr query = Query::get( m_artist->name(), track, QString(), uuid() );
m_topHitsModel->append( query );
if ( ++i == 15 )
break;
}
break;
}
case InfoSystem::InfoArtistImages:
{
const QByteArray ba = returnedData["imgbytes"].toByteArray();
if ( ba.length() )
{
QPixmap pm;
pm.loadFromData( ba );
if ( !pm.isNull() )
m_pixmap = pm.scaledToHeight( 48, Qt::SmoothTransformation );
emit pixmapChanged( m_pixmap );
}
break;
}
case InfoSystem::InfoArtistSimilars:
{
const QStringList artists = returnedData["artists"].toStringList();
foreach ( const QString& artist, artists )
{
m_relatedModel->addArtists( Artist::get( artist ) );
}
break;
}
default:
return;
}
}
void
ArtistInfoWidget::infoSystemFinished( QString target )
{
Q_UNUSED( target );
qDebug() << Q_FUNC_INFO;
}
void
ArtistInfoWidget::changeEvent( QEvent* e )
{
QWidget::changeEvent( e );
switch ( e->type() )
{
case QEvent::LanguageChange:
ui->retranslateUi( this );
break;
default:
break;
}
}

View File

@ -0,0 +1,89 @@
/* === 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 ARTISTINFOWIDGET_H
#define ARTISTINFOWIDGET_H
#include <QWidget>
#include "artist.h"
#include "result.h"
#include "playlistinterface.h"
#include "viewpage.h"
#include "infosystem/infosystem.h"
#include "dllmacro.h"
class PlaylistModel;
class TreeModel;
namespace Ui
{
class ArtistInfoWidget;
}
class DLLEXPORT ArtistInfoWidget : public QWidget, public Tomahawk::ViewPage
{
Q_OBJECT
public:
ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* parent = 0 );
~ArtistInfoWidget();
void load( const Tomahawk::artist_ptr& artist );
virtual QWidget* widget() { return this; }
virtual Tomahawk::PlaylistInterface* playlistInterface() const { return 0; }
virtual QString title() const { return m_title; }
virtual QString description() const { return m_description; }
virtual QString longDescription() const { return m_longDescription; }
virtual QPixmap pixmap() const { if ( m_pixmap.isNull() ) return Tomahawk::ViewPage::pixmap(); else return m_pixmap; }
virtual bool showStatsBar() const { return false; }
virtual bool jumpToCurrentTrack() { return false; }
signals:
void longDescriptionChanged( const QString& description );
void descriptionChanged( const QString& description );
void pixmapChanged( const QPixmap& pixmap );
protected:
void changeEvent( QEvent* e );
private slots:
void infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
void infoSystemFinished( QString target );
private:
Ui::ArtistInfoWidget *ui;
Tomahawk::artist_ptr m_artist;
TreeModel* m_relatedModel;
TreeModel* m_albumsModel;
PlaylistModel* m_topHitsModel;
QString m_title;
QString m_description;
QString m_longDescription;
QPixmap m_pixmap;
};
#endif // SOURCEINFOWIDGET_H

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ArtistInfoWidget</class>
<widget class="QWidget" name="ArtistInfoWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>902</width>
<height>696</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="3,3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="HeaderLabel" name="label">
<property name="text">
<string>Top Hits</string>
</property>
</widget>
</item>
<item>
<widget class="PlaylistView" name="topHits"/>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="HeaderLabel" name="label_2">
<property name="text">
<string>Related Artists</string>
</property>
</widget>
</item>
<item>
<widget class="ArtistView" name="relatedArtists"/>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="HeaderLabel" name="label_3">
<property name="text">
<string>Albums</string>
</property>
</widget>
</item>
<item>
<widget class="ArtistView" name="albums"/>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>HeaderLabel</class>
<extends>QLabel</extends>
<header location="global">widgets/HeaderLabel.h</header>
</customwidget>
<customwidget>
<class>ArtistView</class>
<extends>QTreeView</extends>
<header location="global">artistview.h</header>
</customwidget>
<customwidget>
<class>PlaylistView</class>
<extends>QTreeView</extends>
<header location="global">playlistview.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -116,6 +116,13 @@ Artist::getTopTags() const
}
QNetworkReply*
Artist::getTopTracks() const
{
return ws::get( params("getTopTracks") );
}
QNetworkReply*
Artist::getSimilar() const
{
@ -154,6 +161,25 @@ Artist::getSimilar( QNetworkReply* r )
}
QStringList /* static */
Artist::getTopTracks( QNetworkReply* r )
{
QStringList tracks;
try
{
XmlQuery lfm = ws::parse(r);
foreach (XmlQuery e, lfm.children( "track" ))
{
tracks << e["name"].text();
}
}
catch (ws::ParseError& e)
{
qWarning() << e.what();
}
return tracks;
}
QList<Artist> /* static */
Artist::list( QNetworkReply* r )

View File

@ -86,6 +86,9 @@ namespace lastfm
/** use Tag::list to get the tag list out of the finished reply */
QNetworkReply* getTags() const;
QNetworkReply* getTopTags() const;
QNetworkReply* getTopTracks() const;
static QStringList getTopTracks( QNetworkReply* );
/** Last.fm dictates that you may submit at most 10 of these */
QNetworkReply* addTags( const QStringList& ) const;