PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/app/audioscrobbler/MetadataWindow.cpp

https://github.com/dougma/lastfm-desktop
C++ | 280 lines | 204 code | 42 blank | 34 comment | 4 complexity | 0d632836aa30f4473ceb73f0e27359d1 MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. Copyright 2005-2009 Last.fm Ltd.
  3. - Primarily authored by Max Howell, Jono Cole and Doug Mansell
  4. This file is part of the Last.fm Desktop Application Suite.
  5. lastfm-desktop is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. lastfm-desktop is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with lastfm-desktop. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "MetadataWindow.h"
  17. #include "ScrobbleStatus.h"
  18. #include "ScrobbleControls.h"
  19. #include "Application.h"
  20. #include "lib/unicorn/StylableWidget.h"
  21. #include <lastfm/Artist>
  22. #include <lastfm/XmlQuery>
  23. #include <lastfm/ws.h>
  24. #include <QLabel>
  25. #include <QPainter>
  26. #include <QPushButton>
  27. #include <QTextBrowser>
  28. #include <QNetworkReply>
  29. #include <QTextFrame>
  30. #include <QVBoxLayout>
  31. #include <QScrollArea>
  32. #include <QStatusBar>
  33. #include <QSizeGrip>
  34. #include <QDesktopServices>
  35. #include <QAbstractTextDocumentLayout>
  36. MetadataWindow::MetadataWindow()
  37. {
  38. setCentralWidget(new QWidget);
  39. QVBoxLayout* v = new QVBoxLayout(centralWidget());
  40. setMinimumWidth( 410 );
  41. v->addWidget(ui.now_playing_source = new ScrobbleStatus());
  42. ui.now_playing_source->setObjectName("now_playing");
  43. ui.now_playing_source->setFixedHeight( 22 );
  44. QVBoxLayout* vs;
  45. {
  46. QWidget* scrollWidget;
  47. QScrollArea* sa = new QScrollArea();
  48. sa->setWidgetResizable( true );
  49. sa->setWidget( scrollWidget = new StylableWidget(sa));
  50. sa->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
  51. vs = new QVBoxLayout( scrollWidget );
  52. v->addWidget( sa );
  53. }
  54. // listeners, scrobbles, tags:
  55. {
  56. QLabel* label;
  57. QGridLayout* grid = new QGridLayout();
  58. grid->setSpacing( 0 );
  59. {
  60. QVBoxLayout* v2 = new QVBoxLayout();
  61. grid->addWidget(ui.artist_image = new QLabel, 0, 0, Qt::AlignTop | Qt::AlignLeft );
  62. ui.artist_image->setObjectName("artist_image");
  63. v2->addWidget(ui.title = new QLabel);
  64. v2->addWidget(ui.album = new QLabel);
  65. v2->addStretch();
  66. ui.title->setObjectName("title1");
  67. ui.title->setTextInteractionFlags( Qt::TextSelectableByMouse );
  68. ui.title->setWordWrap(true);
  69. ui.album->setObjectName("title2");
  70. grid->addLayout(v2, 0, 1, Qt::AlignTop );
  71. }
  72. label = new QLabel(tr("Listeners"));
  73. label->setObjectName("name");
  74. label->setProperty("alternate", QVariant(true));
  75. label->setAlignment( Qt::AlignTop );
  76. grid->addWidget( label, 1, 0 );
  77. ui.listeners = new QLabel;
  78. ui.listeners->setObjectName("value");
  79. ui.listeners->setProperty("alternate", QVariant(true));
  80. grid->addWidget(ui.listeners, 1, 1);
  81. label = new QLabel(tr("Scrobbles"));
  82. label->setObjectName("name");
  83. label->setAlignment( Qt::AlignTop );
  84. grid->addWidget( label, 2, 0 );
  85. ui.scrobbles = new QLabel;
  86. ui.scrobbles->setObjectName("value");
  87. grid->addWidget(ui.scrobbles, 2, 1);
  88. label = new QLabel(tr("Tagged as"));
  89. label->setObjectName("name");
  90. label->setProperty("alternate", QVariant(true));
  91. label->setAlignment( Qt::AlignTop );
  92. grid->addWidget( label, 3, 0 );
  93. ui.tags = new QLabel;
  94. ui.tags->setObjectName("value");
  95. ui.tags->setProperty("alternate", QVariant(true));
  96. ui.tags->setWordWrap(true);
  97. grid->addWidget(ui.tags, 3, 1);
  98. // bio:
  99. label = new QLabel(tr("Biography"));
  100. label->setObjectName("name");
  101. label->setAlignment( Qt::AlignTop );
  102. grid->addWidget( label, 4, 0 );
  103. grid->addWidget(ui.bio = new QTextBrowser, 4, 1);
  104. ui.bio->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
  105. ui.bio->setOpenLinks( false );
  106. grid->setRowStretch( 4, 1 );
  107. vs->addLayout(grid, 1);
  108. vs->addStretch();
  109. }
  110. connect(ui.bio->document()->documentLayout(), SIGNAL( documentSizeChanged(QSizeF)), SLOT( onBioChanged(QSizeF)));
  111. connect(ui.bio, SIGNAL(anchorClicked(QUrl)), SLOT(onAnchorClicked(QUrl)));
  112. vs->setStretchFactor(ui.bio, 1);
  113. // status bar and scrobble controls
  114. {
  115. QStatusBar* status = new QStatusBar( this );
  116. //FIXME: this code is duplicated in the radio too
  117. //In order to compensate for the sizer grip on the bottom right
  118. //of the window, an empty QWidget is added as a spacer.
  119. QSizeGrip* sg = status->findChild<QSizeGrip *>();
  120. if( sg ) {
  121. int gripWidth = sg->sizeHint().width();
  122. QWidget* w = new QWidget( status );
  123. w->setFixedWidth( gripWidth );
  124. status->addWidget( w );
  125. }
  126. //Seemingly the only way to get a central widget in a QStatusBar
  127. //is to add an empty widget either side with a stretch value.
  128. status->addWidget( new QWidget( status), 1 );
  129. status->addWidget( ui.sc = new ScrobbleControls());
  130. status->addWidget( new QWidget( status), 1 );
  131. setStatusBar( status );
  132. }
  133. v->setSpacing(0);
  134. v->setMargin(0);
  135. vs->setSpacing(0);
  136. vs->setMargin(0);
  137. setWindowTitle(tr("Last.fm Audioscrobbler"));
  138. setUnifiedTitleAndToolBarOnMac( true );
  139. setMinimumHeight( 80 );
  140. resize(20, 500);
  141. }
  142. //ScrobbleControls*
  143. //MetadataWindow::scrobbleControls() const
  144. //{
  145. // return ui.sc;
  146. //}
  147. void
  148. MetadataWindow::onAnchorClicked( const QUrl& link )
  149. {
  150. QDesktopServices::openUrl( link );
  151. }
  152. void
  153. MetadataWindow::onBioChanged( const QSizeF& size )
  154. {
  155. ui.bio->setMinimumHeight( size.toSize().height() );
  156. }
  157. void
  158. MetadataWindow::onTrackStarted(const Track& t, const Track& previous)
  159. {
  160. const unsigned short em_dash = 0x2014;
  161. QString title = QString("%1 ") + QChar(em_dash) + " %2";
  162. ui.title->setText(title.arg(t.artist()).arg(t.title()));
  163. ui.album->setText("from " + t.album().title());
  164. m_currentTrack = t;
  165. ui.now_playing_source->onTrackStarted(t, previous);
  166. if (t.artist() != previous.artist()) {
  167. ui.bio->clear();
  168. ui.artist_image->clear();
  169. connect(t.artist().getInfo(), SIGNAL(finished()), SLOT(onArtistGotInfo()));
  170. //connect(t.album().getInfo(), SIGNAL(finished()), SLOT(onAlbumGotInfo()));
  171. }
  172. }
  173. void
  174. MetadataWindow::onArtistGotInfo()
  175. {
  176. XmlQuery lfm = static_cast<QNetworkReply*>(sender())->readAll();
  177. int scrobbles = lfm["artist"]["stats"]["playcount"].text().toInt();
  178. int listeners = lfm["artist"]["stats"]["listeners"].text().toInt();
  179. QString tags;
  180. foreach(const XmlQuery& e, lfm["artist"]["tags"].children("tag")) {
  181. if (tags.length()) {
  182. tags += ", ";
  183. }
  184. tags += e["name"].text();
  185. }
  186. ui.scrobbles->setText(QString("%L1").arg(scrobbles));
  187. ui.listeners->setText(QString("%L1").arg(listeners));
  188. ui.tags->setText(tags);
  189. QString stylesheet = ((audioscrobbler::Application*)qApp)->loadedStyleSheet() + styleSheet();
  190. QString style = "<style>" + stylesheet + "</style>";
  191. //TODO if empty suggest they edit it
  192. QString bio;
  193. {
  194. QStringList bioList = lfm["artist"]["bio"]["content"].text().trimmed().split( "\r" );
  195. foreach( const QString& p, bioList )
  196. bio += "<p>" + p + "</p>";
  197. }
  198. ui.bio->setHtml( style + bio );
  199. QTextFrame* root = ui.bio->document()->rootFrame();
  200. QTextFrameFormat f = root->frameFormat();
  201. f.setMargin(12);
  202. root->setFrameFormat(f);
  203. QUrl url = lfm["artist"]["image size=large"].text();
  204. QNetworkReply* reply = lastfm::nam()->get(QNetworkRequest(url));
  205. connect(reply, SIGNAL(finished()), SLOT(onArtistImageDownloaded()));
  206. }
  207. void
  208. MetadataWindow::onArtistImageDownloaded()
  209. {
  210. QPixmap px;
  211. px.loadFromData(static_cast<QNetworkReply*>(sender())->readAll());
  212. QLinearGradient g(QPoint(), px.rect().bottomLeft());
  213. g.setColorAt( 0.0, QColor(0, 0, 0, 0.11*255));
  214. g.setColorAt( 1.0, QColor(0, 0, 0, 0.88*255));
  215. QPainter p(&px);
  216. p.setCompositionMode(QPainter::CompositionMode_Multiply);
  217. p.fillRect(px.rect(), g);
  218. p.end();
  219. ui.artist_image->setFixedSize( px.size());
  220. ui.artist_image->setPixmap(px);
  221. }
  222. void
  223. MetadataWindow::onStopped()
  224. {
  225. ui.bio->clear();
  226. ui.artist_image->clear();
  227. ui.title->clear();
  228. ui.tags->clear();
  229. ui.album->clear();
  230. ui.listeners->clear();
  231. ui.scrobbles->clear();
  232. m_currentTrack = Track();
  233. ui.now_playing_source->onTrackStopped();
  234. }