diff --git a/data/images/configure.png b/data/images/configure.png new file mode 100644 index 000000000..5ce478b1a Binary files /dev/null and b/data/images/configure.png differ diff --git a/include/tomahawk/tomahawkapp.h b/include/tomahawk/tomahawkapp.h index b03e17ab6..2d55f3a1b 100644 --- a/include/tomahawk/tomahawkapp.h +++ b/include/tomahawk/tomahawkapp.h @@ -90,8 +90,9 @@ public: TomahawkWindow* mainWindow() const { return m_mainwindow; } #endif - void addScriptResolver( const QString& scriptPath ); - void removeScriptResolver( const QString& scriptPath ); + void enableScriptResolver( const QString& scriptPath ); + void disableScriptResolver( const QString& scriptPath ); + Tomahawk::ExternalResolver* resolverForPath( const QString& scriptPath ); // PlatformInterface virtual void activate(); @@ -116,7 +117,7 @@ private: void startHTTP(); QList m_collections; - QList m_scriptResolvers; + QHash m_scriptResolvers; Database* m_database; ScanManager *m_scanManager; @@ -143,3 +144,4 @@ private: }; #endif // TOMAHAWKAPP_H + diff --git a/resources.qrc b/resources.qrc index ddbc46b96..9996e5cb0 100644 --- a/resources.qrc +++ b/resources.qrc @@ -74,6 +74,7 @@ ./data/images/back.png ./data/images/forward.png ./data/images/music-icon.png +./data/images/configure.png ./data/topbar-radiobuttons.css ./data/icons/tomahawk-icon-16x16.png ./data/icons/tomahawk-icon-32x32.png diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1b9a95e65..067558b19 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,6 +63,8 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} tomahawktrayicon.cpp audiocontrols.cpp settingsdialog.cpp + resolverconfigdelegate.cpp + resolversmodel.cpp tomahawkwindow.cpp ) @@ -99,6 +101,9 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui} tomahawktrayicon.h audiocontrols.h settingsdialog.h + resolverconfigdelegate.h + resolversmodel.h + resolverconfigwrapper.h tomahawkwindow.h ) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index ae7dc0350..33aaff411 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -4,6 +4,7 @@ SET( QT_USE_QTGUI TRUE ) SET( QT_USE_QTSQL TRUE ) SET( QT_USE_QTNETWORK TRUE ) SET( QT_USE_QTXML TRUE ) +SET(QT_USE_QTUITOOLS TRUE) include( ${QT_USE_FILE} ) @@ -21,6 +22,7 @@ set( libSources album.cpp collection.cpp playlist.cpp + resolver.cpp query.cpp result.cpp source.cpp diff --git a/src/libtomahawk/functimeout.h b/src/libtomahawk/functimeout.h index c66134311..bbb632f59 100644 --- a/src/libtomahawk/functimeout.h +++ b/src/libtomahawk/functimeout.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -22,6 +22,7 @@ #include #include #include +#include #include "boost/function.hpp" #include "boost/bind.hpp" @@ -43,8 +44,9 @@ class DLLEXPORT FuncTimeout : public QObject Q_OBJECT public: - FuncTimeout( int ms, boost::function func ) + FuncTimeout( int ms, boost::function func, QObject* besafe ) : m_func( func ) + , m_watch( QWeakPointer< QObject >( besafe ) ) { //qDebug() << Q_FUNC_INFO; QTimer::singleShot( ms, this, SLOT( exec() ) ); @@ -58,12 +60,14 @@ public: public slots: void exec() { - m_func(); + if( !m_watch.isNull() ) + m_func(); this->deleteLater(); }; private: boost::function m_func; + QWeakPointer< QObject > m_watch; }; }; // ns diff --git a/src/libtomahawk/pipeline.cpp b/src/libtomahawk/pipeline.cpp index b7d538a37..c3bab44d6 100644 --- a/src/libtomahawk/pipeline.cpp +++ b/src/libtomahawk/pipeline.cpp @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -134,7 +134,7 @@ Pipeline::resolve( const query_ptr& q, bool prioritized ) { if ( q.isNull() ) return; - + QList< query_ptr > qlist; qlist << q; resolve( qlist, prioritized ); @@ -292,7 +292,7 @@ Pipeline::shunt( const query_ptr& q ) { incQIDState( q ); // qDebug() << "Shunting in" << lasttimeout << "ms, q:" << q->toString(); - new FuncTimeout( lasttimeout, boost::bind( &Pipeline::shunt, this, q ) ); + new FuncTimeout( lasttimeout, boost::bind( &Pipeline::shunt, this, q ), this ); } } else @@ -311,8 +311,8 @@ Pipeline::shunt( const query_ptr& q ) bool Pipeline::resolverSorter( const Resolver* left, const Resolver* right ) { - if( left->weight() == right->weight() ) - return left->preference() > right->preference(); + if( left->weight() == right->weight() ) // TODO dispatch in parallel + return left; else return left->weight() > right->weight(); } diff --git a/src/libtomahawk/resolver.cpp b/src/libtomahawk/resolver.cpp new file mode 100644 index 000000000..4e6a757fe --- /dev/null +++ b/src/libtomahawk/resolver.cpp @@ -0,0 +1,116 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "resolver.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +QVariant +Tomahawk::ExternalResolver::configMsgFromWidget( QWidget* w ) +{ + if( !w ) + return QVariant(); + + // generate a qvariantmap of all the widgets in the hierarchy, and for each one include the list of properties and values + QVariantMap widgetMap; + addChildProperties( w, widgetMap ); +// qDebug() << "Generated widget variant:" << widgetMap; + return widgetMap; +} + + +void +Tomahawk::ExternalResolver::addChildProperties( QObject* widget, QVariantMap& m ) +{ + // recursively add all properties of this widget to the map, then repeat on all children. + // bare QWidgets are boring---so skip them! They have no input that the user can set. + if( !widget || !widget->isWidgetType() ) + return; + + if( qstrcmp( widget->metaObject()->className(), "QWidget" ) != 0 ) + { +// qDebug() << "Adding properties for this:" << widget->metaObject()->className(); + // add this widget's properties + QVariantMap props; + for( int i = widget->metaObject()->propertyOffset(); i < widget->metaObject()->propertyCount(); i++ ) + { + QString prop = widget->metaObject()->property( i ).name(); + QVariant val = widget->property( prop.toLatin1() ); + // clean up for QJson.... + if( val.canConvert< QPixmap >() || val.canConvert< QImage >() || val.canConvert< QIcon >() ) + continue; + props[ prop ] = val; +// qDebug() << QString( "%1: %2" ).arg( prop ).arg( props[ prop ].toString() ); + } + m[ widget->objectName() ] = props; + } + // and recurse + foreach( QObject* child, widget->children() ) + addChildProperties( child, m ); +} + + +QWidget* +Tomahawk::ExternalResolver::widgetFromData( QByteArray& data, QWidget* parent ) +{ + if( data.isEmpty() ) + return 0; + + QUiLoader l; + QBuffer b( &data ); + QWidget* w = l.load( &b, parent ); + + return w; +} + +QByteArray +Tomahawk::ExternalResolver::fixDataImagePaths( const QByteArray& data, bool compressed, const QVariantMap& images ) +{ + // with a list of images and image data, write each to a temp file, replace the path in the .ui file with the temp file path + QString uiFile = QString::fromUtf8( data ); + foreach( const QString& filename, images.keys() ) + { + if( !uiFile.contains( filename ) ) // make sure the image is used + continue; + + QString fullPath = QDir::tempPath() + "/" + filename; + QFile imgF( fullPath ); + if( !imgF.open( QIODevice::WriteOnly ) ) + { + qWarning() << "Failed to write to temporary image in UI file:" << filename << fullPath; + continue; + } + QByteArray data = images[ filename ].toByteArray(); + qDebug() << "expanding data:" << data << compressed; + data = compressed ? qUncompress( QByteArray::fromBase64( data ) ) : QByteArray::fromBase64( data ); + imgF.write( data ); + imgF.close(); + + // replace the path to the image with the real path + uiFile.replace( filename, fullPath ); + } + return uiFile.toUtf8(); +} + diff --git a/src/libtomahawk/resolver.h b/src/libtomahawk/resolver.h index d1b526ffe..c3a3bae7e 100644 --- a/src/libtomahawk/resolver.h +++ b/src/libtomahawk/resolver.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -33,6 +33,9 @@ weighted resolver */ + +class QWidget; + namespace Tomahawk { @@ -45,12 +48,8 @@ public: virtual QString name() const = 0; virtual unsigned int weight() const = 0; - virtual unsigned int preference() const { return 100; }; virtual unsigned int timeout() const = 0; - //virtual QWidget * configUI() { return 0; }; - //etc - public slots: virtual void resolve( const Tomahawk::query_ptr& query ) = 0; }; @@ -64,10 +63,18 @@ public: virtual QString filePath() const { return m_filePath; } + virtual QWidget* configUI() const = 0; + virtual void saveConfig() = 0; public slots: virtual void stop() = 0; +protected: + QWidget* widgetFromData( QByteArray& data, QWidget* parent = 0 ); + QVariant configMsgFromWidget( QWidget* w ); + QByteArray fixDataImagePaths( const QByteArray& data, bool compressed, const QVariantMap& images ); private: + void addChildProperties( QObject* parent, QVariantMap& m ); + QString m_filePath; }; diff --git a/src/libtomahawk/tomahawksettings.cpp b/src/libtomahawk/tomahawksettings.cpp index 37a905cad..22ce4f548 100644 --- a/src/libtomahawk/tomahawksettings.cpp +++ b/src/libtomahawk/tomahawksettings.cpp @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -52,7 +52,7 @@ TomahawkSettings::TomahawkSettings( QObject* parent ) qDebug() << "Config version outdated, old:" << value( "configversion" ).toUInt() << "new:" << VERSION << "Doing upgrade, if any..."; - + // insert upgrade code here as required setValue( "configversion", VERSION ); } @@ -415,7 +415,7 @@ int TomahawkSettings::defaultPort() const { return 50210; -} +} int TomahawkSettings::externalPort() const @@ -485,7 +485,7 @@ TomahawkSettings::setTwitterScreenName( const QString& screenName ) { setValue( "twitter/ScreenName", screenName ); } - + QString TomahawkSettings::twitterOAuthToken() const { @@ -627,20 +627,33 @@ TomahawkSettings::setXmppBotPort( const int port ) setValue( "xmppBot/port", port ); } -void +void TomahawkSettings::addScriptResolver(const QString& resolver) { - setValue( "script/resolvers", scriptResolvers() << resolver ); + setValue( "script/resolvers", allScriptResolvers() << resolver ); } -QStringList -TomahawkSettings::scriptResolvers() const +QStringList +TomahawkSettings::allScriptResolvers() const { return value( "script/resolvers" ).toStringList(); } -void -TomahawkSettings::setScriptResolvers( const QStringList& resolver ) +void +TomahawkSettings::setAllScriptResolvers( const QStringList& resolver ) { setValue( "script/resolvers", resolver ); } + + +QStringList +TomahawkSettings::enabledScriptResolvers() const +{ + return value( "script/loadedresolvers" ).toStringList(); +} + +void +TomahawkSettings::setEnabledScriptResolvers( const QStringList& resolvers ) +{ + setValue( "script/loadedresolvers", resolvers ); +} diff --git a/src/libtomahawk/tomahawksettings.h b/src/libtomahawk/tomahawksettings.h index 42daa91e3..0b47ca685 100644 --- a/src/libtomahawk/tomahawksettings.h +++ b/src/libtomahawk/tomahawksettings.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -47,14 +47,14 @@ public: bool watchForChanges() const; void setWatchForChanges( bool watch ); - + bool acceptedLegalWarning() const; void setAcceptedLegalWarning( bool accept ); - + /// UI settings QByteArray mainWindowGeometry() const; void setMainWindowGeometry( const QByteArray& geom ); - + QByteArray mainWindowState() const; void setMainWindowState( const QByteArray& state ); @@ -71,24 +71,24 @@ public: /// Jabber settings bool jabberAutoConnect() const; /// true by default void setJabberAutoConnect( bool autoconnect = false ); - + QString jabberUsername() const; void setJabberUsername( const QString& username ); - + QString jabberPassword() const; void setJabberPassword( const QString& pw ); - + QString jabberServer() const; void setJabberServer( const QString& server ); - + unsigned int jabberPort() const; // default is 5222 void setJabberPort( int port ); - + /// Network settings enum ExternalAddressMode { Lan, Upnp }; ExternalAddressMode externalAddressMode() const; void setExternalAddressMode( ExternalAddressMode externalAddressMode ); - + bool preferStaticHostPort() const; void setPreferStaticHostPort( bool prefer ); @@ -120,42 +120,42 @@ public: /// ACL settings QStringList aclEntries() const; void setAclEntries( const QStringList &entries ); - + /// Last.fm settings bool scrobblingEnabled() const; /// false by default void setScrobblingEnabled( bool enable ); - + QString lastFmUsername() const; void setLastFmUsername( const QString& username ); - + QString lastFmPassword() const; void setLastFmPassword( const QString& password ); - + QByteArray lastFmSessionKey() const; void setLastFmSessionKey( const QByteArray& key ); - + /// Twitter settings QString twitterScreenName() const; void setTwitterScreenName( const QString& screenName ); - + QString twitterOAuthToken() const; void setTwitterOAuthToken( const QString& oauthtoken ); - + QString twitterOAuthTokenSecret() const; void setTwitterOAuthTokenSecret( const QString& oauthtokensecret ); qint64 twitterCachedFriendsSinceId() const; void setTwitterCachedFriendsSinceId( qint64 sinceid ); - + qint64 twitterCachedMentionsSinceId() const; void setTwitterCachedMentionsSinceId( qint64 sinceid ); - + qint64 twitterCachedDirectMessagesSinceId() const; void setTwitterCachedDirectMessagesSinceId( qint64 sinceid ); - + QHash twitterCachedPeers() const; void setTwitterCachedPeers( const QHash &cachedPeers ); - + /// XMPP Component Settings QString xmppBotServer() const; void setXmppBotServer( const QString &server ); @@ -168,11 +168,14 @@ public: int xmppBotPort() const; void setXmppBotPort( const int port ); - + /// Script resolver settings - QStringList scriptResolvers() const; - void setScriptResolvers( const QStringList& resolver ); + QStringList allScriptResolvers() const; + void setAllScriptResolvers( const QStringList& resolvers ); void addScriptResolver( const QString& resolver ); + QStringList enabledScriptResolvers() const; + void setEnabledScriptResolvers( const QStringList& resolvers ); + signals: void changed(); diff --git a/src/resolverconfigdelegate.cpp b/src/resolverconfigdelegate.cpp new file mode 100644 index 000000000..fb983c8ae --- /dev/null +++ b/src/resolverconfigdelegate.cpp @@ -0,0 +1,176 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + + +#include "resolverconfigdelegate.h" + +#include "resolversmodel.h" +#include "tomahawk/tomahawkapp.h" + +#include +#include +#include + +#define PADDING 4 + +ResolverConfigDelegate::ResolverConfigDelegate( QObject* parent ) + : QStyledItemDelegate( parent ) + , m_configPressed( false ) +{ + +} + +void +ResolverConfigDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + QStyleOptionViewItemV4 opt = option; + initStyleOption( &opt, index ); + QRect itemRect = opt.rect; + int top = itemRect.top(); + + QFont name = opt.font; + name.setPointSize( name.pointSize() + 2 ); + name.setBold( true ); + + QFont path = opt.font; + path.setItalic( true ); + path.setPointSize( path.pointSize() - 1 ); + + + QFontMetrics bfm( name ); + QFontMetrics sfm( path ); + + // draw the background + const QWidget* w = opt.widget; + QStyle* style = w ? w->style() : QApplication::style(); + style->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, w ); + + int rightSplit = itemRect.width(); + int rectW = opt.rect.height() - 4 * PADDING; + QRect confRect = QRect( rightSplit - rectW - 2 * PADDING, 2 * PADDING + top, rectW, rectW ); + // if the resolver has a config widget, paint it first (right-aligned) + if( index.data( ResolversModel::HasConfig ).toBool() ) { + // draw it the same size as the check belox + QStyleOptionToolButton topt; + topt.font = opt.font; + topt.icon = QIcon( RESPATH "images/configure.png" ); + topt.iconSize = QSize( 16, 16 ); + topt.rect = confRect; + topt.subControls = QStyle::SC_ToolButton; + topt.activeSubControls = QStyle::SC_None; + topt.features = QStyleOptionToolButton::None; + topt.pos = confRect.topLeft(); + topt.state = m_configPressed ? QStyle::State_On : QStyle::State_Raised; + if( opt.state & QStyle::State_MouseOver || m_configPressed ) + topt.state |= QStyle::State_HasFocus; + style->drawComplexControl( QStyle::CC_ToolButton, &topt, painter, w ); + } + + // draw check + confRect.moveTo( 2 * PADDING, 2 * PADDING + top ); + opt.rect = confRect; + opt.checkState == Qt::Checked ? opt.state |= QStyle::State_On : opt.state |= QStyle::State_Off; + style->drawPrimitive( QStyle::PE_IndicatorViewItemCheck, &opt, painter, w ); + itemRect.setX( opt.rect.topRight().x() + PADDING ); + + QString nameStr = bfm.elidedText( index.data( ResolversModel::ResolverName ).toString(),Qt::ElideRight, rightSplit ); + painter->save(); + painter->setFont( name ); + QRect textRect = itemRect.adjusted( PADDING, PADDING, -PADDING, -PADDING ); + textRect.setBottom( itemRect.height() / 2 + top ); + painter->drawText( textRect, nameStr ); + painter->restore(); + + QString pathStr = sfm.elidedText( index.data( ResolversModel::ResolverPath ).toString(),Qt::ElideMiddle, rightSplit ); + painter->save(); + painter->setFont( path ); + painter->setBrush( Qt::gray ); + textRect.moveTop( itemRect.height() / 2 + top ); + painter->drawText( textRect, pathStr ); + painter->restore(); + +} + +QSize +ResolverConfigDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + int width = QStyledItemDelegate::sizeHint( option, index ).width(); + + QStyleOptionViewItemV4 opt = option; + initStyleOption( &opt, index ); + + + QFont name = opt.font; + name.setPointSize( name.pointSize() + 2 ); + name.setBold( true ); + + QFont path = opt.font; + path.setItalic( true ); + path.setPointSize( path.pointSize() - 1 ); + + + QFontMetrics bfm( name ); + QFontMetrics sfm( path ); + return QSize( width, 3 * PADDING + bfm.height() + sfm.height() ); +} + +bool +ResolverConfigDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) +{ +// qDebug() << "EDITOR EVENT!" << ( event->type() == QEvent::MouseButtonRelease ); + + QStyleOptionViewItemV4 viewOpt( option ); + initStyleOption( &viewOpt, index ); + const QWidget* w = viewOpt.widget; + QStyle* style = w ? w->style() : QApplication::style(); + int top = viewOpt.rect.top(); + + if( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick ) { + m_configPressed = false; + + int rectW = option.rect.height() - 4 * PADDING; + QRect checkRect = QRect( 2 * PADDING, 2 * PADDING + top, rectW, rectW ); + QMouseEvent* me = static_cast< QMouseEvent* >( event ); + if( me->button() != Qt::LeftButton || !checkRect.contains( me->pos() ) ) + return false; + + // eat the double click events inside the check rect + if( event->type() == QEvent::MouseButtonDblClick ) { + return true; + } + + Qt::CheckState curState = static_cast< Qt::CheckState >( index.data( Qt::CheckStateRole ).toInt() ); + Qt::CheckState newState = curState == Qt::Checked ? Qt::Unchecked : Qt::Checked; + return model->setData( index, newState, Qt::CheckStateRole ); + + } else if( event->type() == QEvent::MouseButtonPress ) { + int rightSplit = viewOpt.rect.width(); + int rectW = viewOpt.rect.height() - 4 * PADDING; + QRect confRect = QRect( rightSplit - rectW - 2 * PADDING, 2 * PADDING + top, rectW, rectW ); + + QMouseEvent* me = static_cast< QMouseEvent* >( event ); + if( me->button() == Qt::LeftButton && confRect.contains( me->pos() ) ) { + m_configPressed = true; + + emit openConfig( index.data( ResolversModel::ResolverPath ).toString() ); + return true; + } + } + + return QStyledItemDelegate::editorEvent( event, model, option, index ); +} diff --git a/src/resolverconfigdelegate.h b/src/resolverconfigdelegate.h new file mode 100644 index 000000000..280e63ccb --- /dev/null +++ b/src/resolverconfigdelegate.h @@ -0,0 +1,42 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + + +#ifndef RESOLVERCONFIGDELEGATE_H +#define RESOLVERCONFIGDELEGATE_H + +#include + + +class ResolverConfigDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + explicit ResolverConfigDelegate(QObject* parent = 0); + virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index ); + +signals: + void openConfig( const QString& resolverPath ); + +private: + bool m_configPressed; +}; + +#endif // RESOLVERCONFIGDELEGATE_H diff --git a/src/resolverconfigwrapper.cpp b/src/resolverconfigwrapper.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/resolverconfigwrapper.h b/src/resolverconfigwrapper.h new file mode 100644 index 000000000..e43700e38 --- /dev/null +++ b/src/resolverconfigwrapper.h @@ -0,0 +1,68 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ +#ifndef RESOLVER_CONFIG_WRAPPER +#define RESOLVER_CONFIG_WRAPPER + +#include +#include +#include + +class ResolverConfigWrapper : public QDialog +{ + Q_OBJECT +public: + ResolverConfigWrapper( QWidget* conf, const QString& title, QWidget* parent ) : QDialog( parent ), m_widget( conf ) + { + setWindowTitle( title ); + + QVBoxLayout* v = new QVBoxLayout( this ); + v->addWidget( m_widget ); + + QDialogButtonBox* buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this ); + connect( buttons, SIGNAL( clicked( QAbstractButton*) ), this, SLOT( closed( QAbstractButton* ) ) ); + connect( this, SIGNAL( rejected() ), this, SLOT( rejected() ) ); + v->addWidget( buttons ); + + setLayout( v ); + } +public slots: + void closed( QAbstractButton* b ) + { + // let the config widget live to see another day + layout()->removeWidget( m_widget ); + m_widget->setParent( 0 ); + + QDialogButtonBox* buttons = qobject_cast< QDialogButtonBox* >( sender() ); + if( buttons->standardButton( b ) == QDialogButtonBox::Ok ) + done( QDialog::Accepted ); + else + done( QDialog::Rejected ); + } + + // we get a rejected() signal emitted if the user presses escape (and no clicked() signal ) + void rejected() + { + layout()->removeWidget( m_widget ); + m_widget->setParent( 0 ); + } + +private: + QWidget* m_widget; +}; + +#endif diff --git a/src/resolvers/qtscriptresolver.cpp b/src/resolvers/qtscriptresolver.cpp index 3d1773fe8..78375c522 100644 --- a/src/resolvers/qtscriptresolver.cpp +++ b/src/resolvers/qtscriptresolver.cpp @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -49,9 +49,8 @@ QtScriptResolver::QtScriptResolver( const QString& scriptPath ) m_name = m.value( "name" ).toString(); m_weight = m.value( "weight", 0 ).toUInt(); m_timeout = m.value( "timeout", 25 ).toUInt() * 1000; - m_preference = m.value( "preference", 0 ).toUInt(); - qDebug() << Q_FUNC_INFO << m_name << m_weight << m_timeout << m_preference; + qDebug() << Q_FUNC_INFO << m_name << m_weight << m_timeout; m_ready = true; Tomahawk::Pipeline::instance()->addResolver( this ); diff --git a/src/resolvers/qtscriptresolver.h b/src/resolvers/qtscriptresolver.h index a6850ac96..ed90f8261 100644 --- a/src/resolvers/qtscriptresolver.h +++ b/src/resolvers/qtscriptresolver.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -68,9 +68,10 @@ public: virtual QString name() const { return m_name; } virtual unsigned int weight() const { return m_weight; } - virtual unsigned int preference() const { return m_preference; } virtual unsigned int timeout() const { return m_timeout; } + virtual QWidget* configUI() const { return 0; } // TODO support properly for qtscript resolvers too! + virtual void saveConfig() {} public slots: virtual void resolve( const Tomahawk::query_ptr& query ); virtual void stop(); @@ -82,7 +83,7 @@ private: ScriptEngine* m_engine; QString m_name; - unsigned int m_weight, m_preference, m_timeout; + unsigned int m_weight, m_timeout; bool m_ready, m_stopped; }; diff --git a/src/resolvers/scriptresolver.cpp b/src/resolvers/scriptresolver.cpp index f84acf492..a713f186c 100644 --- a/src/resolvers/scriptresolver.cpp +++ b/src/resolvers/scriptresolver.cpp @@ -49,6 +49,9 @@ ScriptResolver::~ScriptResolver() stop(); Tomahawk::Pipeline::instance()->removeResolver( this ); + + if( !m_configWidget.isNull() ) + delete m_configWidget.data(); } @@ -94,8 +97,6 @@ ScriptResolver::sendMsg( const QByteArray& msg ) { qDebug() << Q_FUNC_INFO << m_ready << msg << msg.length(); - if( !m_ready ) return; - quint32 len; qToBigEndian( msg.length(), (uchar*) &len ); m_proc.write( (const char*) &len, 4 ); @@ -121,6 +122,9 @@ ScriptResolver::handleMsg( const QByteArray& msg ) { doSetup( m ); return; + } else if( msgtype == "confwidget" ) { + setupConfWidget( m ); + return; } if( msgtype == "results" ) @@ -212,7 +216,7 @@ ScriptResolver::resolve( const Tomahawk::query_ptr& query ) sendMsg( msg ); m_queryState.insert( query->id(), 1 ); - new Tomahawk::FuncTimeout( m_timeout, boost::bind( &ScriptResolver::onTimeout, this, query ) ); + new Tomahawk::FuncTimeout( m_timeout, boost::bind( &ScriptResolver::onTimeout, this, query ), this ); } @@ -223,17 +227,54 @@ ScriptResolver::doSetup( const QVariantMap& m ) m_name = m.value( "name" ).toString(); m_weight = m.value( "weight", 0 ).toUInt(); m_timeout = m.value( "timeout", 25 ).toUInt() * 1000; - m_preference = m.value( "preference", 0 ).toUInt(); qDebug() << "SCRIPT" << filePath() << "READY," << endl << "name" << m_name << endl << "weight" << m_weight << endl - << "timeout" << m_timeout << endl - << "preference" << m_preference; + << "timeout" << m_timeout; m_ready = true; Tomahawk::Pipeline::instance()->addResolver( this ); } +void +ScriptResolver::setupConfWidget( const QVariantMap& m ) +{ + bool compressed = m.value( "compressed", "false" ).toString() == "true"; + qDebug() << "Resolver has a preferences widget! compressed?" << compressed << m; + + QByteArray uiData = m[ "widget" ].toByteArray(); + if( compressed ) + uiData = qUncompress( QByteArray::fromBase64( uiData ) ); + else + uiData = QByteArray::fromBase64( uiData ); + + if( m.contains( "images" ) ) + uiData = fixDataImagePaths( uiData, compressed, m[ "images" ].toMap() ); + m_configWidget = QWeakPointer< QWidget >( widgetFromData( uiData, 0 ) ); +} + + +void +ScriptResolver::saveConfig() +{ + Q_ASSERT( !m_configWidget.isNull() ); + + QVariantMap m; + m.insert( "_msgtype", "setpref" ); + QVariant widgets = configMsgFromWidget( m_configWidget.data() ); + m.insert( "widgets", widgets ); + QByteArray data = m_serializer.serialize( m ); + sendMsg( data ); +} + +QWidget* ScriptResolver::configUI() const +{ + if( m_configWidget.isNull() ) + return 0; + else + return m_configWidget.data(); +} + void ScriptResolver::stop() diff --git a/src/resolvers/scriptresolver.h b/src/resolvers/scriptresolver.h index 60d636352..34e29fdd2 100644 --- a/src/resolvers/scriptresolver.h +++ b/src/resolvers/scriptresolver.h @@ -29,6 +29,7 @@ #include "query.h" #include "result.h" +class QWidget; class ScriptResolver : public Tomahawk::ExternalResolver { Q_OBJECT @@ -42,6 +43,9 @@ public: virtual unsigned int preference() const { return m_preference; } virtual unsigned int timeout() const { return m_timeout; } + virtual QWidget* configUI() const; + virtual void saveConfig(); + signals: void finished(); @@ -60,10 +64,12 @@ private: void handleMsg( const QByteArray& msg ); void sendMsg( const QByteArray& msg ); void doSetup( const QVariantMap& m ); + void setupConfWidget( const QVariantMap& m ); QProcess m_proc; QString m_name; unsigned int m_weight, m_preference, m_timeout, m_num_restarts; + QWeakPointer< QWidget > m_configWidget; quint32 m_msgsize; QByteArray m_msg; diff --git a/src/resolversmodel.cpp b/src/resolversmodel.cpp new file mode 100644 index 000000000..07e7c8aca --- /dev/null +++ b/src/resolversmodel.cpp @@ -0,0 +1,154 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + + +#include "resolversmodel.h" +#include +#include +#include + + +ResolversModel::ResolversModel( const QStringList& allResolvers, const QStringList& enabledResolvers, QObject* parent ) + : QAbstractListModel( parent ) + , m_allResolvers( allResolvers ) + , m_enabledResolvers( enabledResolvers ) +{ + // do some sanity checking just in case + bool changed = false; + foreach( const QString& l, m_enabledResolvers ) { + if( !m_allResolvers.contains( l ) ) { + m_enabledResolvers.removeAll( l ); + changed = true; + } + } + if( changed ) + TomahawkSettings::instance()->setEnabledScriptResolvers( m_enabledResolvers ); + +} + + +ResolversModel::~ResolversModel() +{ + +} + +QVariant +ResolversModel::data( const QModelIndex& index, int role ) const +{ + if( !index.isValid() ) + return QVariant(); + + switch( role ) + { + case Qt::DisplayRole: + case ResolversModel::ResolverName: + { + QFileInfo info( m_allResolvers.at( index.row() ) ); + return info.baseName(); + } + case ResolversModel::ResolverPath: + return m_allResolvers.at( index.row() ); + case ResolversModel::HasConfig: + if( Tomahawk::ExternalResolver* r = TomahawkApp::instance()->resolverForPath( m_allResolvers.at( index.row() ) ) ) // if we have one, it means we are loaded too! + return r->configUI() != 0; + return false; + case Qt::CheckStateRole: + return m_enabledResolvers.contains( m_allResolvers.at( index.row() ) ) ? Qt::Checked : Qt::Unchecked; + default: + return QVariant(); + } +} + +bool +ResolversModel::setData( const QModelIndex& index, const QVariant& value, int role ) +{ + if( role == Qt::CheckStateRole ) { + Qt::CheckState state = static_cast< Qt::CheckState >( value.toInt() ); + QString resolver = m_allResolvers.at( index.row() ); + + if( state == Qt::Checked && !m_enabledResolvers.contains( resolver ) ) { + m_enabledResolvers.append( resolver ); + + TomahawkApp::instance()->enableScriptResolver( resolver ); + } else if( state == Qt::Unchecked ) { + m_enabledResolvers.removeAll( resolver ); + + TomahawkApp::instance()->disableScriptResolver( resolver ); + } + dataChanged( index, index ); + + return true; + } + return false; +} + + +int +ResolversModel::rowCount( const QModelIndex& parent ) const +{ + return m_allResolvers.size(); +} + +int +ResolversModel::columnCount(const QModelIndex& parent) const +{ + return 1; +} + +Qt::ItemFlags +ResolversModel::flags( const QModelIndex& index ) const +{ + return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable; +} + + +void +ResolversModel::addResolver( const QString& resolver, bool enable ) +{ + beginInsertRows( QModelIndex(), m_allResolvers.count(), m_allResolvers.count() ); + m_allResolvers << resolver; + if( enable ) + m_enabledResolvers << resolver; + endInsertRows(); +} + +void +ResolversModel::removeResolver( const QString& resolver ) +{ + for( int i = 0; i < m_allResolvers.count(); i++ ) { + if( m_allResolvers.at( i ) == resolver ) { + beginRemoveRows( QModelIndex(), i, i ); + m_allResolvers.takeAt( i ); + endRemoveRows(); + } + } + m_enabledResolvers.removeAll( resolver ); +} + +QStringList +ResolversModel::allResolvers() const +{ + return m_allResolvers; +} + +QStringList +ResolversModel::enabledResolvers() const +{ + return m_enabledResolvers; +} + diff --git a/src/resolversmodel.h b/src/resolversmodel.h new file mode 100644 index 000000000..c6cf8fa73 --- /dev/null +++ b/src/resolversmodel.h @@ -0,0 +1,55 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + + +#ifndef RESOLVERSMODEL_H +#define RESOLVERSMODEL_H + +#include +#include + + +class ResolversModel : public QAbstractListModel +{ +public: + enum Roles { + ResolverName = Qt::UserRole + 15, + ResolverPath = Qt::UserRole + 16, + HasConfig = Qt::UserRole + 17 + }; + + explicit ResolversModel( const QStringList& allResolvers, const QStringList& enabledResolvers, QObject* parent = 0 ); + virtual ~ResolversModel(); + + virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; + virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const; + virtual int columnCount( const QModelIndex& parent ) const; + virtual Qt::ItemFlags flags(const QModelIndex& index) const; + virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); + + void addResolver( const QString& resolver, bool enable = false ); + void removeResolver( const QString& resolver ); + + QStringList allResolvers() const; + QStringList enabledResolvers() const; +private: + QStringList m_allResolvers; + QStringList m_enabledResolvers; +}; + +#endif // RESOLVERSMODEL_H diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 72bc4edbe..966f193d1 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef LIBLASTFM_FOUND #include @@ -39,6 +40,9 @@ #include "sip/SipHandler.h" #include #include "scanmanager.h" +#include "resolverconfigdelegate.h" +#include "resolversmodel.h" +#include "resolverconfigwrapper.h" static QString md5( const QByteArray& src ) @@ -47,7 +51,6 @@ md5( const QByteArray& src ) return QString::fromLatin1( digest.toHex() ).rightJustified( 32, '0' ); } - SettingsDialog::SettingsDialog( QWidget *parent ) : QDialog( parent ) , ui( new Ui::SettingsDialog ) @@ -96,18 +99,19 @@ SettingsDialog::SettingsDialog( QWidget *parent ) ui->lineEditLastfmUsername->setText( s->lastFmUsername() ); ui->lineEditLastfmPassword->setText(s->lastFmPassword() ); connect( ui->pushButtonTestLastfmLogin, SIGNAL( clicked( bool) ), this, SLOT( testLastFmLogin() ) ); - + // SCRIPT RESOLVER ui->removeScript->setEnabled( false ); - foreach( const QString& resolver, s->scriptResolvers() ) { - QFileInfo info( resolver ); - ui->scriptList->addTopLevelItem( new QTreeWidgetItem( QStringList() << info.baseName() << resolver ) ); - - } - connect( ui->scriptList, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), this, SLOT( scriptSelectionChanged() ) ); + ResolverConfigDelegate* del = new ResolverConfigDelegate( this ); + connect( del, SIGNAL( openConfig( QString ) ), this, SLOT( openResolverConfig( QString ) ) ); + ui->scriptList->setItemDelegate( del ); + m_resolversModel = new ResolversModel( s->allScriptResolvers(), s->enabledScriptResolvers(), this ); + ui->scriptList->setModel( m_resolversModel ); + + connect( ui->scriptList->selectionModel(), SIGNAL( selectionChanged( QItemSelection,QItemSelection ) ), this, SLOT( scriptSelectionChanged() ) ); connect( ui->addScript, SIGNAL( clicked( bool ) ), this, SLOT( addScriptResolver() ) ); connect( ui->removeScript, SIGNAL( clicked( bool ) ), this, SLOT( removeScriptResolver() ) ); - + connect( ui->buttonBrowse, SIGNAL( clicked() ), SLOT( showPathSelector() ) ); connect( ui->proxyButton, SIGNAL( clicked() ), SLOT( showProxySettings() ) ); connect( ui->checkBoxStaticPreferred, SIGNAL( toggled(bool) ), SLOT( toggleUpnp(bool) ) ); @@ -132,23 +136,19 @@ SettingsDialog::~SettingsDialog() s->setJabberPassword( ui->jabberPassword->text() ); s->setJabberServer( ui->jabberServer->text() ); s->setJabberPort( ui->jabberPort->value() ); - + s->setExternalHostname( ui->staticHostName->text() ); s->setExternalPort( ui->staticPort->value() ); s->setScannerPaths( QStringList( ui->lineEditMusicPath->text() ) ); s->setWatchForChanges( ui->checkBoxWatchForChanges->isChecked() ); - + s->setScrobblingEnabled( ui->checkBoxEnableLastfm->isChecked() ); s->setLastFmUsername( ui->lineEditLastfmUsername->text() ); s->setLastFmPassword( ui->lineEditLastfmPassword->text() ); - QStringList resolvers; - for( int i = 0; i < ui->scriptList->topLevelItemCount(); i++ ) - { - resolvers << ui->scriptList->topLevelItem( i )->data( 1, Qt::DisplayRole ).toString(); - } - s->setScriptResolvers( resolvers ); + s->setAllScriptResolvers( m_resolversModel->allResolvers() ); + s->setEnabledScriptResolvers( m_resolversModel->enabledResolvers() ); s->applyChanges(); } @@ -260,13 +260,13 @@ SettingsDialog::onLastFmFinished() ui->pushButtonTestLastfmLogin->setEnabled( false ); } break; - + case QNetworkReply::ContentOperationNotPermittedError: case QNetworkReply::AuthenticationRequiredError: ui->pushButtonTestLastfmLogin->setText( tr( "Failed" ) ); ui->pushButtonTestLastfmLogin->setEnabled( true ); break; - + default: qDebug() << "Couldn't get last.fm auth result"; ui->pushButtonTestLastfmLogin->setText( tr( "Could not contact server" ) ); @@ -336,38 +336,50 @@ ProxyDialog::saveSettings() } -void +void SettingsDialog::addScriptResolver() { QString resolver = QFileDialog::getOpenFileName( this, tr( "Load script resolver file" ), qApp->applicationDirPath() ); if( !resolver.isEmpty() ) { - QFileInfo info( resolver ); - ui->scriptList->addTopLevelItem( new QTreeWidgetItem( QStringList() << info.baseName() << resolver ) ); - - TomahawkApp::instance()->addScriptResolver( resolver ); + m_resolversModel->addResolver( resolver, true ); + TomahawkApp::instance()->enableScriptResolver( resolver ); } } -void +void SettingsDialog::removeScriptResolver() { // only one selection - if( !ui->scriptList->selectedItems().isEmpty() ) { - QString resolver = ui->scriptList->selectedItems().first()->data( 1, Qt::DisplayRole ).toString(); - delete ui->scriptList->takeTopLevelItem( ui->scriptList->indexOfTopLevelItem( ui->scriptList->selectedItems().first() ) ); - - TomahawkApp::instance()->removeScriptResolver( resolver ); + if( !ui->scriptList->selectionModel()->selectedIndexes().isEmpty() ) { + QString resolver = ui->scriptList->selectionModel()->selectedIndexes().first().data( ResolversModel::ResolverPath ).toString(); + m_resolversModel->removeResolver( resolver ); + + TomahawkApp::instance()->disableScriptResolver( resolver ); } } - -void +void SettingsDialog::scriptSelectionChanged() { - if( !ui->scriptList->selectedItems().isEmpty() ) { + if( !ui->scriptList->selectionModel()->selectedIndexes().isEmpty() ) { ui->removeScript->setEnabled( true ); } else { ui->removeScript->setEnabled( false ); } } + +void +SettingsDialog::openResolverConfig( const QString& resolver ) +{ + Tomahawk::ExternalResolver* r = TomahawkApp::instance()->resolverForPath( resolver ); + if( r && r->configUI() ) { + ResolverConfigWrapper dialog( r->configUI(), "Resolver Config", this ); + QWeakPointer< ResolverConfigWrapper > watcher( &dialog ); + int ret = dialog.exec(); + if( !watcher.isNull() && ret == QDialog::Accepted ) { + // send changed config to resolver + r->saveConfig(); + } + } +} diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 02a3c608f..880c319da 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -21,6 +21,7 @@ #include +class ResolversModel; class QNetworkReply; namespace Ui @@ -53,7 +54,7 @@ public: signals: void settingsChanged(); - + protected: void changeEvent( QEvent* e ); @@ -71,13 +72,15 @@ private slots: void addScriptResolver(); void scriptSelectionChanged(); void removeScriptResolver(); - + void openResolverConfig( const QString& ); + private: Ui::SettingsDialog* ui; ProxyDialog m_proxySettings; bool m_rejected; QNetworkReply* m_testLastFmQuery; + ResolversModel* m_resolversModel; }; #endif // SETTINGSDIALOG_H diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 0558568b6..292e7cf59 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -23,7 +23,7 @@ - 0 + 4 @@ -590,7 +590,7 @@ - + true @@ -600,40 +600,18 @@ false + + true + false true - - 2 + + true - - false - - - true - - - 150 - - - true - - - true - - - - 1 - - - - - 2 - - diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 541068403..ea5311844 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -289,7 +289,7 @@ TomahawkApp::~TomahawkApp() qDebug() << Q_FUNC_INFO; // stop script resolvers - foreach( Tomahawk::ExternalResolver* r, m_scriptResolvers ) + foreach( Tomahawk::ExternalResolver* r, m_scriptResolvers.values() ) { delete r; } @@ -415,37 +415,41 @@ TomahawkApp::setupPipeline() Pipeline::instance()->addResolver( new DatabaseResolver( 100 ) ); // load script resolvers - foreach( QString resolver, TomahawkSettings::instance()->scriptResolvers() ) - addScriptResolver( resolver ); + foreach( QString resolver, TomahawkSettings::instance()->enabledScriptResolvers() ) + enableScriptResolver( resolver ); } void -TomahawkApp::addScriptResolver( const QString& path ) +TomahawkApp::enableScriptResolver( const QString& path ) { const QFileInfo fi( path ); if ( fi.suffix() == "js" || fi.suffix() == "script" ) - m_scriptResolvers << new QtScriptResolver( path ); + m_scriptResolvers.insert( path, new QtScriptResolver( path ) ); else - m_scriptResolvers << new ScriptResolver( path ); + m_scriptResolvers.insert( path, new ScriptResolver( path ) ); } void -TomahawkApp::removeScriptResolver( const QString& path ) +TomahawkApp::disableScriptResolver( const QString& path ) { - foreach( Tomahawk::ExternalResolver* r, m_scriptResolvers ) + if( m_scriptResolvers.contains( path ) ) { - if( r->filePath() == path ) - { - m_scriptResolvers.removeAll( r ); - connect( r, SIGNAL( finished() ), r, SLOT( deleteLater() ) ); - r->stop(); - return; - } + Tomahawk::ExternalResolver* r = m_scriptResolvers.take( path ); + + connect( r, SIGNAL( finished() ), r, SLOT( deleteLater() ) ); + r->stop(); + return; } } +Tomahawk::ExternalResolver* +TomahawkApp::resolverForPath( const QString& scriptPath ) +{ + return m_scriptResolvers.value( scriptPath, 0 ); +} + void TomahawkApp::initLocalCollection()