File indexing completed on 2025-01-19 04:24:10

0001 /****************************************************************************************
0002  * Copyright (c) 2010 Rainer Sigle <rainer.sigle@web.de>                                *
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 #define DEBUG_PREFIX "TabsApplet"
0018 
0019 #include "TabsApplet.h"
0020 
0021 #include "TabsItem.h"
0022 #include "TabsView.h"
0023 #include "core/support/Amarok.h"
0024 #include "core/support/Debug.h"
0025 #include "context/ContextView.h"
0026 #include "context/widgets/AppletHeader.h"
0027 
0028 #include <KConfigDialog>
0029 #include <KConfigGroup>
0030 #include <KDialog>
0031 #include <QDialog>
0032 #include <Plasma/IconWidget>
0033 #include <Plasma/Label>
0034 #include <QDialogButtonBox>
0035 #include <QPushButton>
0036 #include <QVBoxLayout>
0037 
0038 /**
0039  * \brief Constructor
0040  *
0041  * TabsApplet constructor
0042  *
0043  * \param parent : the TabsApplet parent (used by Context::Applet)
0044  * \param args   : (used by Context::Applet)
0045  */
0046 TabsApplet::TabsApplet( QObject* parent, const QVariantList& args )
0047     : Context::Applet( parent, args )
0048     , m_tabsView( 0 )
0049     , m_currentState( InitState )
0050     , m_layout( 0 )
0051     , m_fetchGuitar( true )
0052     , m_fetchBass( true )
0053     , m_showTabBrowser( false )
0054 {
0055     DEBUG_BLOCK
0056     setHasConfigurationInterface( true );
0057 
0058     EngineController *engine = The::engineController();
0059     connect( engine, SIGNAL(stopped(qint64,qint64)), this, SLOT(stopped()) );
0060 }
0061 
0062 TabsApplet::~TabsApplet()
0063 {
0064     DEBUG_BLOCK
0065     delete m_tabsView;
0066     if( m_reloadIcon )
0067         delete m_reloadIcon.data();
0068 }
0069 
0070 /**
0071  * \brief Initialization
0072  *
0073  * Initializes the TabsApplet with default parameters
0074  */
0075 void
0076 TabsApplet::init()
0077 {
0078     // applet base initialization
0079     Context::Applet::init();
0080 
0081     // create the header label
0082     enableHeader( true );
0083     setHeaderText( i18nc( "Guitar tablature", "Tabs" ) );
0084 
0085     // creates the tab view
0086     m_tabsView = new TabsView( this );
0087 
0088     // Set the collapse size
0089     setCollapseOffHeight( -1 );
0090     setCollapseHeight( m_header->height() );
0091     setMinimumHeight( collapseHeight() );
0092     setPreferredHeight( collapseHeight() );
0093 
0094     // create the reload icon
0095     QAction* reloadAction = new QAction( this );
0096     reloadAction->setIcon( QIcon::fromTheme( "view-refresh" ) );
0097     reloadAction->setVisible( true );
0098     reloadAction->setEnabled( true );
0099     reloadAction->setText( i18nc( "Guitar tablature", "Reload tabs" ) );
0100     m_reloadIcon = addLeftHeaderAction( reloadAction );
0101     m_reloadIcon.data()->setEnabled( false );
0102     connect( m_reloadIcon.data(), SIGNAL(clicked()), this, SLOT(reloadTabs()) );
0103 
0104     // create the settings icon
0105     QAction* settingsAction = new QAction( this );
0106     settingsAction->setIcon( QIcon::fromTheme( "preferences-system" ) );
0107     settingsAction->setEnabled( true );
0108     settingsAction->setText( i18n( "Settings" ) );
0109     QWeakPointer<Plasma::IconWidget> settingsIcon = addRightHeaderAction( settingsAction );
0110     connect( settingsIcon.data(), SIGNAL(clicked()), this, SLOT(showConfigurationInterface()) );
0111 
0112     m_layout = new QGraphicsLinearLayout( Qt::Vertical );
0113     m_layout->addItem( m_header );
0114     m_layout->addItem( m_tabsView );
0115     setLayout( m_layout );
0116 
0117     // read configuration data and update the engine.
0118     KConfigGroup config = Amarok::config("Tabs Applet");
0119     m_fetchGuitar = config.readEntry( "FetchGuitar", true );
0120     m_fetchBass = config.readEntry( "FetchBass", true );
0121 
0122     Plasma::DataEngine *engine = dataEngine( "amarok-tabs" );
0123     engine->setProperty( "fetchGuitarTabs", m_fetchGuitar );
0124     engine->setProperty( "fetchBassTabs", m_fetchBass );
0125     engine->connectSource( "tabs", this );
0126 
0127     updateInterface( InitState );
0128 }
0129 
0130 void
0131 TabsApplet::stopped()
0132 {
0133     setHeaderText( i18nc( "Guitar tablature", "Tabs" ) );
0134     updateInterface( StoppedState );
0135 }
0136 
0137 void
0138 TabsApplet::dataUpdated( const QString& name, const Plasma::DataEngine::Data& data )
0139 {
0140     DEBUG_BLOCK
0141     Q_UNUSED( name )
0142 
0143     // remove previously fetched stuff
0144     m_tabsView->clear();
0145     m_tabsView->clearTabBrowser();
0146     setBusy( false );
0147 
0148     if( data.empty() )
0149     {
0150         setHeaderText( i18nc( "Guitar tablature", "Tabs" ) );
0151         updateInterface( InitState );
0152         return;
0153     }
0154 
0155     const QString state      = data[ "state" ].toString();
0156     const QString artistName = data[ "artist" ].toString();
0157     const QString titleName  = data[ "title" ].toString();
0158     if( data.contains( "state" ) && state.contains( "Fetching" ) )
0159     {
0160         if( canAnimate() )
0161             setBusy( true );
0162         setHeaderText( i18nc( "Guitar tablature", "Tabs: Fetching..." ) );
0163         updateInterface( FetchingState );
0164         return;
0165     }
0166     else if( data.contains( "state" ) && state.contains( "Stopped" ) )
0167     {
0168         stopped();
0169         return;
0170     }
0171     else if( data.contains( "state" ) && state.contains( "noTabs") )
0172     {
0173         // no tabs for the current track
0174         setHeaderText( i18nc( "Guitar tablature", "No Tabs for %1 by %2", titleName, artistName ) );
0175         updateInterface( NoTabsState );
0176         return;
0177     }
0178     else if( data.contains( "state" ) && state.contains( "FetchError") )
0179     {
0180         setHeaderText( i18nc( "Guitar tablature", "Tabs: Fetch Error" ) );
0181         updateInterface( NoTabsState );
0182         return;
0183     }
0184 
0185     // getting the tab-data from the engine
0186     bool tabFound = false;
0187     for( int i = 0; i < data.size(); i++ )
0188     {
0189         const QString tabId = QString( "tabs:" ).append( QString::number( i ) );
0190         if( data.contains( tabId ) )
0191         {
0192             TabsInfo *item = data[ tabId ].value<TabsInfo *>() ;
0193             if( item )
0194             {
0195                 TabsItem *tabsItem = new TabsItem();
0196                 tabsItem->setTab( item );
0197 
0198                 m_tabsView->appendTab( tabsItem );
0199                 if( !tabFound )
0200                 {
0201                     // update the applet and display the first tab in list
0202                     m_tabsView->showTab( tabsItem );
0203 
0204                     // update artist and title in the headerlabel
0205                     setHeaderText( i18nc( "Guitar tablature", "Tabs: %1 - %2", titleName, artistName ) );
0206                     updateInterface( TabState );
0207                     tabFound = true;
0208                 }
0209             }
0210         }
0211     }
0212 }
0213 
0214 void
0215 TabsApplet::updateInterface( const AppletState appletState )
0216 {
0217     // return if state has not changed (except for init state)
0218     if( m_currentState == appletState && appletState != InitState )
0219         return;
0220 
0221     debug() << "updating interface from state " << m_currentState << " to " << appletState;
0222     m_currentState = appletState;
0223     bool collapse = false;
0224 
0225     switch( m_currentState )
0226     {
0227         case InitState:
0228         case StoppedState:
0229             m_reloadIcon.data()->setEnabled( false );
0230             m_showTabBrowser = false;
0231             collapse = true;
0232             break;
0233         case NoTabsState:
0234             m_reloadIcon.data()->setEnabled( true );
0235             m_showTabBrowser = false;
0236             collapse = true;
0237             break;
0238         case FetchingState:
0239             m_reloadIcon.data()->setEnabled( false );
0240             m_showTabBrowser = false;
0241             break;
0242         case TabState:
0243             m_reloadIcon.data()->setEnabled( true );
0244             m_showTabBrowser = true;
0245             break;
0246     }
0247 
0248     QGraphicsLinearLayout *lo = static_cast<QGraphicsLinearLayout*>( layout() );
0249 
0250     m_showTabBrowser ? lo->addItem( m_tabsView ) : lo->removeItem( m_tabsView );
0251     m_showTabBrowser ? m_tabsView->show() : m_tabsView->hide();
0252 
0253     collapse ? setCollapseOn() : setCollapseOff();
0254 
0255     updateConstraints();
0256     update();
0257 }
0258 
0259 void
0260 TabsApplet::createConfigurationInterface( KConfigDialog *parent )
0261 {
0262     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
0263     QVBoxLayout *mainLayout = new QVBoxLayout;
0264     parent->setLayout(mainLayout);
0265     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0266     okButton->setDefault(true);
0267     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0268     parent->connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
0269     parent->connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
0270     mainLayout->addWidget(buttonBox);
0271 
0272     QWidget *settings = new QWidget;
0273     ui_Settings.setupUi( settings );
0274 
0275     if( m_fetchGuitar )
0276         ui_Settings.cbFetchGuitar->setChecked( true );
0277     if( m_fetchBass )
0278         ui_Settings.cbFetchBass->setChecked( true );
0279 
0280     parent->addPage( settings, i18nc( "Guitar tablature settings", "Tabs Settings" ), "preferences-system" );
0281     connect( parent, SIGNAL(accepted()), this, SLOT(saveSettings()) );
0282 }
0283 
0284 void
0285 TabsApplet::saveSettings()
0286 {
0287     DEBUG_BLOCK
0288     KConfigGroup config = Amarok::config("Tabs Applet");
0289 
0290     bool fetchGuitar = ui_Settings.cbFetchGuitar->isChecked();
0291     bool fetchBass = ui_Settings.cbFetchBass->isChecked();
0292 
0293     // check if any setting has changed
0294     bool forceUpdate = false;
0295     if( m_fetchGuitar != fetchGuitar || m_fetchBass != fetchBass )
0296         forceUpdate = true;
0297 
0298     if( forceUpdate )
0299     {
0300         m_fetchGuitar = fetchGuitar;
0301         m_fetchBass = fetchBass;
0302 
0303         config.writeEntry( "FetchGuitar", m_fetchGuitar );
0304         config.writeEntry( "FetchBass", m_fetchBass );
0305 
0306         Plasma::DataEngine *engine = dataEngine( "amarok-tabs" );
0307         engine->setProperty( "fetchGuitarTabs", m_fetchGuitar );
0308         engine->setProperty( "fetchBassTabs", m_fetchBass );
0309         engine->query( QLatin1String( "tabs:forceUpdate" ) );
0310     }
0311 }
0312 
0313 void
0314 TabsApplet::reloadTabs()
0315 {
0316     DEBUG_BLOCK
0317     KDialog reloadDialog;
0318     QWidget *reloadWidget = new QWidget( &reloadDialog );
0319 
0320     Ui::ReloadEditDialog *reloadUI = new Ui::ReloadEditDialog();
0321     reloadUI->setupUi( reloadWidget );
0322 
0323     reloadDialog.setCaption( i18nc( "Guitar tablature", "Reload Tabs" ) );
0324     reloadDialog.setButtons( KDialog::Ok|KDialog::Cancel );
0325     reloadDialog.setDefaultButton( KDialog::Ok );
0326     reloadDialog.setMainWidget( reloadWidget );
0327 
0328     // query engine for current artist and title
0329     Plasma::DataEngine *engine = dataEngine( "amarok-tabs" );
0330     QString artistName = engine->property( "artistName" ).toString();
0331     QString titleName = engine->property( "titleName" ).toString();
0332 
0333     // update ui
0334     reloadUI->artistLineEdit->setText( artistName );
0335     reloadUI->titleLineEdit->setText( titleName );
0336 
0337     if( reloadDialog.exec() == KDialog::Accepted )
0338     {
0339         QString newArtist = reloadUI->artistLineEdit->text();
0340         QString newTitle = reloadUI->titleLineEdit->text();
0341         if ( newArtist != artistName || newTitle != titleName )
0342         {
0343             engine->setProperty( "artistName", newArtist );
0344             engine->setProperty( "titleName", newTitle );
0345             engine->query( QLatin1String( "tabs:forceUpdateSpecificTitleArtist" ) );
0346         }
0347     }
0348 }
0349