File indexing completed on 2024-05-05 04:49:16
0001 /**************************************************************************************** 0002 * Copyright (c) 2007 Nikolaj Hald Nielsen <nhn@kde.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #include "ServiceBase.h" 0018 0019 #include "browsers/CollectionTreeItem.h" 0020 #include "browsers/CollectionTreeItemModelBase.h" 0021 #include "browsers/InfoProxy.h" 0022 #include "core/collections/Collection.h" 0023 #include "core/support/Amarok.h" 0024 #include "core/support/Debug.h" 0025 #include "core-impl/collections/support/CollectionManager.h" 0026 #include "widgets/SearchWidget.h" 0027 #include "widgets/BoxWidget.h" 0028 0029 #include <QLabel> 0030 #include <QLayout> 0031 #include <QMenuBar> 0032 0033 0034 ServiceFactory::ServiceFactory() 0035 : Plugins::PluginFactory() 0036 { 0037 CollectionManager::instance()->addTrackProvider( this ); 0038 connect( this, &ServiceFactory::newService, this, &ServiceFactory::slotNewService ); 0039 connect( this, &ServiceFactory::removeService, this, &ServiceFactory::slotRemoveService ); 0040 } 0041 0042 ServiceFactory::~ServiceFactory() 0043 { 0044 CollectionManager::instance()->removeTrackProvider( this ); 0045 } 0046 0047 0048 Meta::TrackPtr 0049 ServiceFactory::trackForUrl( const QUrl &url ) 0050 { 0051 if ( m_activeServices.isEmpty() ) { 0052 debug() << "our service (" << name() << ") is needed for a url, so init it!"; 0053 init(); 0054 } 0055 0056 foreach( ServiceBase *service, m_activeServices ) 0057 { 0058 if( !service->serviceReady() ) 0059 { 0060 debug() << "our service is not ready! queuing track and returning proxy"; 0061 MetaProxy::Track *ptrack = new MetaProxy::Track( url, MetaProxy::Track::ManualLookup ); 0062 MetaProxy::TrackPtr trackptr( ptrack ); 0063 m_tracksToLocate.enqueue( trackptr ); 0064 return Meta::TrackPtr::staticCast( trackptr ); 0065 } 0066 else if( service->collection() ) 0067 { 0068 debug() << "Service Ready. Collection is: " << service->collection(); 0069 return service->collection()->trackForUrl( url ); 0070 } 0071 else 0072 warning() << __PRETTY_FUNCTION__ << "service is ready, but service->collection() is null!"; 0073 } 0074 return Meta::TrackPtr(); 0075 } 0076 0077 void ServiceFactory::clearActiveServices() 0078 { 0079 m_activeServices.clear(); 0080 } 0081 0082 void ServiceFactory::slotServiceReady() 0083 { 0084 while( !m_tracksToLocate.isEmpty() ) 0085 { 0086 MetaProxy::TrackPtr track = m_tracksToLocate.dequeue(); 0087 if( !track ) 0088 continue; 0089 0090 track->lookupTrack( this ); 0091 } 0092 } 0093 0094 void 0095 ServiceFactory::slotNewService( ServiceBase *newService ) 0096 { 0097 Q_ASSERT( newService ); 0098 connect( newService, &ServiceBase::ready, this, &ServiceFactory::slotServiceReady ); 0099 m_activeServices << newService; 0100 } 0101 0102 void 0103 ServiceFactory::slotRemoveService( ServiceBase *service ) 0104 { 0105 Q_ASSERT( service ); 0106 m_activeServices.remove( service ); 0107 service->deleteLater(); 0108 } 0109 0110 ServiceBase *ServiceBase::s_instance = nullptr; 0111 0112 ServiceBase::ServiceBase( const QString &name, ServiceFactory *parent, bool useCollectionTreeView, const QString &prettyName ) 0113 : BrowserCategory( name, nullptr ) 0114 , m_contentView ( nullptr ) 0115 , m_parentFactory( parent ) 0116 , m_polished( false ) 0117 , m_useCollectionTreeView( useCollectionTreeView ) 0118 , m_infoParser( nullptr ) 0119 , m_serviceready( false ) 0120 , m_model( nullptr ) 0121 , m_filterModel( nullptr ) 0122 { 0123 DEBUG_BLOCK 0124 0125 if ( !prettyName.isEmpty() ) 0126 { 0127 setPrettyName( prettyName ); 0128 } 0129 else 0130 setPrettyName( name ); 0131 0132 layout()->setSpacing( 1 ); 0133 0134 m_topPanel = new BoxWidget( true, this ); 0135 0136 if( useCollectionTreeView ) 0137 { 0138 m_contentView = new ServiceCollectionTreeView( this ); 0139 m_contentView->setFrameShape( QFrame::NoFrame ); 0140 m_contentView->setSortingEnabled( true ); 0141 m_contentView->sortByColumn ( 0, Qt::AscendingOrder ); 0142 m_contentView->setDragEnabled ( true ); 0143 m_contentView->setDragDropMode ( QAbstractItemView::DragOnly ); 0144 connect( static_cast<ServiceCollectionTreeView*>( m_contentView ), &ServiceCollectionTreeView::itemSelected, 0145 this, &ServiceBase::itemSelected ); 0146 } 0147 0148 m_bottomPanel = new BoxWidget( true, this ); 0149 0150 m_bottomPanel->setFrameStyle( QFrame::NoFrame ); 0151 m_bottomPanel->setLineWidth(2); 0152 m_bottomPanel->layout()->setSpacing( 2 ); 0153 m_bottomPanel->layout()->setMargin( 2 ); 0154 0155 m_filterModel = new QSortFilterProxyModel( this ); 0156 m_filterModel->setSortCaseSensitivity( Qt::CaseInsensitive ); 0157 m_filterModel->setFilterCaseSensitivity( Qt::CaseInsensitive ); 0158 0159 m_menubar = new QMenuBar( m_topPanel ); 0160 // Make sure we do not expose this menubar outside to ensure it does not 0161 // replace the main menubar when Amarok is used with Plasma Menubar 0162 m_menubar->setNativeMenuBar( false ); 0163 m_filterMenu = m_menubar->addMenu( i18n( "Group By" ) ); 0164 0165 m_menubar->hide(); 0166 0167 m_searchWidget = new SearchWidget( m_topPanel ); 0168 if( m_contentView ) 0169 connect( m_searchWidget, &SearchWidget::filterChanged, 0170 static_cast<ServiceCollectionTreeView*>( m_contentView ), &ServiceCollectionTreeView::slotSetFilter ); 0171 } 0172 0173 ServiceBase::~ServiceBase() 0174 { 0175 delete m_infoParser; 0176 } 0177 0178 ServiceFactory* 0179 ServiceBase::parent() const 0180 { 0181 return m_parentFactory; 0182 } 0183 0184 void 0185 ServiceBase::itemActivated ( const QModelIndex & index ) 0186 { 0187 Q_UNUSED( index ); 0188 } 0189 0190 0191 void 0192 ServiceBase::setModel( QAbstractItemModel * model ) 0193 { 0194 if( m_contentView ) 0195 m_contentView->setModel( model ); 0196 m_model = model; 0197 } 0198 0199 QAbstractItemModel * 0200 ServiceBase::model() 0201 { 0202 return m_model; 0203 } 0204 0205 QTreeView * 0206 ServiceBase::view() 0207 { 0208 return m_contentView; 0209 } 0210 0211 void 0212 ServiceBase::setView( QTreeView * view ) 0213 { 0214 if( !view) 0215 return; 0216 m_contentView = view; 0217 if( m_model ) 0218 m_contentView->setModel( m_model ); 0219 } 0220 0221 bool 0222 ServiceBase::serviceReady() const 0223 { 0224 return m_serviceready; 0225 } 0226 0227 void 0228 ServiceBase::setServiceReady( bool newReady ) 0229 { 0230 if( newReady == m_serviceready ) 0231 return; // nothing to do 0232 0233 m_serviceready = newReady; 0234 if( m_serviceready ) 0235 Q_EMIT ready(); 0236 } 0237 0238 void 0239 ServiceBase::infoChanged( const QString &infoHtml ) 0240 { 0241 QVariantMap map; 0242 map[QStringLiteral("service_name")] = prettyName(); 0243 map[QStringLiteral("main_info")] = infoHtml; 0244 The::infoProxy()->setInfo( map ); 0245 } 0246 0247 void 0248 ServiceBase::itemSelected( CollectionTreeItem * item ) 0249 { 0250 0251 Meta::DataPtr ptr = item->data(); 0252 if ( ( ptr.data() == nullptr ) || ( m_infoParser == nullptr )) return; 0253 0254 debug() << "selected item: " << ptr->name(); 0255 0256 ServiceDisplayInfoProvider * infoProvider = dynamic_cast<ServiceDisplayInfoProvider *>( ptr.data() ); 0257 if (infoProvider == nullptr ) return; 0258 0259 infoProvider->processInfoOf( m_infoParser ); 0260 } 0261 0262 void 0263 ServiceBase::generateWidgetInfo( const QString &html ) const 0264 { 0265 QVariantMap map; 0266 map[QStringLiteral("service_name")] = prettyName(); 0267 map[QStringLiteral("main_info")] = html; 0268 The::infoProxy()->setInfo( map ); 0269 } 0270 0271 void 0272 ServiceBase::setPlayableTracks(bool playable) 0273 { 0274 if( m_useCollectionTreeView ) { 0275 if( ServiceCollectionTreeView* view = dynamic_cast<ServiceCollectionTreeView*>(m_contentView) ) 0276 view->setPlayableTracks( playable ); 0277 } 0278 } 0279 0280 void 0281 ServiceBase::sortByArtist() 0282 { 0283 setLevels( QList<CategoryId::CatMenuId>() << CategoryId::Artist ); 0284 } 0285 0286 void 0287 ServiceBase::sortByArtistAlbum() 0288 { 0289 setLevels( QList<CategoryId::CatMenuId>() << CategoryId::Artist << CategoryId::Album ); 0290 } 0291 0292 void 0293 ServiceBase::sortByAlbum() 0294 { 0295 setLevels( QList<CategoryId::CatMenuId>() << CategoryId::Album ); 0296 } 0297 0298 void 0299 ServiceBase::sortByGenreArtist() 0300 { 0301 setLevels( QList<CategoryId::CatMenuId>() << CategoryId::Genre << CategoryId::Artist ); 0302 } 0303 0304 void 0305 ServiceBase::sortByGenreArtistAlbum() 0306 { 0307 if( m_useCollectionTreeView ) { 0308 if( ServiceCollectionTreeView* view = dynamic_cast<ServiceCollectionTreeView*>(m_contentView) ) 0309 view->setLevels( QList<CategoryId::CatMenuId>() << CategoryId::Genre << CategoryId::Artist << CategoryId::Album ); 0310 } 0311 } 0312 0313 void 0314 ServiceBase::setFilter(const QString & filter) 0315 { 0316 polish(); 0317 m_searchWidget->setSearchString( filter ); 0318 } 0319 0320 void 0321 ServiceBase::setInfoParser(InfoParserBase * infoParser) 0322 { 0323 m_infoParser = infoParser; 0324 0325 connect ( m_infoParser, &InfoParserBase::info, this, &ServiceBase::infoChanged ); 0326 } 0327 0328 InfoParserBase * 0329 ServiceBase::infoParser() 0330 { 0331 return m_infoParser; 0332 } 0333 0334 QString 0335 ServiceBase::messages() 0336 { 0337 return i18n( "This service does not accept any messages" ); 0338 } 0339 0340 QString 0341 ServiceBase::sendMessage( const QString & message ) 0342 { 0343 Q_UNUSED( message ); 0344 return i18n( "ERROR: unknown message" ); 0345 } 0346 0347 QString 0348 ServiceBase::filter() const 0349 { 0350 return m_searchWidget->currentText(); 0351 } 0352 0353 QList<CategoryId::CatMenuId> 0354 ServiceBase::levels() const 0355 { 0356 CollectionTreeView *contentView = qobject_cast<CollectionTreeView*>(m_contentView); 0357 if( contentView ) 0358 return contentView->levels(); 0359 return QList<CategoryId::CatMenuId>(); 0360 } 0361 0362 void ServiceBase::setLevels( const QList<CategoryId::CatMenuId> &levels ) 0363 { 0364 if( m_useCollectionTreeView ) { 0365 if( ServiceCollectionTreeView* view = dynamic_cast<ServiceCollectionTreeView*>(m_contentView) ) 0366 view->setLevels( levels ); 0367 } 0368 } 0369 0370 0371