File indexing completed on 2025-01-05 04:25:43
0001 /**************************************************************************************** 0002 * Copyright (c) 2009-2010 Joffrey Clavel <jclavel@clabert.info> * 0003 * Copyright (c) 2010 Alexandre Mendes <alex.mendes1988@gmail.com> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify it under * 0006 * the terms of the GNU General Public License as published by the Free Software * 0007 * Foundation; either version 2 of the License, or (at your option) any later * 0008 * version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0012 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License along with * 0015 * this program. If not, see <http://www.gnu.org/licenses/>. * 0016 ****************************************************************************************/ 0017 0018 #define DEBUG_PREFIX "ArtistWidget" 0019 0020 #include "ArtistWidget.h" 0021 0022 //Amarok 0023 #include "PaletteHandler.h" 0024 #include "SvgHandler.h" 0025 #include "amarokurls/AmarokUrl.h" 0026 #include "core/collections/Collection.h" 0027 #include "core/collections/QueryMaker.h" 0028 #include "core/meta/Meta.h" 0029 #include "core/support/Amarok.h" 0030 #include "core/support/Debug.h" 0031 #include "core-impl/collections/support/CollectionManager.h" 0032 #include "playlist/PlaylistController.h" 0033 0034 //KDE 0035 #include <KColorUtils> 0036 #include <KGlobalSettings> 0037 #include <QIcon> 0038 #include <Plasma/PushButton> 0039 #include <Plasma/Separator> 0040 0041 //Qt 0042 #include <QDesktopServices> 0043 #include <QFontMetricsF> 0044 #include <QGraphicsGridLayout> 0045 #include <QGraphicsLinearLayout> 0046 #include <QLabel> 0047 #include <QPainter> 0048 #include <QPixmapCache> 0049 #include <QSignalMapper> 0050 #include <QTextDocument> 0051 #include <QTimer> 0052 0053 #include <cmath> 0054 0055 ArtistWidget::ArtistWidget( const SimilarArtistPtr &artist, 0056 QGraphicsWidget *parent, Qt::WindowFlags wFlags ) 0057 : QGraphicsWidget( parent, wFlags ) 0058 , m_artist( artist ) 0059 { 0060 setAttribute( Qt::WA_NoSystemBackground, true ); 0061 0062 m_image = new QLabel; 0063 m_image->setAttribute( Qt::WA_NoSystemBackground, true ); 0064 m_image->setFixedSize( 128, 128 ); 0065 m_image->setCursor( Qt::PointingHandCursor ); 0066 QGraphicsProxyWidget *imageProxy = new QGraphicsProxyWidget( this ); 0067 imageProxy->setWidget( m_image ); 0068 m_image->installEventFilter( this ); 0069 0070 m_nameLabel = new QLabel; 0071 m_match = new QLabel; 0072 m_tagsLabel = new QLabel; 0073 m_topTrackLabel = new QLabel; 0074 m_bio = new QGraphicsWidget( this ); 0075 0076 QGraphicsProxyWidget *nameProxy = new QGraphicsProxyWidget( this ); 0077 QGraphicsProxyWidget *matchProxy = new QGraphicsProxyWidget( this ); 0078 QGraphicsProxyWidget *topTrackProxy = new QGraphicsProxyWidget( this ); 0079 QGraphicsProxyWidget *tagsProxy = new QGraphicsProxyWidget( this ); 0080 nameProxy->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); 0081 matchProxy->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred ); 0082 topTrackProxy->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); 0083 tagsProxy->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); 0084 imageProxy->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); 0085 0086 nameProxy->setWidget( m_nameLabel ); 0087 matchProxy->setWidget( m_match ); 0088 topTrackProxy->setWidget( m_topTrackLabel ); 0089 tagsProxy->setWidget( m_tagsLabel ); 0090 0091 m_nameLabel->setAttribute( Qt::WA_NoSystemBackground ); 0092 m_match->setAttribute( Qt::WA_NoSystemBackground ); 0093 m_topTrackLabel->setAttribute( Qt::WA_NoSystemBackground ); 0094 m_tagsLabel->setAttribute( Qt::WA_NoSystemBackground ); 0095 0096 m_image->setAlignment( Qt::AlignCenter ); 0097 m_match->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); 0098 m_nameLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); 0099 m_topTrackLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); 0100 m_tagsLabel->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); 0101 0102 m_nameLabel->setWordWrap( false ); 0103 m_match->setWordWrap( false ); 0104 m_topTrackLabel->setWordWrap( false ); 0105 m_tagsLabel->setWordWrap( false ); 0106 0107 m_match->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); 0108 m_topTrackLabel->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); 0109 m_match->setMinimumWidth( 10 ); 0110 m_topTrackLabel->setMinimumWidth( 10 ); 0111 m_nameLabel->setMinimumWidth( 10 ); 0112 m_tagsLabel->setMinimumWidth( 10 ); 0113 0114 QFontMetricsF fm( font() ); 0115 m_bio->setMinimumHeight( fm.lineSpacing() * 5 ); 0116 m_bio->setMaximumHeight( fm.lineSpacing() * 5 ); 0117 m_bio->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); 0118 m_bioLayout.setCacheEnabled( true ); 0119 0120 QFont artistFont; 0121 artistFont.setPointSize( artistFont.pointSize() + 2 ); 0122 artistFont.setBold( true ); 0123 m_nameLabel->setFont( artistFont ); 0124 m_topTrackLabel->setFont( KGlobalSettings::smallestReadableFont() ); 0125 m_tagsLabel->setFont( KGlobalSettings::smallestReadableFont() ); 0126 m_match->setFont( KGlobalSettings::smallestReadableFont() ); 0127 0128 m_navigateButton = new Plasma::PushButton( this ); 0129 m_navigateButton->setMaximumSize( QSizeF( 22, 22 ) ); 0130 m_navigateButton->setIcon( QIcon::fromTheme( "edit-find" ) ); 0131 m_navigateButton->setToolTip( i18n( "Show in Media Sources" ) ); 0132 connect( m_navigateButton, SIGNAL(clicked()), this, SLOT(navigateToArtist()) ); 0133 0134 m_lastfmStationButton = new Plasma::PushButton( this ); 0135 m_lastfmStationButton->setMaximumSize( QSizeF( 22, 22 ) ); 0136 m_lastfmStationButton->setIcon( QIcon::fromTheme("view-services-lastfm-amarok") ); 0137 m_lastfmStationButton->setToolTip( i18n( "Add Last.fm artist station to the Playlist" ) ); 0138 connect( m_lastfmStationButton, SIGNAL(clicked()), this, SLOT(addLastfmArtistStation()) ); 0139 0140 m_topTrackButton = new Plasma::PushButton( this ); 0141 m_topTrackButton->setMaximumSize( QSizeF( 22, 22 ) ); 0142 m_topTrackButton->setIcon( QIcon::fromTheme( "media-track-add-amarok" ) ); 0143 m_topTrackButton->setToolTip( i18n( "Add top track to the Playlist" ) ); 0144 m_topTrackButton->hide(); 0145 connect( m_topTrackButton, SIGNAL(clicked()), this, SLOT(addTopTrackToPlaylist()) ); 0146 0147 m_similarArtistButton = new Plasma::PushButton( this ); 0148 m_similarArtistButton->setMaximumSize( QSizeF( 22, 22 ) ); 0149 m_similarArtistButton->setIcon( QIcon::fromTheme( "similarartists-amarok" ) ); 0150 m_similarArtistButton->setToolTip( i18n( "Show Similar Artists to %1", m_artist->name() ) ); 0151 connect( m_similarArtistButton, SIGNAL(clicked()), this, SIGNAL(showSimilarArtists()) ); 0152 0153 QGraphicsLinearLayout *buttonsLayout = new QGraphicsLinearLayout( Qt::Horizontal ); 0154 buttonsLayout->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred ); 0155 buttonsLayout->addItem( m_topTrackButton ); 0156 buttonsLayout->addItem( m_navigateButton ); 0157 buttonsLayout->addItem( m_lastfmStationButton ); 0158 0159 QString artistUrl = m_artist->url().url(); 0160 if( !artistUrl.isEmpty() ) 0161 { 0162 m_urlButton = new Plasma::PushButton( this ); 0163 m_urlButton->setMaximumSize( QSizeF( 22, 22 ) ); 0164 m_urlButton->setIcon( QIcon::fromTheme("internet-services") ); 0165 m_urlButton->setToolTip( i18n( "Open Last.fm webpage for this artist" ) ); 0166 connect( m_urlButton, SIGNAL(clicked()), this, SLOT(openArtistUrl()) ); 0167 buttonsLayout->addItem( m_urlButton ); 0168 } 0169 0170 buttonsLayout->addItem( m_similarArtistButton ); 0171 0172 // the image display is extended on two row 0173 m_layout = new QGraphicsGridLayout( this ); 0174 m_layout->addItem( imageProxy, 0, 0, 4, 1 ); 0175 m_layout->addItem( nameProxy, 0, 1 ); 0176 m_layout->addItem( buttonsLayout, 0, 2, Qt::AlignRight ); 0177 m_layout->addItem( topTrackProxy, 1, 1 ); 0178 m_layout->addItem( matchProxy, 1, 2, Qt::AlignRight ); 0179 m_layout->addItem( tagsProxy, 2, 1, 1, 2 ); 0180 m_layout->addItem( m_bio, 3, 1, 1, 2 ); 0181 0182 m_match->setText( i18n( "Match: %1%", QString::number( m_artist->match() ) ) ); 0183 m_nameLabel->setText( m_artist->name() ); 0184 0185 QTimer::singleShot( 0, this, SLOT(updateInfo()) ); 0186 } 0187 0188 void 0189 ArtistWidget::updateInfo() 0190 { 0191 fetchPhoto(); 0192 fetchInfo(); 0193 fetchTopTrack(); 0194 } 0195 0196 ArtistWidget::~ArtistWidget() 0197 { 0198 clear(); 0199 } 0200 0201 bool 0202 ArtistWidget::eventFilter( QObject *obj, QEvent *event ) 0203 { 0204 if( obj == m_image ) 0205 { 0206 if( event->type() == QEvent::MouseButtonPress ) 0207 { 0208 emit showBio(); 0209 event->accept(); 0210 return true; 0211 } 0212 } 0213 return QGraphicsWidget::eventFilter( obj, event ); 0214 } 0215 0216 void 0217 ArtistWidget::fetchPhoto() 0218 { 0219 // display a message for the user while the fetch of the picture 0220 m_image->clear(); 0221 0222 QPixmap image; 0223 if( QPixmapCache::find( m_artist->urlImage().url(), &image ) ) 0224 { 0225 m_image->setPixmap( image ); 0226 return; 0227 } 0228 m_image->setPixmap( Amarok::semiTransparentLogo( 120 ) ); 0229 0230 if( m_artist->urlImage().isEmpty() ) 0231 return; 0232 0233 The::networkAccessManager()->getData( m_artist->urlImage(), this, 0234 SLOT(photoFetched(QUrl,QByteArray,NetworkAccessManagerProxy::Error)) ); 0235 } 0236 0237 void 0238 ArtistWidget::fetchInfo() 0239 { 0240 // we generate the url for the demand on the lastFM Api 0241 QUrl url; 0242 url.setScheme( "http" ); 0243 url.setHost( "ws.audioscrobbler.com" ); 0244 url.setPath( "/2.0/" ); 0245 url.addQueryItem( "method", "artist.getInfo" ); 0246 url.addQueryItem( "api_key", Amarok::lastfmApiKey() ); 0247 url.addQueryItem( "artist", m_artist->name() ); 0248 0249 The::networkAccessManager()->getData( url, this, 0250 SLOT(parseInfo(QUrl,QByteArray,NetworkAccessManagerProxy::Error)) ); 0251 } 0252 0253 void 0254 ArtistWidget::fetchTopTrack() 0255 { 0256 // we generate the url for the demand on the lastFM Api 0257 QUrl url; 0258 url.setScheme( "http" ); 0259 url.setHost( "ws.audioscrobbler.com" ); 0260 url.setPath( "/2.0/" ); 0261 url.addQueryItem( "method", "artist.getTopTracks" ); 0262 url.addQueryItem( "api_key", Amarok::lastfmApiKey() ); 0263 url.addQueryItem( "artist", m_artist->name() ); 0264 0265 The::networkAccessManager()->getData( url, this, 0266 SLOT(parseTopTrack(QUrl,QByteArray,NetworkAccessManagerProxy::Error)) ); 0267 } 0268 0269 void 0270 ArtistWidget::photoFetched( const QUrl &url, QByteArray data, NetworkAccessManagerProxy::Error e ) 0271 { 0272 if( url != m_artist->urlImage() ) 0273 return; 0274 0275 if( e.code != QNetworkReply::NoError ) 0276 { 0277 m_image->clear(); 0278 m_image->setText( i18n( "Unable to fetch the picture: %1", e.description ) ); 0279 return; 0280 } 0281 0282 QPixmap image; 0283 if( image.loadFromData( data ) ) 0284 { 0285 image = image.scaled( 116, 116, Qt::KeepAspectRatio, Qt::SmoothTransformation ); 0286 image = The::svgHandler()->addBordersToPixmap( image, 6, QString(), true ); 0287 m_image->setToolTip( i18nc( "@info:tooltip Artist biography", "Show Biography" ) ); 0288 m_image->setPixmap( image ); 0289 QPixmapCache::insert( url.url(), image ); 0290 } 0291 } 0292 0293 void 0294 ArtistWidget::parseInfo( const QUrl &url, QByteArray data, NetworkAccessManagerProxy::Error e ) 0295 { 0296 Q_UNUSED( url ) 0297 if( e.code != QNetworkReply::NoError ) 0298 return; 0299 0300 if( data.isEmpty() ) 0301 return; 0302 0303 QXmlStreamReader xml( data ); 0304 xml.readNextStartElement(); // lfm 0305 if( xml.attributes().value(QLatin1String("status")) != QLatin1String("ok") ) 0306 { 0307 setBioSummary( QString() ); 0308 return; 0309 } 0310 0311 QString summary; 0312 xml.readNextStartElement(); // artist 0313 while( xml.readNextStartElement() ) 0314 { 0315 if( xml.name() == QLatin1String("tags") ) 0316 { 0317 m_tags.clear(); 0318 while( xml.readNextStartElement() ) 0319 { 0320 if( xml.name() != QLatin1String("tag") ) 0321 continue; 0322 0323 while( xml.readNextStartElement() ) 0324 { 0325 if( xml.name() == QLatin1String("name") ) 0326 m_tags << xml.readElementText(); 0327 else 0328 xml.skipCurrentElement(); 0329 } 0330 } 0331 } 0332 else if( xml.name() == QLatin1String("bio") ) 0333 { 0334 while( xml.readNextStartElement() ) 0335 { 0336 if( xml.name() == QLatin1String("published") ) 0337 m_fullBio.first = KDateTime::fromString( xml.readElementText(), "%a, %d %b %Y %H:%M:%S" ); 0338 else if( xml.name() == QLatin1String("summary") ) 0339 summary = xml.readElementText().simplified(); 0340 else if( xml.name() == QLatin1String("content") ) 0341 m_fullBio.second = xml.readElementText().replace( QRegExp("\n+"), QLatin1String("<br>") ); 0342 else 0343 xml.skipCurrentElement(); 0344 } 0345 } 0346 else 0347 xml.skipCurrentElement(); 0348 } 0349 setBioSummary( summary ); 0350 setTags(); 0351 } 0352 0353 void 0354 ArtistWidget::parseTopTrack( const QUrl &url, QByteArray data, NetworkAccessManagerProxy::Error e ) 0355 { 0356 Q_UNUSED( url ) 0357 if( e.code != QNetworkReply::NoError ) 0358 return; 0359 0360 if( data.isEmpty() ) 0361 return; 0362 0363 QXmlStreamReader xml( data ); 0364 xml.readNextStartElement(); // lfm 0365 if( xml.attributes().value(QLatin1String("status")) != QLatin1String("ok") ) 0366 { 0367 setTopTrack( QString() ); 0368 return; 0369 } 0370 0371 QString topTrack; 0372 xml.readNextStartElement(); // toptracks 0373 while( xml.readNextStartElement() ) 0374 { 0375 if( xml.name() != QLatin1String("track") ) 0376 { 0377 xml.skipCurrentElement(); 0378 continue; 0379 } 0380 0381 while( xml.readNextStartElement() ) 0382 { 0383 if( xml.name() != QLatin1String("name") ) 0384 { 0385 xml.skipCurrentElement(); 0386 continue; 0387 } 0388 topTrack = xml.readElementText(); 0389 break; 0390 } 0391 0392 if( !topTrack.isEmpty() ) 0393 break; 0394 } 0395 setTopTrack( topTrack ); 0396 } 0397 0398 SimilarArtistPtr 0399 ArtistWidget::artist() const 0400 { 0401 return m_artist; 0402 } 0403 0404 void 0405 ArtistWidget::clear() 0406 { 0407 m_image->clear(); 0408 m_nameLabel->clear(); 0409 m_match->clear(); 0410 m_topTrackLabel->clear(); 0411 } 0412 0413 void 0414 ArtistWidget::openArtistUrl() 0415 { 0416 // somehow Last.fm decides to supply this url without the scheme 0417 QUrl artistUrl = QString( "http://%1" ).arg( m_artist->url().url() ); 0418 if( artistUrl.isValid() ) 0419 QDesktopServices::openUrl( artistUrl ); 0420 } 0421 0422 void 0423 ArtistWidget::setBioSummary( const QString &bio ) 0424 { 0425 if( bio.isEmpty() ) 0426 { 0427 m_bioLayout.clearLayout(); 0428 m_bioLayout.setText( i18n( "No description available." ) ); 0429 } 0430 else 0431 { 0432 QTextDocument doc; 0433 doc.setHtml( bio ); 0434 QString plain = doc.toPlainText(); 0435 m_bioLayout.setText( plain ); 0436 } 0437 layoutBio(); 0438 } 0439 0440 void 0441 ArtistWidget::setTags() 0442 { 0443 QString tags = m_tags.isEmpty() ? i18n( "none" ) : m_tags.join( QLatin1String(", ") ); 0444 QString label = i18nc( "@label:textbox", "Tags: %1", tags ); 0445 m_tagsLabel->setText( label ); 0446 } 0447 0448 void 0449 ArtistWidget::setTopTrack( const QString &topTrack ) 0450 { 0451 if( topTrack.isEmpty() ) 0452 { 0453 m_topTrackLabel->setText( i18n("Top track not found") ); 0454 m_topTrackButton->hide(); 0455 } 0456 else 0457 { 0458 m_topTrackTitle = topTrack; 0459 m_topTrackLabel->setText( i18n("Top track: %1", topTrack) ); 0460 0461 Collections::QueryMaker *qm = CollectionManager::instance()->queryMaker(); 0462 0463 qm->setQueryType( Collections::QueryMaker::Track ); 0464 qm->beginAnd(); 0465 qm->addFilter( Meta::valArtist, m_nameLabel->text() ); 0466 qm->addFilter( Meta::valTitle, m_topTrackTitle ); 0467 qm->endAndOr(); 0468 qm->limitMaxResultSize( 1 ); 0469 qm->setAutoDelete( true ); 0470 0471 connect( qm, SIGNAL(newResultReady(Meta::TrackList)), 0472 SLOT(resultReady(Meta::TrackList)) ); 0473 0474 qm->run(); 0475 } 0476 } 0477 0478 void 0479 ArtistWidget::resizeEvent( QGraphicsSceneResizeEvent *event ) 0480 { 0481 QGraphicsWidget::resizeEvent( event ); 0482 layoutBio(); 0483 QFontMetrics fm( m_match->font() ); 0484 m_match->setMaximumWidth( fm.horizontalAdvance( m_match->text() ) ); 0485 } 0486 0487 void 0488 ArtistWidget::paint( QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *widget ) 0489 { 0490 QGraphicsWidget::paint( p, option, widget ); 0491 0492 p->save(); 0493 QFontMetricsF fm( m_bio->font() ); 0494 QPointF pos = m_bio->geometry().topLeft(); 0495 const int maxLines = floor( m_bio->size().height() / fm.lineSpacing() ); 0496 for( int i = 0, lines = m_bioLayout.lineCount(); i < lines; ++i ) 0497 { 0498 const QTextLine &line = m_bioLayout.lineAt( i ); 0499 if( m_bioCropped && (i == (maxLines - 1)) ) 0500 { 0501 // fade out the last bit of text if not all of the bio is shown 0502 QLinearGradient alphaGradient( 0, 0, 1, 0 ); 0503 alphaGradient.setCoordinateMode( QGradient::ObjectBoundingMode ); 0504 const QColor &textColor = The::paletteHandler()->palette().text().color(); 0505 alphaGradient.setColorAt( 0, textColor ); 0506 alphaGradient.setColorAt( 0.85, textColor ); 0507 alphaGradient.setColorAt( 1, Qt::transparent ); 0508 QPen pen = p->pen(); 0509 pen.setBrush( alphaGradient ); 0510 p->setPen( pen ); 0511 } 0512 line.draw( p, pos ); 0513 pos.ry() += line.leading(); 0514 } 0515 p->restore(); 0516 } 0517 0518 void 0519 ArtistWidget::layoutBio() 0520 { 0521 QFontMetricsF fm( m_bio->font() ); 0522 QRectF geom = m_bio->geometry(); 0523 int maxLines = floor( m_bio->size().height() / fm.lineSpacing() ); 0524 int leading = fm.leading(); 0525 qreal height = 0; 0526 m_bioCropped = true; 0527 m_bioLayout.clearLayout(); 0528 m_bioLayout.beginLayout(); 0529 while( m_bioLayout.lineCount() < maxLines ) 0530 { 0531 QTextLine line = m_bioLayout.createLine(); 0532 if( !line.isValid() ) 0533 { 0534 m_bioCropped = false; 0535 break; 0536 } 0537 0538 line.setLineWidth( geom.width() ); 0539 height += leading; 0540 line.setPosition( QPointF(0, height) ); 0541 height += line.height(); 0542 } 0543 m_bioLayout.endLayout(); 0544 update(); 0545 } 0546 0547 KDateTime 0548 ArtistWidget::bioPublished() const 0549 { 0550 return m_fullBio.first; 0551 } 0552 0553 QString 0554 ArtistWidget::fullBio() const 0555 { 0556 return m_fullBio.second; 0557 } 0558 0559 void 0560 ArtistWidget::addTopTrackToPlaylist() 0561 { 0562 The::playlistController()->insertOptioned( m_topTrack, Playlist::OnAppendToPlaylistAction ); 0563 } 0564 0565 void 0566 ArtistWidget::navigateToArtist() 0567 { 0568 AmarokUrl url; 0569 url.setCommand( "navigate" ); 0570 url.setPath( "collections" ); 0571 url.setArg( "filter", "artist:\"" + AmarokUrl::escape( m_artist->name() ) + '\"' ); 0572 url.run(); 0573 } 0574 0575 void 0576 ArtistWidget::addLastfmArtistStation() 0577 { 0578 const QString url = "lastfm://artist/" + m_artist->name() + "/similarartists"; 0579 Meta::TrackPtr lastfmtrack = CollectionManager::instance()->trackForUrl( QUrl( url ) ); 0580 The::playlistController()->insertOptioned( lastfmtrack, Playlist::OnAppendToPlaylistAction ); 0581 } 0582 0583 ArtistsListWidget::ArtistsListWidget( QGraphicsWidget *parent ) 0584 : Plasma::ScrollWidget( parent ) 0585 , m_separatorCount( 0 ) 0586 { 0587 QGraphicsWidget *content = new QGraphicsWidget( this ); 0588 m_layout = new QGraphicsLinearLayout( Qt::Vertical, content ); 0589 setWidget( content ); 0590 0591 m_showArtistsSigMapper = new QSignalMapper( this ); 0592 connect( m_showArtistsSigMapper, SIGNAL(mapped(QString)), SIGNAL(showSimilarArtists(QString)) ); 0593 0594 m_showBioSigMapper = new QSignalMapper( this ); 0595 connect( m_showBioSigMapper, SIGNAL(mapped(QString)), SIGNAL(showBio(QString)) ); 0596 } 0597 0598 ArtistsListWidget::~ArtistsListWidget() 0599 { 0600 clear(); 0601 } 0602 0603 int 0604 ArtistsListWidget::count() const 0605 { 0606 return m_layout->count() - m_separatorCount; 0607 } 0608 0609 void 0610 ArtistsListWidget::addArtist( const SimilarArtistPtr &artist ) 0611 { 0612 if( !m_widgets.isEmpty() ) 0613 addSeparator(); 0614 ArtistWidget *widget = new ArtistWidget( artist ); 0615 const QString &name = artist->name(); 0616 connect( widget, SIGNAL(showSimilarArtists()), m_showArtistsSigMapper, SLOT(map()) ); 0617 m_showArtistsSigMapper->setMapping( widget, name ); 0618 connect( widget, SIGNAL(showBio()), m_showBioSigMapper, SLOT(map()) ); 0619 m_showBioSigMapper->setMapping( widget, name ); 0620 m_layout->addItem( widget ); 0621 m_widgets << widget; 0622 } 0623 0624 void 0625 ArtistsListWidget::addArtists( const SimilarArtist::List &artists ) 0626 { 0627 foreach( const SimilarArtistPtr &artist, artists ) 0628 addArtist( artist ); 0629 updateGeometry(); 0630 } 0631 0632 void 0633 ArtistsListWidget::addSeparator() 0634 { 0635 m_layout->addItem( new Plasma::Separator ); 0636 ++m_separatorCount; 0637 } 0638 0639 void 0640 ArtistsListWidget::clear() 0641 { 0642 qDeleteAll( m_widgets ); 0643 m_widgets.clear(); 0644 int count = m_layout->count(); 0645 if( count > 0 ) 0646 { 0647 while( --count >= 0 ) 0648 { 0649 QGraphicsLayoutItem *child = m_layout->itemAt( 0 ); 0650 m_layout->removeItem( child ); 0651 delete child; 0652 } 0653 m_separatorCount = 0; 0654 } 0655 m_layout->invalidate(); 0656 updateGeometry(); 0657 } 0658 0659 QSizeF 0660 ArtistsListWidget::sizeHint( Qt::SizeHint which, const QSizeF &constraint ) const 0661 { 0662 QSizeF sz = Plasma::ScrollWidget::sizeHint( which, constraint ); 0663 if( count() == 0 ) 0664 sz.rheight() = 0; 0665 return sz; 0666 } 0667 0668 bool 0669 ArtistsListWidget::isEmpty() const 0670 { 0671 return count() == 0; 0672 } 0673 0674 QString 0675 ArtistsListWidget::name() const 0676 { 0677 return m_name; 0678 } 0679 0680 void 0681 ArtistsListWidget::setName( const QString &name ) 0682 { 0683 m_name = name; 0684 } 0685 0686 ArtistWidget * 0687 ArtistsListWidget::widget( const QString &artistName ) 0688 { 0689 foreach( ArtistWidget *widget, m_widgets ) 0690 { 0691 if( widget->artist()->name() == artistName ) 0692 return widget; 0693 } 0694 return 0; 0695 } 0696 0697 void 0698 ArtistWidget::resultReady( const Meta::TrackList &tracks ) 0699 { 0700 if( !tracks.isEmpty() ) 0701 { 0702 m_topTrack = tracks.first(); 0703 m_topTrackButton->show(); 0704 } 0705 } 0706