From 9caf9fc98fac6b70b4cf35f15e2c31e81fcd0a33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20Lindstr=C3=B6m?= <hugolm84@gmail.com>
Date: Thu, 6 Oct 2011 23:00:19 +0200
Subject: [PATCH] Adding charts for Billboard and Itunes

---
 .../infoplugins/generic/chartsplugin.cpp      | 188 +++++++++---------
 .../infoplugins/generic/chartsplugin.h        |   1 -
 src/libtomahawk/widgets/whatshotwidget.cpp    |  34 ++--
 src/libtomahawk/widgets/whatshotwidget.ui     |  20 +-
 4 files changed, 114 insertions(+), 129 deletions(-)

diff --git a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp
index 868b90739..025308680 100644
--- a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp
+++ b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.cpp
@@ -52,9 +52,20 @@ ChartsPlugin::ChartsPlugin()
 
     tDebug() << "ChartsPlugin: InfoChart fetching possible resources";
 
-    QUrl url = QUrl(CHART_URL);
-    QNetworkReply* reply = lastfm::nam()->get( QNetworkRequest( url ) );
-    connect( reply, SIGNAL( finished() ), SLOT( chartResources() ) );
+    /// Add resources here
+    m_chartResources << "billboard"
+                     << "itunes";
+
+    /// Then get each chart from resource
+    if(!m_chartResources.isEmpty()){
+
+        foreach(QVariant resource, m_chartResources)
+        {
+            QUrl url = QUrl( QString( CHART_URL "source/%1" ).arg(resource.toString() ) );
+            QNetworkReply* reply = lastfm::nam()->get( QNetworkRequest( url ) );
+            connect( reply, SIGNAL( finished() ), SLOT( chartTypes() ) );
+        }
+    }
 
     m_supportedGetTypes <<  InfoChart << InfoChartCapabilities;
 
@@ -112,29 +123,29 @@ ChartsPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoTy
 }
 
 
-
-
 void
 ChartsPlugin::fetchChart( uint requestId, Tomahawk::InfoSystem::InfoRequestData requestData )
 {
+
     if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() )
     {
         dataError( requestId, requestData );
         return;
     }
+
     InfoCriteriaHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
     Tomahawk::InfoSystem::InfoCriteriaHash criteria;
-    if ( !hash.contains( "chart_id" ) )
+
+    /// Each request needs to contain both a id and source
+    if ( !hash.contains( "chart_id" ) && !hash.contains( "chart_source" ) )
     {
         dataError( requestId, requestData );
         return;
-    } else {
-        criteria["chart_id"] = hash["chart_id"];
-    }
-    if ( hash.contains( "chart_source" ) )
-    {
-        criteria["chart_source"] = hash["chart_source"];
+
     }
+    /// Set the criterias for current chart
+    criteria["chart_id"] = hash["chart_id"];
+    criteria["chart_source"] = hash["chart_source"];
 
     emit getCachedInfo( requestId, criteria, 0, requestData );
 }
@@ -147,7 +158,8 @@ ChartsPlugin::fetchChartCapabilities( uint requestId, Tomahawk::InfoSystem::Info
         dataError( requestId, requestData );
         return;
     }
-    InfoCriteriaHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
+
+    //InfoCriteriaHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
     Tomahawk::InfoSystem::InfoCriteriaHash criteria;
 
     emit getCachedInfo( requestId, criteria, 0, requestData );
