File indexing completed on 2024-05-19 04:50:13

0001 /****************************************************************************************
0002  * Copyright (c) 2011 Stefan Derkits <stefan@derkits.at>                                *
0003  * Copyright (c) 2011 Christian Wagner <christian.wagner86@gmx.at>                      *
0004  * Copyright (c) 2011 Felix Winter <ixos01@gmail.com>                                   *
0005  *                                                                                      *
0006  * This program is free software; you can redistribute it and/or modify it under        *
0007  * the terms of the GNU General Public License as published by the Free Software        *
0008  * Foundation; either version 2 of the License, or (at your option) any later           *
0009  * version.                                                                             *
0010  *                                                                                      *
0011  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0012  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0013  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0014  *                                                                                      *
0015  * You should have received a copy of the GNU General Public License along with         *
0016  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0017  ****************************************************************************************/
0018 
0019 #include "GpodderServiceModel.h"
0020 
0021 #include "core/support/Debug.h"
0022 #include "GpodderPodcastRequestHandler.h"
0023 #include "GpodderPodcastTreeItem.h"
0024 #include "GpodderServiceSettings.h"
0025 #include "GpodderTagTreeItem.h"
0026 
0027 #include <QEventLoop>
0028 #include <QList>
0029 #include <QNetworkConfigurationManager>
0030 #include <QTimer>
0031 
0032 static const int s_numberItemsToLoad = 100;
0033 
0034 using namespace mygpo;
0035 
0036 GpodderServiceModel::GpodderServiceModel( ApiRequest *request, QObject *parent )
0037     : QAbstractItemModel( parent )
0038     , m_rootItem( nullptr )
0039     , m_topTagsItem( nullptr )
0040     , m_topPodcastsItem( nullptr )
0041     , m_suggestedPodcastsItem( nullptr )
0042     , m_topTags( nullptr )
0043     , m_apiRequest( request )
0044 {
0045     GpodderServiceConfig config;
0046     
0047     m_rootItem = new GpodderTreeItem( );
0048 
0049     m_topTagsItem = new GpodderTreeItem( m_rootItem, "Top Tags" );
0050     m_rootItem->appendChild( m_topTagsItem );
0051 
0052     m_topPodcastsItem = new GpodderTreeItem( m_rootItem, "Top Podcasts" );
0053     m_rootItem->appendChild( m_topPodcastsItem );
0054 
0055     if ( config.isDataLoaded() && config.enableProvider() )
0056     {
0057         m_suggestedPodcastsItem = new GpodderTreeItem( m_rootItem, "Suggested Podcasts" );
0058         m_rootItem->appendChild( m_suggestedPodcastsItem );
0059 
0060     }
0061 }
0062 
0063 GpodderServiceModel::~GpodderServiceModel()
0064 {
0065     delete m_rootItem;
0066 }
0067 
0068 QModelIndex
0069 GpodderServiceModel::index( int row, int column, const QModelIndex &parent ) const
0070 {
0071     if( !hasIndex( row, column, parent ) )
0072         return QModelIndex();
0073 
0074     GpodderTreeItem *parentItem;
0075 
0076     if( !parent.isValid() )
0077         parentItem = m_rootItem;
0078     else
0079         parentItem = static_cast<GpodderTreeItem *>( parent.internalPointer() );
0080 
0081     if( parentItem == nullptr )
0082         return QModelIndex();
0083 
0084     GpodderTreeItem *childItem = parentItem->child( row );
0085     if( childItem )
0086         return createIndex( row, column, childItem );
0087     else
0088         return QModelIndex();
0089 }
0090 
0091 QModelIndex
0092 GpodderServiceModel::parent( const QModelIndex &index ) const
0093 {
0094     if( !index.isValid() )
0095         return QModelIndex();
0096 
0097     GpodderTreeItem *childItem = static_cast<GpodderTreeItem *>( index.internalPointer() );
0098 
0099     if( childItem == nullptr || childItem->isRoot() )
0100         return QModelIndex();
0101 
0102     GpodderTreeItem *parentItem = childItem->parent();
0103 
0104     if( parentItem == nullptr )
0105         return QModelIndex();
0106 
0107     int childIndex;
0108     if( parentItem->isRoot() )
0109         return QModelIndex();
0110     else
0111         childIndex = parentItem->parent()->children().indexOf( parentItem );
0112 
0113     return createIndex( childIndex, 0, parentItem );
0114 }
0115 
0116 int
0117 GpodderServiceModel::rowCount( const QModelIndex &parent ) const
0118 {
0119     GpodderTreeItem *parentItem;
0120 
0121     if( !parent.isValid() )
0122     {
0123         return m_rootItem->childCount();
0124     }
0125 
0126     parentItem = static_cast<GpodderTreeItem *>( parent.internalPointer() );
0127 
0128     if( parentItem == nullptr )
0129         return 0;
0130 
0131     return parentItem->childCount();
0132 }
0133 
0134 int
0135 GpodderServiceModel::columnCount( const QModelIndex &parent ) const
0136 {
0137     Q_UNUSED( parent )
0138     return 1;
0139 }
0140 
0141 QVariant
0142 GpodderServiceModel::data( const QModelIndex &index, int role ) const
0143 {
0144     if( !index.isValid() )
0145         return QVariant();
0146 
0147     if( role != Qt::DisplayRole )
0148         return QVariant();
0149 
0150     GpodderTreeItem *item = static_cast<GpodderTreeItem*>( index.internalPointer() );
0151     if( item == nullptr )
0152     {
0153         return QVariant();
0154     }
0155 
0156     return item->displayData();
0157 }
0158 
0159 void
0160 GpodderServiceModel::insertTagList()
0161 {
0162     if( m_rootItem != nullptr )
0163     {
0164         beginInsertRows( createIndex( 0,0, m_topTagsItem), 0, m_topTags->list().count() - 1 );
0165         m_topTagsItem->appendTags( m_topTags );
0166         endInsertRows();
0167     }
0168 }
0169 
0170 void
0171 GpodderServiceModel::topTagsRequestError( QNetworkReply::NetworkError error )
0172 {
0173     DEBUG_BLOCK
0174 
0175     debug() << "Error in TopTags request: " << error;
0176 
0177     QTimer::singleShot( 20000, this, &GpodderServiceModel::requestTopTags );
0178 }
0179 
0180 void
0181 GpodderServiceModel::topTagsParseError()
0182 {
0183     DEBUG_BLOCK
0184 
0185     debug() << "Error while parsing TopTags";
0186 
0187     QTimer::singleShot( 20000, this, &GpodderServiceModel::requestTopTags );
0188 }
0189 
0190 void
0191 GpodderServiceModel::topPodcastsRequestError( QNetworkReply::NetworkError error )
0192 {
0193     DEBUG_BLOCK
0194 
0195     debug() << "Error in TopPodcasts request: " << error;
0196 
0197     QTimer::singleShot( 20000, this, &GpodderServiceModel::requestTopPodcasts );
0198 }
0199 
0200 void
0201 GpodderServiceModel::topPodcastsParseError()
0202 {
0203     DEBUG_BLOCK
0204 
0205     debug() << "Error while parsing TopPodcasts";
0206 
0207     QTimer::singleShot( 20000, this, &GpodderServiceModel::requestTopPodcasts );
0208 }
0209 
0210 void
0211 GpodderServiceModel::suggestedPodcastsRequestError( QNetworkReply::NetworkError error )
0212 {
0213     DEBUG_BLOCK
0214 
0215     debug() << "Error in suggestedPodcasts request: " << error;
0216 
0217     QTimer::singleShot( 20000, this, &GpodderServiceModel::requestSuggestedPodcasts );
0218 }
0219 
0220 void
0221 GpodderServiceModel::suggestedPodcastsParseError()
0222 {
0223     DEBUG_BLOCK
0224 
0225     debug() << "Error while parsing suggestedPodcasts";
0226 
0227     QTimer::singleShot( 20000, this, &GpodderServiceModel::requestSuggestedPodcasts );
0228 }
0229 
0230 void
0231 GpodderServiceModel::insertPodcastList( mygpo::PodcastListPtr podcasts,
0232                                         const QModelIndex &parentItem )
0233 {
0234     DEBUG_BLOCK
0235 
0236     emit layoutAboutToBeChanged();
0237     beginInsertRows( parentItem, 0, podcasts->list().count() - 1 );
0238     GpodderTreeItem *item = static_cast<GpodderTreeItem*>( parentItem.internalPointer() );
0239     if( item != nullptr )
0240     {
0241         debug() << "Appending Podcasts...";
0242         item->appendPodcasts( podcasts );
0243     }
0244     endInsertRows();
0245 
0246     emit layoutChanged();
0247 }
0248 
0249 bool
0250 GpodderServiceModel::hasChildren( const QModelIndex &parent ) const
0251 {
0252     if( !parent.isValid() )
0253         return true;
0254 
0255     GpodderTreeItem *treeItem = static_cast<GpodderTreeItem *>( parent.internalPointer() );
0256 
0257     if( treeItem == nullptr )
0258         return false;
0259 
0260     if( treeItem->childCount() > 0 )
0261         return true;
0262 
0263     if( !qobject_cast<GpodderPodcastTreeItem *>( treeItem ) )
0264     {
0265         return true;
0266     }
0267     else
0268     {
0269         return false;
0270     }
0271 }
0272 
0273 bool
0274 GpodderServiceModel::canFetchMore( const QModelIndex &parent ) const
0275 {
0276     // root item
0277     if( !parent.isValid() )
0278     {
0279         return !m_rootItem->hasChildren();
0280     }
0281 
0282     // already fetched or just started?
0283     GpodderTreeItem *treeItem = static_cast<GpodderTreeItem *>( parent.internalPointer() );
0284     if( treeItem == nullptr || treeItem->hasChildren() /* || m_currentFetchingMap.values().contains( parent ) */ )
0285     {
0286         return false;
0287     }
0288 
0289     // TagTreeItem
0290 
0291     if( qobject_cast<GpodderTagTreeItem*>( treeItem ) )
0292     {
0293         if( !QNetworkConfigurationManager().isOnline() )
0294             return false;
0295 
0296         return true;
0297     }
0298     return false;
0299 }
0300 
0301 void
0302 GpodderServiceModel::fetchMore( const QModelIndex &parent )
0303 {
0304     // root item
0305     if( !parent.isValid() )
0306     {
0307         requestTopTags();
0308         requestTopPodcasts();
0309         if ( m_suggestedPodcastsItem != nullptr )
0310             requestSuggestedPodcasts();
0311     }
0312 
0313     GpodderTreeItem *treeItem = static_cast<GpodderTreeItem *>( parent.internalPointer() );
0314 
0315     // TagTreeItem
0316     if( GpodderTagTreeItem *tagTreeItem = qobject_cast<GpodderTagTreeItem*>( treeItem ) )
0317     {
0318         m_rootItem->setHasChildren( true );
0319         tagTreeItem->setHasChildren( true );
0320 
0321         mygpo::PodcastListPtr podcasts =
0322                 m_apiRequest->podcastsOfTag( s_numberItemsToLoad, tagTreeItem->tag()->tag() );
0323         GpodderPodcastRequestHandler *podcastRequestHandler =
0324                 new GpodderPodcastRequestHandler( podcasts, parent, this );
0325         connect( podcasts.data(), SIGNAL(finished()), podcastRequestHandler, SLOT(finished()) );
0326         connect( podcasts.data(), SIGNAL(requestError(QNetworkReply::NetworkError)),
0327                  podcastRequestHandler, SLOT(requestError(QNetworkReply::NetworkError)) );
0328         connect( podcasts.data(), SIGNAL(parseError()), podcastRequestHandler, SLOT(parseError()) );
0329     }
0330 
0331 }
0332 
0333 void
0334 GpodderServiceModel::requestTopTags()
0335 {
0336     if( !QNetworkConfigurationManager().isOnline() )
0337     {
0338         QTimer::singleShot( 10000, this, SLOT(requestTopTags()) );
0339         return;
0340     }
0341 
0342     m_rootItem->setHasChildren( true );
0343 
0344     m_topTags = m_apiRequest->topTags( s_numberItemsToLoad );
0345     connect( m_topTags.data(), SIGNAL(finished()), this, SLOT(insertTagList()) );
0346     connect( m_topTags.data(), SIGNAL(requestError(QNetworkReply::NetworkError)),
0347              SLOT(topTagsRequestError(QNetworkReply::NetworkError)) );
0348     connect( m_topTags.data(), SIGNAL(parseError()), SLOT(topTagsParseError()) );
0349 }
0350 
0351 void
0352 GpodderServiceModel::requestTopPodcasts()
0353 {
0354     if( !QNetworkConfigurationManager().isOnline() )
0355     {
0356         QTimer::singleShot( 10000, this, SLOT(requestTopPodcasts()) );
0357         return;
0358     }
0359 
0360     m_rootItem->setHasChildren( true );
0361 
0362     mygpo::PodcastListPtr topPodcasts = m_apiRequest->toplist( s_numberItemsToLoad );
0363     GpodderPodcastRequestHandler *podcastRequestHandler = new GpodderPodcastRequestHandler(
0364                                                               topPodcasts,
0365                                                               createIndex( 0,0, m_topPodcastsItem ),
0366                                                               this );
0367     connect( topPodcasts.data(), SIGNAL(finished()), podcastRequestHandler, SLOT(finished()) );
0368     connect( topPodcasts.data(), SIGNAL(requestError(QNetworkReply::NetworkError)),
0369              SLOT(topPodcastsRequestError(QNetworkReply::NetworkError)) );
0370     connect( topPodcasts.data(), SIGNAL(parseError()), SLOT(topPodcastsParseError()) );
0371 }
0372 
0373 void
0374 GpodderServiceModel::requestSuggestedPodcasts()
0375 {
0376     if( !QNetworkConfigurationManager().isOnline() )
0377     {
0378         QTimer::singleShot( 10000, this, SLOT(requestSuggestedPodcasts()) );
0379         return;
0380     }
0381 
0382     m_rootItem->setHasChildren( true );
0383 
0384     mygpo::PodcastListPtr topSuggestions =
0385             m_apiRequest->suggestions( s_numberItemsToLoad );
0386     GpodderPodcastRequestHandler *podcastRequestHandler = new GpodderPodcastRequestHandler(
0387                                                                topSuggestions,
0388                                                               createIndex( 0,0, m_suggestedPodcastsItem ),
0389                                                               this );
0390     connect( topSuggestions.data(), SIGNAL(finished()),
0391              podcastRequestHandler, SLOT(finished()) );
0392     connect( topSuggestions.data(), SIGNAL(requestError(QNetworkReply::NetworkError)),
0393              SLOT(suggestedPodcastsRequestError(QNetworkReply::NetworkError)) );
0394     connect( topSuggestions.data(), SIGNAL(parseError()),
0395              SLOT(suggestedPodcastsParseError()) );
0396 }