From 118b0a1cbf4d09412428e484f737018546187c10 Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Mon, 11 Mar 2013 22:53:58 +0100 Subject: [PATCH] Found a better place to do bundle loading, and also load metadata. --- src/SettingsDialog.cpp | 44 ++------- src/libtomahawk/accounts/Account.h | 2 + src/libtomahawk/accounts/AccountDelegate.cpp | 9 +- src/libtomahawk/accounts/AccountModel.cpp | 6 +- src/libtomahawk/accounts/ResolverAccount.cpp | 99 +++++++++++++++++++- src/libtomahawk/accounts/ResolverAccount.h | 8 +- 6 files changed, 121 insertions(+), 47 deletions(-) diff --git a/src/SettingsDialog.cpp b/src/SettingsDialog.cpp index cc2bcabee..4e8693230 100644 --- a/src/SettingsDialog.cpp +++ b/src/SettingsDialog.cpp @@ -451,48 +451,18 @@ SettingsDialog::openAccountConfig( Account* account, bool showDelete ) void SettingsDialog::installFromFile() { - QString resolver = QFileDialog::getOpenFileName( 0, tr( "Install resolver from file" ), - TomahawkSettings::instance()->scriptDefaultPath(), - tr( "Tomahawk Resolvers (*.axe *.js);;" - "All files (*)" ), - 0, - QFileDialog::ReadOnly ); + const QString resolver = QFileDialog::getOpenFileName( 0, tr( "Install resolver from file" ), + TomahawkSettings::instance()->scriptDefaultPath(), + tr( "Tomahawk Resolvers (*.axe *.js);;" + "All files (*)" ), + 0, + QFileDialog::ReadOnly ); if( !resolver.isEmpty() ) { - //I'm still a little proof of concept, refactor me into a proper class - QFileInfo resolverAbsoluteFilePath( resolver ); + const QFileInfo resolverAbsoluteFilePath( resolver ); TomahawkSettings::instance()->setScriptDefaultPath( resolverAbsoluteFilePath.absolutePath() ); - if ( resolverAbsoluteFilePath.suffix() == "axe" ) - { - QDir dir( TomahawkUtils::extractScriptPayload( resolverAbsoluteFilePath.filePath(), - resolverAbsoluteFilePath.baseName(), - "manualresolvers" ) ); - dir.cd( "content" ); - QFile desktopFile( dir.absoluteFilePath( "metadata.desktop" ) ); - if ( desktopFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) - { - QTextStream desktopFileStream( &desktopFile ); - - while ( !desktopFileStream.atEnd() ) - { - QString line = desktopFileStream.readLine().trimmed(); - //TODO: correct baseName - if ( line.startsWith( "X-Synchrotron-MainScript" ) ) - { - line.remove( QRegExp( "^X-Synchrotron-MainScript\\s*=\\s*" ) ); - resolver = dir.absoluteFilePath( line ); //this is our path to the JS - } - } - } - } - resolverAbsoluteFilePath = QFileInfo( resolver ); - - //TODO: if the new path has a metadata file in the dir structure, read it, check the config - // and act accordingly for multi-account resolvers - - if ( resolverAbsoluteFilePath.baseName() == "spotify_tomahawkresolver" ) { // HACK if this is a spotify resolver, we treat it specially. diff --git a/src/libtomahawk/accounts/Account.h b/src/libtomahawk/accounts/Account.h index 324a76779..54b6db6ec 100644 --- a/src/libtomahawk/accounts/Account.h +++ b/src/libtomahawk/accounts/Account.h @@ -88,6 +88,8 @@ public: virtual QWidget* aclWidget() = 0; virtual QPixmap icon() const = 0; #endif + virtual QString description() const { return QString(); } + virtual QString author() const { return QString(); } virtual void saveConfig() {} // called when the widget has been edited. save values from config widget, call sync() to write to disk account generic settings diff --git a/src/libtomahawk/accounts/AccountDelegate.cpp b/src/libtomahawk/accounts/AccountDelegate.cpp index 2786e33d2..2ca7d3e1e 100644 --- a/src/libtomahawk/accounts/AccountDelegate.cpp +++ b/src/libtomahawk/accounts/AccountDelegate.cpp @@ -278,11 +278,16 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, // Draw the title and description // title QString title = index.data( Qt::DisplayRole ).toString(); + QString author = index.data( AccountModel::AuthorRole ).toString(); + QString desc = index.data( AccountModel::DescriptionRole ).toString(); + const int rightTitleEdge = rightEdge - PADDING; const int leftTitleEdge = pixmapRect.right() + PADDING; painter->setFont( titleFont ); QRect textRect; - const bool canRate = index.data( AccountModel::CanRateRole ).toBool(); + const bool canRate = index.data( AccountModel::CanRateRole ).toBool() + || !author.isEmpty() + || !desc.isEmpty(); // if it's Attica, or it has non-empty at least author or description if ( canRate ) { textRect = QRect( leftTitleEdge, opt.rect.top() + PADDING, rightTitleEdge - leftTitleEdge, painter->fontMetrics().height() ); @@ -294,7 +299,6 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, painter->drawText( textRect, Qt::AlignVCenter | Qt::AlignLeft, title ); // author - QString author = index.data( AccountModel::AuthorRole ).toString(); int runningBottom = textRect.bottom(); if ( !author.isEmpty() && canRate ) { @@ -310,7 +314,6 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, } // description - QString desc = index.data( AccountModel::DescriptionRole ).toString(); const int descWidth = rightEdge - leftTitleEdge - PADDING; painter->setFont( descFont ); const QRect descRect( leftTitleEdge, runningBottom + PADDING, descWidth, painter->fontMetrics().height() ); diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index c32582eb0..637ff55a1 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -337,7 +337,11 @@ AccountModel::data( const QModelIndex& index, int role ) const case Qt::DecorationRole: return acct->icon(); case DescriptionRole: - return node->factory ? node->factory->description() : QString(); + return node->factory ? + ( !node->factory->description().isEmpty() ? node->factory->description() : acct->description() ) + : acct->description(); + case AuthorRole: + return acct->author(); case Qt::CheckStateRole: return acct->enabled() ? Qt::Checked : Qt::Unchecked; case AccountData: diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 1384cdb63..e41630109 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -66,8 +66,84 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact QFileInfo info( path ); return new AtticaResolverAccount( generateId( factory ), path, info.baseName() ); } - else - return new ResolverAccount( generateId( factory ), path ); + else //on filesystem, but it could be a bundle or a legacy resolver file + { + QString realPath( path ); + const QFileInfo pathInfo( path ); + + QVariantHash configuration; + + if ( pathInfo.suffix() == "axe" ) + { + QDir dir( TomahawkUtils::extractScriptPayload( pathInfo.filePath(), + pathInfo.baseName(), + "manualresolvers" ) ); + if ( !( dir.exists() && dir.isReadable() ) ) //decompression fubar + return 0; + + if ( !dir.cd( "content" ) ) //more fubar + return 0; + + QString desktopFilePath = dir.absoluteFilePath( "metadata.desktop" ); + + configuration = metadataFromDesktopFile( desktopFilePath ); + realPath = configuration[ "path" ].toString(); + if ( realPath.isEmpty() ) + return 0; + } + else //either legacy resolver or uncompressed bundle, so we look for a metadata file + { + QDir dir = pathInfo.absoluteDir();//assume we are in the code directory of a bundle + if ( dir.cdUp() && dir.cdUp() ) //go up twice to the content dir, if any + { + QString desktopFilePath = dir.absoluteFilePath( "metadata.desktop" ); + configuration = metadataFromDesktopFile( desktopFilePath ); + configuration[ "path" ] = realPath; //our initial path still overrides whatever the desktop file says + } + //else we just have empty metadata (legacy resolver without desktop file) + } + + //TODO: handle multi-account resolvers + + return new ResolverAccount( generateId( factory ), realPath, configuration ); + } +} + + +QVariantHash +ResolverAccountFactory::metadataFromDesktopFile( const QString& path ) +{ + QVariantHash result; + QFile desktopFile( path ); + if ( desktopFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + QTextStream desktopFileStream( &desktopFile ); + + while ( !desktopFileStream.atEnd() ) + { + QString line = desktopFileStream.readLine().trimmed(); + + if ( line.contains( QRegExp( "^X-Synchrotron-MainScript\\s*=\\s*" ) ) ) + { + line.remove( QRegExp( "^X-Synchrotron-MainScript\\s*=\\s*" ) ); + QFileInfo fi( path ); + result[ "path" ] = fi.absoluteDir().absoluteFilePath( line ); //this is our path to the JS + } + else if ( line.contains( QRegExp( "^X-KDE-PluginInfo-Author\\s*=\\s*" ) ) ) + { + line.remove( QRegExp( "^X-KDE-PluginInfo-Author\\s*=\\s*" ) ); + result[ "author" ] = line; + } + else if ( line.contains( QRegExp( "^Comment\\s*=\\s*" ) ) ) + { + line.remove( QRegExp( "^Comment\\s*=\\s*" ) ); + result[ "description" ] = line; + } + + //TODO: correct baseName and rename directory maybe? + } + } + return result; } @@ -84,10 +160,10 @@ ResolverAccount::ResolverAccount( const QString& accountId ) } -ResolverAccount::ResolverAccount( const QString& accountId, const QString& path ) +ResolverAccount::ResolverAccount( const QString& accountId, const QString& path, const QVariantHash& initialConfiguration ) : Account( accountId ) { - QVariantHash configuration; + QVariantHash configuration( initialConfiguration ); configuration[ "path" ] = path; setConfiguration( configuration ); @@ -242,6 +318,21 @@ ResolverAccount::icon() const return m_resolver.data()->icon(); } + +QString +ResolverAccount::description() const +{ + return configuration().value( "description" ).toString(); +} + + +QString +ResolverAccount::author() const +{ + return configuration().value( "author" ).toString(); +} + + /// AtticaResolverAccount AtticaResolverAccount::AtticaResolverAccount( const QString& accountId ) diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index 830f3c0ba..06466fade 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -51,6 +51,9 @@ public: // Internal use static Account* createFromPath( const QString& path, const QString& factoryId, bool isAttica ); + +private: + static QVariantHash metadataFromDesktopFile( const QString& path ); }; /** @@ -80,6 +83,8 @@ public: QString path() const; virtual QPixmap icon() const; + virtual QString description() const; + virtual QString author() const; // Not relevant virtual SipPlugin* sipPlugin() { return 0; } @@ -91,8 +96,7 @@ private slots: protected: // Created by factory, when user installs a new resolver - ResolverAccount( const QString& accountId, const QString& path ); - + ResolverAccount( const QString& accountId, const QString& path, const QVariantHash& initialConfiguration = QVariantHash() ); void hookupResolver(); QPointer m_resolver;