@@ -168,9 +180,11 @@ ChartsPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
         case InfoChart:
         {
 
+            /// Fetch the chart, we need source and id
             QUrl url = QUrl( QString( CHART_URL "/source/%1/chart/%2" ).arg( criteria["chart_source"] ).arg( criteria["chart_id"] ) );
             qDebug() << Q_FUNC_INFO << "Getting chart url" << url;
 
+            /// @todo: Should add ChartPlugin nam here
             QNetworkReply* reply = lastfm::nam()->get( QNetworkRequest( url ) );
             reply->setProperty( "requestId", requestId );
             reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
@@ -193,12 +207,15 @@ ChartsPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
                 if( !m_chartTypes.isEmpty() )
                     foreach( QVariant type, m_chartTypes )
                     {
-                        // Itunes supplys charts based on geo, for now, only take US charts
+                        /// Itunes supplys charts based on geo, for now, only take US charts
+                        /// @todo: Add new breadcrumb option for country?
                         if( type.toMap().value( "source" ).toString() == chartResource.toString()
                             && type.toMap().value( "geo" ).isValid()
                             && type.toMap().value( "geo" ).toString() != "us" )
                                 continue;
 
+                        /// Append each type to its parent source
+                        /// @todo Add chartType enum
                         if( type.toMap().value( "source" ).toString() == chartResource.toString() )
                         {
                             if( type.toMap().value( "type" ).toString() == "Album" )
@@ -213,8 +230,13 @@ ChartsPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
                             }
                         }
                     }
+                /// @note For displaying purposes, upper the first letter
+                /// @note Remeber to lower it when fetching this!
+                QString chartName = chartResource.toString();
+                chartName[0] = chartName[0].toUpper();
 
-                result.insert( chartResource.toString() , QVariant::fromValue<QVariantMap>( charts ) );
+                /// Add the possible charts and its types to breadcrumb
+                result.insert( chartName , QVariant::fromValue<QVariantMap>( charts ) );
             }
             emit info(
                 requestId,
@@ -224,8 +246,6 @@ ChartsPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
             return;
         }
 
-
-
         default:
         {
             tLog() << "Couldn't figure out what to do with this type of request after cache miss";
@@ -235,56 +255,13 @@ ChartsPlugin::notInCacheSlot( uint requestId, QHash<QString, QString> criteria,
     }
 }
 
-
-void
-ChartsPlugin::chartResources()
-{
-
-    tDebug() << "ChartsPlugin: InfoChart resources returned!";
-    QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
-
-
-    if ( reply->error() == QNetworkReply::NoError )
-    {
-        QJson::Parser p;
-        bool ok;
-        QVariantMap res = p.parse( reply, &ok ).toMap();
-
-        if ( !ok )
-        {
-            tLog() << "Failed to parse resources" << p.errorString() << "On line" << p.errorLine();
-
-            return;
-        }
-
-        m_chartResources = res.value( "chart_sources" ).toList();
-        qDebug() << "Resources" << m_chartResources;
-
-        if(!m_chartResources.isEmpty()){
-
-            foreach(QVariant resource, m_chartResources){
-                tDebug() << "ChartsPlugin: InfoChart fetching possible types for "<< resource.toString();
-
-                QUrl url = QUrl( QString( CHART_URL "source/%1" ).arg(resource.toString() ) );
-                qDebug() << "Getting types from " << url;
-
-                QNetworkReply* reply = lastfm::nam()->get( QNetworkRequest( url ) );
-
-                connect( reply, SIGNAL( finished() ), SLOT( chartTypes() ) );
-            }
-        }
-    }
-
-}
-
 void
 ChartsPlugin::chartTypes()
 {
-
+    /// Get possible chart type for specific chart source
     tDebug() << "ChartsPlugin: InfoChart types returned!";
     QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
 
-
     if ( reply->error() == QNetworkReply::NoError )
     {
         QJson::Parser p;
@@ -297,11 +274,9 @@ ChartsPlugin::chartTypes()
 
             return;
         }
-
-        foreach(QVariant chart, res.value( "charts" ).toMap() ){
+        /// Got types, append!
+        foreach(QVariant chart, res.value( "charts" ).toMap() )
             m_chartTypes.append(chart);
-            qDebug() << "Chart types" << chart;
-        }
 
     }
 
