diff --git a/resource.qrc b/resource.qrc deleted file mode 100644 index e69de29bb..000000000 diff --git a/resources.prc b/resources.prc deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/libtomahawk/infosystem/infoplugins/generic/musicbrainzPlugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/musicbrainzPlugin.cpp new file mode 100644 index 000000000..31efbd7c8 --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/generic/musicbrainzPlugin.cpp @@ -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 ) ); +} diff --git a/src/libtomahawk/infosystem/infoplugins/generic/musicbrainzPlugin.h b/src/libtomahawk/infosystem/infoplugins/generic/musicbrainzPlugin.h new file mode 100644 index 000000000..c1ccb0733 --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/generic/musicbrainzPlugin.h @@ -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 diff --git a/src/libtomahawk/infosystem/infosystem.h b/src/libtomahawk/infosystem/infosystem.h index 9ca664f8c..8ae527b51 100644 --- a/src/libtomahawk/infosystem/infosystem.h +++ b/src/libtomahawk/infosystem/infosystem.h @@ -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; diff --git a/src/libtomahawk/infosystem/infosystemworker.cpp b/src/libtomahawk/infosystem/infosystemworker.cpp index 399fb0318..0f5916673 100644 --- a/src/libtomahawk/infosystem/infosystemworker.cpp +++ b/src/libtomahawk/infosystem/infosystemworker.cpp @@ -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 ) ) diff --git a/src/libtomahawk/playlist/playlistitemdelegate.cpp b/src/libtomahawk/playlist/playlistitemdelegate.cpp index 68fe42143..dca3c7c92 100644 --- a/src/libtomahawk/playlist/playlistitemdelegate.cpp +++ b/src/libtomahawk/playlist/playlistitemdelegate.cpp @@ -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(); } diff --git a/src/libtomahawk/playlist/playlistitemdelegate.h b/src/libtomahawk/playlist/playlistitemdelegate.h index cd29e41d7..9fc11ab6f 100644 --- a/src/libtomahawk/playlist/playlistitemdelegate.h +++ b/src/libtomahawk/playlist/playlistitemdelegate.h @@ -53,6 +53,7 @@ private: unsigned int m_removalProgress; QPixmap m_nowPlayingIcon; + QPixmap m_arrowIcon; TrackView* m_view; TrackProxyModel* m_model; diff --git a/src/libtomahawk/playlist/trackview.cpp b/src/libtomahawk/playlist/trackview.cpp index d8bf6c0a1..b058638ff 100644 --- a/src/libtomahawk/playlist/trackview.cpp +++ b/src/libtomahawk/playlist/trackview.cpp @@ -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; + } + } +} diff --git a/src/libtomahawk/playlist/trackview.h b/src/libtomahawk/playlist/trackview.h index d2ad0de82..2a297d007 100644 --- a/src/libtomahawk/playlist/trackview.h +++ b/src/libtomahawk/playlist/trackview.h @@ -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; }; diff --git a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp index 2b1e7bdd0..17b54b64f 100644 --- a/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp @@ -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 ); }