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