@@ -311,8 +286,8 @@ void
 ChartsPlugin::chartReturned()
 {
 
+    /// Chart request returned something! Woho
     QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
-
     QVariantMap returnedData;
 
     if ( reply->error() == QNetworkReply::NoError )
@@ -324,15 +299,16 @@ ChartsPlugin::chartReturned()
         if ( !ok )
         {
             tLog() << "Failed to parse json from chart lookup:" << p.errorString() << "On line" << p.errorLine();
-
             return;
-        }else qDebug() << res;
-
+        }
 
+        /// SO we have a result, parse it!
         QVariantList chartResponse = res.value( "list" ).toList();
         QList<ArtistTrackPair> top_tracks;
         QList<ArtistAlbumPair> top_albums;
 
+        /// Deside what type, we need to handle it differently
+        /// @todo: We allready know the type, append it to breadcrumb hash
 
         if( res.value( "type" ).toString() == "Album" )
             setChartType( Album );
@@ -347,57 +323,77 @@ ChartsPlugin::chartReturned()
             QString title, artist, album;
             QVariantMap chartMap = chartR.toMap();
 
-            if ( chartMap.contains( "track" ) )
+            if( !chartMap.isEmpty() )
             {
 
                 title = chartMap.value( "track" ).toString();
+                album = chartMap.value( "album" ).toString();
                 artist = chartMap.value( "artist" ).toString();
+                /// Maybe we can use rank later on, to display something nice
+                /// rank = chartMap.value( "rank" ).toString();
 
-                if ( title.isEmpty() && artist.isEmpty() ) // don't have enough...
+                if( chartType() == Album )
                 {
-                    tLog() << "Didn't get an artist and track name from itunes, not enough to build a query on. Aborting" << title << artist << album;
+                     /** HACK, billboard chart returns wrong typename **/
+                    if( res.value( "source" ).toString() == "billboard" )
+                        album = chartMap.value( "track" ).toString();
 
-                }
-                else{
-
-                    if( chartType() == Album ){
+                    if ( album.isEmpty() && artist.isEmpty() ) // don't have enough...
+                    {
+                        tLog() << "Didn't get an artist and album name from chart, not enough to build a query on. Aborting" << title << album << artist;
 
+                    }else
+                    {
+                        qDebug() << Q_FUNC_INFO << album << artist;
                         ArtistAlbumPair pair;
                         pair.artist = artist;
-                        pair.album = title;
+                        pair.album = album;
                         top_albums << pair;
 
-                    }else if( chartType() == Track ){
+                    }
+                }
+
+                else if( chartType() == Track )
+                {
+
+                    if ( title.isEmpty() && artist.isEmpty() ) // don't have enough...
+                    {
+                        tLog() << "Didn't get an artist and track name from charts, not enough to build a query on. Aborting" << title << artist << album;
+
+                    }else{
 
                         ArtistTrackPair pair;
                         pair.artist = artist;
                         pair.track = title;
                         top_tracks << pair;
-                    }
 
+                    }
                 }
             }
         }
-            if( chartType() == Track ){
-                tDebug() << "ChartsPlugin:" << "\tgot " << top_tracks.size() << " tracks";
-                returnedData["tracks"] = QVariant::fromValue( top_tracks );
-                returnedData["type"] = "tracks";
-            }
 
-            if( chartType() == Album ){
-                tDebug() << "ChartsPlugin:" << "\tgot " << top_albums.size() << " albums";
-                returnedData["albums"] = QVariant::fromValue( top_albums );
-                returnedData["type"] = "albums";
-            }
+        if( chartType() == Track )
+        {
+            tDebug() << "ChartsPlugin:" << "\tgot " << top_tracks.size() << " tracks";
+            returnedData["tracks"] = QVariant::fromValue( top_tracks );
+            returnedData["type"] = "tracks";
+        }
 
-        Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
+        if( chartType() == Album )
+        {
+            tDebug() << "ChartsPlugin:" << "\tgot " << top_albums.size() << " albums";
+            returnedData["albums"] = QVariant::fromValue( top_albums );
+            returnedData["type"] = "albums";
+        }
 
