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 }