-        emit info(
-            reply->property( "requestId" ).toUInt(),
-            requestData,
-            returnedData
-        );
-        // TODO update cache
+    Tomahawk::InfoSystem::InfoRequestData requestData = reply->property( "requestData" ).value< Tomahawk::InfoSystem::InfoRequestData >();
+
+    emit info(
+        reply->property( "requestId" ).toUInt(),
+        requestData,
+        returnedData
+    );
+    // TODO update cache
 
     }else qDebug() << "Network error";
 
diff --git a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h
index b358f3a91..33f378744 100644
--- a/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h
+++ b/src/libtomahawk/infosystem/infoplugins/generic/chartsplugin.h
@@ -52,7 +52,6 @@ public:
 
 public slots:
     void chartReturned();
-    void chartResources();
     void chartTypes();
     void namChangedSlot( QNetworkAccessManager *nam );
 
diff --git a/src/libtomahawk/widgets/whatshotwidget.cpp b/src/libtomahawk/widgets/whatshotwidget.cpp
index a41bfea08..4960240e1 100644
--- a/src/libtomahawk/widgets/whatshotwidget.cpp
+++ b/src/libtomahawk/widgets/whatshotwidget.cpp
@@ -53,14 +53,15 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent )
 {
     ui->setupUi( this );
 
+    ui->additionsView->setFrameShape( QFrame::NoFrame );
+    ui->additionsView->setAttribute( Qt::WA_MacShowFocusRect, 0 );
+
     TomahawkUtils::unmarginLayout( layout() );
     TomahawkUtils::unmarginLayout( ui->stackLeft->layout() );
     TomahawkUtils::unmarginLayout( ui->horizontalLayout->layout() );
     TomahawkUtils::unmarginLayout( ui->horizontalLayout_2->layout() );
     TomahawkUtils::unmarginLayout( ui->breadCrumbLeft->layout() );
-    TomahawkUtils::unmarginLayout( ui->verticalLayout2->layout() );
-
-
+    TomahawkUtils::unmarginLayout( ui->verticalLayout->layout() );
 
     //set crumb widgets
     SiblingCrumbButtonFactory * crumbFactory = new SiblingCrumbButtonFactory;
@@ -70,21 +71,16 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent )
     ui->breadCrumbLeft->setButtonFactory(crumbFactory);
     ui->breadCrumbLeft->setModel(m_crumbModelLeft);
     ui->breadCrumbLeft->setRootIcon(QIcon( RESPATH "images/charts.png" ));
-    //ui->breadCrumbLeft->setSelectionModel(selectionModelLeft);
     ui->breadCrumbLeft->setUseAnimation(true);
 
     connect(ui->breadCrumbLeft, SIGNAL(currentIndexChanged(QModelIndex)), SLOT(leftCrumbIndexChanged(QModelIndex)));
 
-    /*ui->breadCrumbRight->setButtonFactory(crumbFactory);
-    ui->breadCrumbRight->setRootIcon(QIcon( RESPATH "images/charts.png" ));
-    ui->breadCrumbRight->setModel(m_crumbModelLeft);
-    ui->breadCrumbRight->setUseAnimation(true);*/
-
+    m_albumsModel = new AlbumModel( ui->additionsView );
+    ui->additionsView->setAlbumModel( m_albumsModel );
 
     m_tracksModel = new PlaylistModel( ui->tracksViewLeft );
     m_tracksModel->setStyle( TrackModel::ShortWithAvatars );
 
-
     ui->tracksViewLeft->setFrameShape( QFrame::NoFrame );
     ui->tracksViewLeft->setAttribute( Qt::WA_MacShowFocusRect, 0 );
     ui->tracksViewLeft->overlay()->setEnabled( false );
@@ -111,11 +107,6 @@ WhatsHotWidget::WhatsHotWidget( QWidget* parent )
     ui->artistsViewLeft->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
     ui->artistsViewLeft->header()->setVisible( false );
 
-    ui->albumsViewLeft->setFrameShape( QFrame::NoFrame );
-    ui->albumsViewLeft->setAttribute( Qt::WA_MacShowFocusRect, 0 );
-
-    m_albumsModel = new AlbumModel( ui->albumsViewLeft );
-    ui->albumsViewLeft->setAlbumModel( m_albumsModel );
 
     m_timer = new QTimer( this );
     connect( m_timer, SIGNAL( timeout() ), SLOT( checkQueries() ) );
@@ -193,7 +184,7 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat
             //ui->breadCrumbRight->setSelectionModel(selectionModelLeft);
             //HACK ALERT - we want the second crumb to expand right away, so we
             //force it here. We should find a more elegant want to do this
-            ui->breadCrumbLeft->currentChangedTriggered(m_crumbModelLeft->index(0,0).child(0,0));
+            ui->breadCrumbLeft->currentChangedTriggered(m_crumbModelLeft->index(0,0).child(0,0).child(0,0));
             break;
         }
         case InfoSystem::InfoChart:
@@ -226,13 +217,15 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat
                 foreach ( const Tomahawk::InfoSystem::ArtistAlbumPair& album, albums )
                 {
                     qDebug() << "Getting album" << album.album << "By" << album.artist;
-                    album_ptr albumPtr = Album::get( 0, album.album, Artist::get( album.artist ) );
-                    al << albumPtr;
+                    album_ptr albumPtr = Album::get(Artist::get( album.artist, true ), album.album );
+
+                    if(!albumPtr.isNull())
+                        al << albumPtr;
 
                 }
                 qDebug() << "Adding albums to model";
                 m_albumsModel->addAlbums( al );
-                qDebug() << "Added albums";
+
 
             }
             else if( type == "tracks" )
@@ -290,7 +283,8 @@ WhatsHotWidget::leftCrumbIndexChanged( QModelIndex index )
 
     Tomahawk::InfoSystem::InfoCriteriaHash criteria;
     criteria.insert("chart_id", chartId);
-    criteria.insert("chart_source",  index.data().toString());
+    /// Remember to lower the source!
+    criteria.insert("chart_source",  index.data().toString().toLower());
 
     Tomahawk::InfoSystem::InfoRequestData requestData;
     QVariantMap customData;
diff --git a/src/libtomahawk/widgets/whatshotwidget.ui b/src/libtomahawk/widgets/whatshotwidget.ui
index c1e857163..4caa5e32b 100644
--- a/src/libtomahawk/widgets/whatshotwidget.ui
+++ b/src/libtomahawk/widgets/whatshotwidget.ui
@@ -10,7 +10,7 @@
     <height>513</height>
    </rect>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
+  <layout class="QVBoxLayout" name="verticalLayout_2">
    <item>
     <widget class="HeaderBreadCrumb" name="breadCrumbLeft" native="true"/>
    </item>
@@ -45,21 +45,17 @@
       </layout>
      </widget>
      <widget class="QWidget" name="page2">
-      <layout class="QVBoxLayout" name="verticalLayout2">
+      <layout class="QVBoxLayout" name="verticalLayout">
        <item>
-        <layout class="QVBoxLayout" name="verticalLayout_2"/>
- 
-        <widget class="AlbumView" name="albumsViewLeft">
-         <property name="minimumSize">
-          <size>
-           <width>320</width>
-           <height>0</height>
-          </size>
+        <widget class="AlbumView" name="additionsView">
+         <property name="dragEnabled">
+          <bool>true</bool>
+         </property>
+         <property name="selectionMode">
+          <enum>QAbstractItemView::ExtendedSelection</enum>
          </property>
         </widget>
-    
        </item>
-       
       </layout>
      </widget>
     </widget>