From ccc4db22706a86babd95ffbea28a9ebb77c62f01 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Thu, 5 May 2011 22:14:30 -0700 Subject: [PATCH 01/53] Copy over Adium files from Adium branch. --- .../infosystem/infoplugins/adium.h | 25 ++++ .../infosystem/infoplugins/adium.mm | 30 +++++ .../infosystem/infoplugins/adiumplugin.cpp | 121 ++++++++++++++++++ .../infosystem/infoplugins/adiumplugin.h | 54 ++++++++ 4 files changed, 230 insertions(+) create mode 100644 src/libtomahawk/infosystem/infoplugins/adium.h create mode 100644 src/libtomahawk/infosystem/infoplugins/adium.mm create mode 100644 src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp create mode 100644 src/libtomahawk/infosystem/infoplugins/adiumplugin.h diff --git a/src/libtomahawk/infosystem/infoplugins/adium.h b/src/libtomahawk/infosystem/infoplugins/adium.h new file mode 100644 index 000000000..9833fe82b --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/adium.h @@ -0,0 +1,25 @@ +/* === 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 ADIUM_TOMAHAWK_H +#define ADIUM_TOMAHAWK_H +#include + +void script( const char* status ); + +#endif ADIUM_TOMAHAWK_H diff --git a/src/libtomahawk/infosystem/infoplugins/adium.mm b/src/libtomahawk/infosystem/infoplugins/adium.mm new file mode 100644 index 000000000..576bc0624 --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/adium.mm @@ -0,0 +1,30 @@ +/* === 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 . + */ + +#import +#import +#import "adium.h" + +void script( const char* status ) +{ + NSString *stat = [NSString stringWithUTF8String:status]; + NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:stat]; + NSDictionary *errorDictionary; + NSAppleEventDescriptor *eventDescriptor = [appleScript executeAndReturnError:&errorDictionary]; + [appleScript release]; +} diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp new file mode 100644 index 000000000..acb36d30e --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -0,0 +1,121 @@ +/* === 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 + +#include "artist.h" +#include "result.h" + +#include "adiumplugin.h" +#include "adium.h" + +static void setStatus(const QString &status) +{ + QString adiumStatus = "tell application \"Adium\"\n"; + adiumStatus.append("set the status message of every account to \""); + adiumStatus.append(status); + adiumStatus.append("\"\nend tell\n"); + const char* scriptstr = adiumStatus.toUtf8(); + script( scriptstr ); + +} + +using namespace Tomahawk::InfoSystem; + +AdiumPlugin::AdiumPlugin(QObject *parent) + : InfoPlugin(parent) +{ + /** No supported types since the plugin pushes info, doesn't get any */ + qDebug() << Q_FUNC_INFO; + QSet< InfoType > supportedTypes; + InfoSystem *system = qobject_cast< InfoSystem* >(parent); + system->registerInfoTypes(this, supportedTypes); + + /** Connect to audio state signals. + TODO: Move this into InfoSystem? There could end up being many plugins + connected to audio state signals. */ + + connect( system, SIGNAL( audioStarted( const Tomahawk::result_ptr& ) ), + SLOT( audioStarted( const Tomahawk::result_ptr& ) ) ); + connect( system, SIGNAL( audioFinished( const Tomahawk::result_ptr& ) ), + SLOT( audioFinished( const Tomahawk::result_ptr& ) ) ); + connect( system, SIGNAL( audioStopped() ), + SLOT( audioStopped() ) ); + connect( system, SIGNAL( audioPaused() ), + SLOT( audioPaused() ) ); + connect( system, SIGNAL( audioResumed( const Tomahawk::result_ptr& ) ), + SLOT( audioResumed( const Tomahawk::result_ptr& ) ) ); + +} + +AdiumPlugin::~AdiumPlugin() +{ + qDebug() << Q_FUNC_INFO; + setStatus( "" ); +} + +void AdiumPlugin::getInfo(const QString &caller, const InfoType type, const QVariant& data, InfoCustomData customData) +{ + switch (type) + { + default: + { + emit info(caller, Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariant(), customData); + return; + } + } +} + +/** Audio state slots */ + +void AdiumPlugin::audioStarted( const Tomahawk::result_ptr& track ) +{ + qDebug() << Q_FUNC_INFO; + QString nowPlaying = ""; + nowPlaying.append( track->track() ); + nowPlaying.append(" - "); + nowPlaying.append(track->artist()->name()); + setStatus( nowPlaying ); +} + +void AdiumPlugin::audioFinished( const Tomahawk::result_ptr& track ) +{ + //qDebug() << Q_FUNC_INFO; +} + +void AdiumPlugin::audioStopped() +{ + qDebug() << Q_FUNC_INFO; + // TODO: audio stopped, so push update status to Adium that says "stopped" + setStatus( "Stopped" ); +} + +void AdiumPlugin::audioPaused() +{ + qDebug() << Q_FUNC_INFO; + // TODO: audio paused, so push update status to Adium that says "paused" + setStatus( "Paused" ); +} + +void AdiumPlugin::audioResumed( const Tomahawk::result_ptr& track ) +{ + qDebug() << Q_FUNC_INFO; + // TODO: audio resumed, so push update status to Adium with playing track + this->audioStarted( track ); +} + diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.h b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h new file mode 100644 index 000000000..604432ab1 --- /dev/null +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h @@ -0,0 +1,54 @@ +/* === 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 ADIUMPLUGIN_H +#define ADIUMPLUGIN_H + +#include "infosystem/infosystem.h" + +#include + +namespace Tomahawk { + +namespace InfoSystem { + +class AdiumPlugin : public InfoPlugin +{ + Q_OBJECT + +public: + AdiumPlugin( QObject *parent ); + virtual ~AdiumPlugin(); + + void getInfo( const QString &caller, const InfoType type, const QVariant &data, InfoCustomData customData ); + +public slots: + void audioStarted( const Tomahawk::result_ptr& track ); + void audioFinished( const Tomahawk::result_ptr& track ); + void audioStopped(); + void audioPaused(); + void audioResumed( const Tomahawk::result_ptr& track ); + +}; + + +} + +} + +#endif // ADIUMPLUGIN_H From fb9069320ed08530c589bf13205c6deee6195bb6 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Sat, 7 May 2011 12:03:52 -0700 Subject: [PATCH 02/53] Build AdiumPlugin, now a pushInfo-using InfoPlugin. --- src/libtomahawk/CMakeLists.txt | 14 +++- src/libtomahawk/audio/audioengine.cpp | 11 +++ .../infosystem/infoplugins/adiumplugin.cpp | 68 +++++++++++-------- .../infosystem/infoplugins/adiumplugin.h | 16 +++-- src/libtomahawk/infosystem/infosystem.cpp | 1 + src/libtomahawk/infosystem/infosystem.h | 4 +- .../infosystem/infosystemworker.cpp | 3 + 7 files changed, 82 insertions(+), 35 deletions(-) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 3e1d9e258..3ebd0a70f 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -382,7 +382,17 @@ ENDIF( WIN32 ) IF( APPLE ) FIND_LIBRARY( COREAUDIO_LIBRARY CoreAudio ) FIND_LIBRARY( COREFOUNDATION_LIBRARY CoreFoundation ) - MARK_AS_ADVANCED( COREAUDIO_LIBRARY COREFOUNDATION_LIBRARY ) + FIND_LIBRARY( FOUNDATION_LIBRARY Foundation ) + FIND_LIBRARY( SCRIPTINGBRIDGE_LIBRARY ScriptingBridge ) + MARK_AS_ADVANCED( COREAUDIO_LIBRARY COREFOUNDATION_LIBRARY FOUNDATION_LIBRARY SCRIPTINGBRIDGE_LIBRARY ) + + SET( libSources ${libSources} + infosystem/infoplugins/adium.mm + infosystem/infoplugins/adiumplugin.cpp ) + + SET( libHeaders ${libHeaders} + infosystem/infoplugins/adium.h + infosystem/infoplugins/adiumplugin.h ) SET( OS_SPECIFIC_LINK_LIBRARIES ${OS_SPECIFIC_LINK_LIBRARIES} @@ -391,6 +401,8 @@ IF( APPLE ) # System ${COREAUDIO_LIBRARY} ${COREFOUNDATION_LIBRARY} + ${FOUNDATION_LIBRARY} + ${SCRIPTINGBRIDGE_LIBRARY} ) ENDIF( APPLE ) diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 657c38c7a..6e4def041 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -24,10 +24,12 @@ #include "database/database.h" #include "database/databasecommand_logplayback.h" +#include "infosystem/infosystem.h" #include "network/servent.h" AudioEngine* AudioEngine::s_instance = 0; +static QString s_aeInfoIdentifier = QString( "AUDIOENGINE" ); AudioEngine* AudioEngine::instance() @@ -217,6 +219,15 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( m_currentTrack, DatabaseCommand_LogPlayback::Started ); Database::instance()->enqueue( QSharedPointer(cmd) ); + + Tomahawk::InfoSystem::InfoCriteriaHash trackInfo; + + trackInfo["title"] = m_currentTrack->track(); + trackInfo["artist"] = m_currentTrack->artist()->name(); + Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( + s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowPlaying, + QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) ); + } } diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index acb36d30e..bc910f403 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -18,6 +18,7 @@ #include +#include "infosystem/infosystemworker.h" #include "artist.h" #include "result.h" @@ -37,30 +38,15 @@ static void setStatus(const QString &status) using namespace Tomahawk::InfoSystem; -AdiumPlugin::AdiumPlugin(QObject *parent) +AdiumPlugin::AdiumPlugin( InfoSystemWorker* parent ) : InfoPlugin(parent) { /** No supported types since the plugin pushes info, doesn't get any */ qDebug() << Q_FUNC_INFO; - QSet< InfoType > supportedTypes; - InfoSystem *system = qobject_cast< InfoSystem* >(parent); - system->registerInfoTypes(this, supportedTypes); + QSet< InfoType > supportedGetTypes, supportedPushTypes; + supportedPushTypes << InfoNowPlaying; + parent->registerInfoTypes( this, supportedGetTypes, supportedPushTypes ); - /** Connect to audio state signals. - TODO: Move this into InfoSystem? There could end up being many plugins - connected to audio state signals. */ - - connect( system, SIGNAL( audioStarted( const Tomahawk::result_ptr& ) ), - SLOT( audioStarted( const Tomahawk::result_ptr& ) ) ); - connect( system, SIGNAL( audioFinished( const Tomahawk::result_ptr& ) ), - SLOT( audioFinished( const Tomahawk::result_ptr& ) ) ); - connect( system, SIGNAL( audioStopped() ), - SLOT( audioStopped() ) ); - connect( system, SIGNAL( audioPaused() ), - SLOT( audioPaused() ) ); - connect( system, SIGNAL( audioResumed( const Tomahawk::result_ptr& ) ), - SLOT( audioResumed( const Tomahawk::result_ptr& ) ) ); - } AdiumPlugin::~AdiumPlugin() @@ -69,7 +55,8 @@ AdiumPlugin::~AdiumPlugin() setStatus( "" ); } -void AdiumPlugin::getInfo(const QString &caller, const InfoType type, const QVariant& data, InfoCustomData customData) +void +AdiumPlugin::getInfo( const QString caller, const InfoType type, const QVariant data, InfoCustomData customData ) { switch (type) { @@ -81,19 +68,44 @@ void AdiumPlugin::getInfo(const QString &caller, const InfoType type, const QVar } } -/** Audio state slots */ - -void AdiumPlugin::audioStarted( const Tomahawk::result_ptr& track ) +void +AdiumPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input ) { qDebug() << Q_FUNC_INFO; + + switch ( type ) + { + case InfoNowPlaying: + audioStarted( input ); + break; + + default: + return; + } +} + +/** Audio state slots */ +void AdiumPlugin::audioStarted( const QVariant &input ) +//void AdiumPlugin::audioStarted( const Tomahawk::result_ptr& track ) +{ + qDebug() << Q_FUNC_INFO; + + if ( !input.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() ) + return; + + InfoCriteriaHash hash = input.value< Tomahawk::InfoSystem::InfoCriteriaHash >(); + if ( !hash.contains( "title" ) || !hash.contains( "artist" ) ) + return; + QString nowPlaying = ""; - nowPlaying.append( track->track() ); + nowPlaying.append( hash["title"] ); nowPlaying.append(" - "); - nowPlaying.append(track->artist()->name()); + nowPlaying.append( hash["artist"] ); setStatus( nowPlaying ); } -void AdiumPlugin::audioFinished( const Tomahawk::result_ptr& track ) +void +AdiumPlugin::audioFinished( const QVariant &input ) { //qDebug() << Q_FUNC_INFO; } @@ -112,10 +124,10 @@ void AdiumPlugin::audioPaused() setStatus( "Paused" ); } -void AdiumPlugin::audioResumed( const Tomahawk::result_ptr& track ) +void AdiumPlugin::audioResumed( const QVariant &input ) { qDebug() << Q_FUNC_INFO; // TODO: audio resumed, so push update status to Adium with playing track - this->audioStarted( track ); + audioStarted( input ); } diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.h b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h index 604432ab1..f67f2126f 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.h +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h @@ -22,6 +22,7 @@ #include "infosystem/infosystem.h" #include +#include namespace Tomahawk { @@ -32,17 +33,22 @@ class AdiumPlugin : public InfoPlugin Q_OBJECT public: - AdiumPlugin( QObject *parent ); + AdiumPlugin( InfoSystemWorker *parent ); virtual ~AdiumPlugin(); - void getInfo( const QString &caller, const InfoType type, const QVariant &data, InfoCustomData customData ); +protected slots: + void getInfo( const QString caller, const InfoType type, const QVariant data, InfoCustomData customData ); + void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input ); public slots: - void audioStarted( const Tomahawk::result_ptr& track ); - void audioFinished( const Tomahawk::result_ptr& track ); + void audioStarted( const QVariant &input ); + void audioFinished( const QVariant &input ); void audioStopped(); void audioPaused(); - void audioResumed( const Tomahawk::result_ptr& track ); + void audioResumed( const QVariant &input ); + + void namChangedSlot() {} // unused + void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ) {} // unused }; diff --git a/src/libtomahawk/infosystem/infosystem.cpp b/src/libtomahawk/infosystem/infosystem.cpp index e42edda5b..4dbddeee4 100644 --- a/src/libtomahawk/infosystem/infosystem.cpp +++ b/src/libtomahawk/infosystem/infosystem.cpp @@ -25,6 +25,7 @@ #include "infoplugins/echonestplugin.h" #include "infoplugins/musixmatchplugin.h" #include "infoplugins/lastfmplugin.h" +#include "infoplugins/adiumplugin.h" namespace Tomahawk { diff --git a/src/libtomahawk/infosystem/infosystem.h b/src/libtomahawk/infosystem/infosystem.h index f4fe24871..b03b4e2cd 100644 --- a/src/libtomahawk/infosystem/infosystem.h +++ b/src/libtomahawk/infosystem/infosystem.h @@ -92,7 +92,9 @@ enum InfoType { // as items are saved in cache, mark them here to not change the InfoSubmitNowPlaying = 46, InfoSubmitScrobble = 47, - InfoNoInfo = 48 + InfoNowPlaying = 48, + + InfoNoInfo = 49 }; typedef QMap< InfoType, QVariant > InfoMap; diff --git a/src/libtomahawk/infosystem/infosystemworker.cpp b/src/libtomahawk/infosystem/infosystemworker.cpp index 4b376a932..99a6e190e 100644 --- a/src/libtomahawk/infosystem/infosystemworker.cpp +++ b/src/libtomahawk/infosystem/infosystemworker.cpp @@ -26,6 +26,7 @@ #include "infoplugins/echonestplugin.h" #include "infoplugins/musixmatchplugin.h" #include "infoplugins/lastfmplugin.h" +#include "infoplugins/adiumplugin.h" #include "lastfm/NetworkAccessManager" @@ -61,6 +62,8 @@ void InfoSystemWorker::init() m_plugins.append( mmptr ); InfoPluginPtr lfmptr( new LastFmPlugin( this ) ); m_plugins.append( lfmptr ); + InfoPluginPtr admptr( new AdiumPlugin( this ) ); + m_plugins.append( admptr ); InfoSystemCache *cache = InfoSystem::instance()->getCache(); From 8cc0277cca31e8a458402b5e52b8e69535c7d02b Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Sat, 7 May 2011 12:25:17 -0700 Subject: [PATCH 03/53] Catch up to the InfoSystem. --- src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp | 10 +++------- src/libtomahawk/infosystem/infoplugins/adiumplugin.h | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index bc910f403..59a97c0a4 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -38,15 +38,11 @@ static void setStatus(const QString &status) using namespace Tomahawk::InfoSystem; -AdiumPlugin::AdiumPlugin( InfoSystemWorker* parent ) - : InfoPlugin(parent) +AdiumPlugin::AdiumPlugin() + : InfoPlugin() { - /** No supported types since the plugin pushes info, doesn't get any */ qDebug() << Q_FUNC_INFO; - QSet< InfoType > supportedGetTypes, supportedPushTypes; - supportedPushTypes << InfoNowPlaying; - parent->registerInfoTypes( this, supportedGetTypes, supportedPushTypes ); - + m_supportedPushTypes << InfoNowPlaying; } AdiumPlugin::~AdiumPlugin() diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.h b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h index f67f2126f..12ecdbe8b 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.h +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h @@ -33,7 +33,7 @@ class AdiumPlugin : public InfoPlugin Q_OBJECT public: - AdiumPlugin( InfoSystemWorker *parent ); + AdiumPlugin(); virtual ~AdiumPlugin(); protected slots: @@ -47,7 +47,7 @@ public slots: void audioPaused(); void audioResumed( const QVariant &input ); - void namChangedSlot() {} // unused + void namChangedSlot( QNetworkAccessManager *nam ) {} // unused void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ) {} // unused }; From f4b4a021eed7449ce7d2087583d22967badace47 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Sat, 7 May 2011 13:26:21 -0700 Subject: [PATCH 04/53] Add resumed, stopped, paused info. --- src/libtomahawk/audio/audioengine.cpp | 11 +++++++++++ .../infosystem/infoplugins/adiumplugin.cpp | 19 ++++++++++++++----- src/libtomahawk/infosystem/infosystem.h | 5 ++++- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 6e4def041..ee51230ae 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -91,6 +91,13 @@ AudioEngine::play() { m_mediaObject->play(); emit resumed(); + Tomahawk::InfoSystem::InfoCriteriaHash trackInfo; + + trackInfo["title"] = m_currentTrack->track(); + trackInfo["artist"] = m_currentTrack->artist()->name(); + Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( + s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowResumed, + QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) ); } else loadNextTrack(); @@ -104,6 +111,8 @@ AudioEngine::pause() m_mediaObject->pause(); emit paused(); + Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( + s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowPaused, QVariant() ); } @@ -117,6 +126,8 @@ AudioEngine::stop() setCurrentTrack( Tomahawk::result_ptr() ); emit stopped(); + Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( + s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowStopped, QVariant() ); } diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index 59a97c0a4..4a9da79ef 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -42,7 +42,7 @@ AdiumPlugin::AdiumPlugin() : InfoPlugin() { qDebug() << Q_FUNC_INFO; - m_supportedPushTypes << InfoNowPlaying; + m_supportedPushTypes << InfoNowPlaying << InfoNowPaused << InfoNowResumed << InfoNowStopped; } AdiumPlugin::~AdiumPlugin() @@ -68,15 +68,24 @@ void AdiumPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input ) { qDebug() << Q_FUNC_INFO; - + switch ( type ) { case InfoNowPlaying: - audioStarted( input ); - break; + audioStarted( input ); + break; + case InfoNowPaused: + audioPaused(); + break; + case InfoNowResumed: + audioResumed( input ); + break; + case InfoNowStopped: + audioStopped(); + break; default: - return; + return; } } diff --git a/src/libtomahawk/infosystem/infosystem.h b/src/libtomahawk/infosystem/infosystem.h index 86de07e6e..a484307b8 100644 --- a/src/libtomahawk/infosystem/infosystem.h +++ b/src/libtomahawk/infosystem/infosystem.h @@ -95,8 +95,11 @@ enum InfoType { // as items are saved in cache, mark them here to not change the InfoSubmitScrobble = 47, InfoNowPlaying = 48, + InfoNowPaused = 49, + InfoNowResumed = 50, + InfoNowStopped = 51, - InfoNoInfo = 49 + InfoNoInfo = 52 }; typedef QMap< InfoType, QVariant > InfoMap; From 0bac06b2c08e4cdfe505ccbdb46c04c4eb367fd9 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Sat, 7 May 2011 15:45:34 -0700 Subject: [PATCH 05/53] Add setting to enable/disable Adium now-playing (defaults to off, and only shows up on macs). --- .../infosystem/infoplugins/adiumplugin.cpp | 17 +++++++++++++ .../infosystem/infoplugins/adiumplugin.h | 5 ++++ src/libtomahawk/tomahawksettings.cpp | 13 ++++++++++ src/libtomahawk/tomahawksettings.h | 5 ++++ src/settingsdialog.cpp | 9 +++++++ src/stackedsettingsdialog.ui | 25 ++++++++++++++++++- 6 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index 4a9da79ef..bbd8d7cfb 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -21,6 +21,7 @@ #include "infosystem/infosystemworker.h" #include "artist.h" #include "result.h" +#include "tomahawksettings.h" #include "adiumplugin.h" #include "adium.h" @@ -43,6 +44,11 @@ AdiumPlugin::AdiumPlugin() { qDebug() << Q_FUNC_INFO; m_supportedPushTypes << InfoNowPlaying << InfoNowPaused << InfoNowResumed << InfoNowStopped; + + m_active = TomahawkSettings::instance()->nowPlayingEnabled(); + + connect( TomahawkSettings::instance(), SIGNAL( changed() ), + SLOT( settingsChanged() ), Qt::QueuedConnection ); } AdiumPlugin::~AdiumPlugin() @@ -51,6 +57,14 @@ AdiumPlugin::~AdiumPlugin() setStatus( "" ); } +void +AdiumPlugin::settingsChanged() +{ + m_active = TomahawkSettings::instance()->nowPlayingEnabled(); + if( !m_active ) + setStatus( "" ); +} + void AdiumPlugin::getInfo( const QString caller, const InfoType type, const QVariant data, InfoCustomData customData ) { @@ -68,6 +82,9 @@ void AdiumPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input ) { qDebug() << Q_FUNC_INFO; + + if( !m_active ) + return; switch ( type ) { diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.h b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h index 12ecdbe8b..8660ce3d8 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.h +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h @@ -41,6 +41,8 @@ protected slots: void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input ); public slots: + void settingsChanged(); + void audioStarted( const QVariant &input ); void audioFinished( const QVariant &input ); void audioStopped(); @@ -50,6 +52,9 @@ public slots: void namChangedSlot( QNetworkAccessManager *nam ) {} // unused void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ) {} // unused +private: + bool m_active; + }; diff --git a/src/libtomahawk/tomahawksettings.cpp b/src/libtomahawk/tomahawksettings.cpp index 62674e4f9..fd06d6821 100644 --- a/src/libtomahawk/tomahawksettings.cpp +++ b/src/libtomahawk/tomahawksettings.cpp @@ -661,3 +661,16 @@ TomahawkSettings::setEnabledScriptResolvers( const QStringList& resolvers ) { setValue( "script/loadedresolvers", resolvers ); } + +bool +TomahawkSettings::nowPlayingEnabled() const +{ + return value( "adium/enablenowplaying", false ).toBool(); +} + + +void +TomahawkSettings::setNowPlayingEnabled( bool enable ) +{ + setValue( "adium/enablenowplaying", enable ); +} diff --git a/src/libtomahawk/tomahawksettings.h b/src/libtomahawk/tomahawksettings.h index 366355bb4..310904228 100644 --- a/src/libtomahawk/tomahawksettings.h +++ b/src/libtomahawk/tomahawksettings.h @@ -156,6 +156,11 @@ public: QStringList enabledScriptResolvers() const; void setEnabledScriptResolvers( const QStringList& resolvers ); + // Now-Playing Settings + // For now, just Adium. Soon, the world! + bool nowPlayingEnabled() const; // false by default + void setNowPlayingEnabled( bool enable ); + signals: void changed(); diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index fbd9def16..0249b3534 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -104,6 +104,13 @@ SettingsDialog::SettingsDialog( QWidget *parent ) ui->lineEditMusicPath_2->setText( s->scannerPaths().first() ); ui->checkBoxWatchForChanges->setChecked( s->watchForChanges() ); + // NOW PLAYING + #ifdef Q_WS_MAC + ui->checkBoxEnableAdium->setChecked( s->nowPlayingEnabled() ); + #else + ui->checkBoxEnableAdium->hide(); + #endif + // LAST FM ui->checkBoxEnableLastfm->setChecked( s->scrobblingEnabled() ); ui->lineEditLastfmUsername->setText( s->lastFmUsername() ); @@ -149,6 +156,8 @@ SettingsDialog::~SettingsDialog() s->setScannerPaths( QStringList( ui->lineEditMusicPath_2->text() ) ); s->setWatchForChanges( ui->checkBoxWatchForChanges->isChecked() ); + s->setNowPlayingEnabled( ui->checkBoxEnableAdium->isChecked() ); + s->setScrobblingEnabled( ui->checkBoxEnableLastfm->isChecked() ); s->setLastFmUsername( ui->lineEditLastfmUsername->text() ); s->setLastFmPassword( ui->lineEditLastfmPassword->text() ); diff --git a/src/stackedsettingsdialog.ui b/src/stackedsettingsdialog.ui index 91abc1c48..fce3a1fb8 100644 --- a/src/stackedsettingsdialog.ui +++ b/src/stackedsettingsdialog.ui @@ -100,7 +100,7 @@ - 0 + 1 @@ -253,6 +253,29 @@ + + + + Now Playing Information + + + + + + Applications to update with currently playing track: + + + + + + + Adium + + + + + + From 69a01c252a48e9ff3357b165ac3ffa641caca0e9 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Sat, 7 May 2011 15:50:48 -0700 Subject: [PATCH 06/53] Add a few more guards for OS X. --- src/libtomahawk/infosystem/infosystemworker.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libtomahawk/infosystem/infosystemworker.cpp b/src/libtomahawk/infosystem/infosystemworker.cpp index 767e7347b..b64058056 100644 --- a/src/libtomahawk/infosystem/infosystemworker.cpp +++ b/src/libtomahawk/infosystem/infosystemworker.cpp @@ -26,7 +26,9 @@ #include "infoplugins/echonestplugin.h" #include "infoplugins/musixmatchplugin.h" #include "infoplugins/lastfmplugin.h" +#ifdef Q_WS_MAC #include "infoplugins/adiumplugin.h" +#endif #include "lastfm/NetworkAccessManager" @@ -66,9 +68,11 @@ InfoSystemWorker::init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache> cac InfoPluginPtr lfmptr( new LastFmPlugin() ); m_plugins.append( lfmptr ); registerInfoTypes( lfmptr, lfmptr.data()->supportedGetTypes(), lfmptr.data()->supportedPushTypes() ); + #ifdef Q_WS_MAC InfoPluginPtr admptr( new AdiumPlugin() ); m_plugins.append( admptr ); registerInfoTypes( admptr, admptr.data()->supportedGetTypes(), admptr.data()->supportedPushTypes() ); + #endif Q_FOREACH( InfoPluginPtr plugin, m_plugins ) { From df996769f8e59926784bb735b56d98d7b6b018d8 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Sat, 7 May 2011 15:58:16 -0700 Subject: [PATCH 07/53] Make layout a bit more aligned. --- src/stackedsettingsdialog.ui | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/stackedsettingsdialog.ui b/src/stackedsettingsdialog.ui index fce3a1fb8..56c4ef3a5 100644 --- a/src/stackedsettingsdialog.ui +++ b/src/stackedsettingsdialog.ui @@ -258,7 +258,10 @@ Now Playing Information - + + + 2 + From 5cd9e49629b920d0d48c884bb2a827ef75a1f2f7 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 31 May 2011 18:17:46 -0400 Subject: [PATCH 08/53] Add support for SPMediaKeyTap. This lets tomahawk stop iTunes from opening when a user presses one of the media keys. Thanks to the Clementine project and tyler.s.rhodes@gmail.com for much of the code in this patch. --- src/CMakeLists.osx.txt | 2 + src/CMakeLists.txt | 2 + src/mac/macdelegate.h | 40 +++++++++++++++ src/mac/tomahawkapp_mac.mm | 95 +++++++++++++++++++++++++---------- src/tomahawkapp_macdelegate.h | 43 ---------------- thirdparty/CMakeLists.txt | 3 ++ 6 files changed, 116 insertions(+), 69 deletions(-) create mode 100644 src/mac/macdelegate.h delete mode 100644 src/tomahawkapp_macdelegate.h diff --git a/src/CMakeLists.osx.txt b/src/CMakeLists.osx.txt index f1a5b2d20..f88939b80 100644 --- a/src/CMakeLists.osx.txt +++ b/src/CMakeLists.osx.txt @@ -5,6 +5,8 @@ SET( OS_SPECIFIC_LINK_LIBRARIES ${COREAUDIO_LIBRARY} ${COREFOUNDATION_LIBRARY} + SPMediaKeyTap + /System/Library/Frameworks/AppKit.framework /System/Library/Frameworks/Carbon.framework /System/Library/Frameworks/DiskArbitration.framework diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d292c954..efedc8706 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -160,6 +160,8 @@ IF( UNIX ) ENDIF( UNIX ) IF( APPLE ) + INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/thirdparty/SPMediaKeyTap ) + SET( tomahawkHeaders ${tomahawkHeaders} mac/tomahawkapp_mac.h mac/macshortcuthandler.h ) SET( tomahawkSources ${tomahawkSources} mac/tomahawkapp_mac.mm mac/macshortcuthandler.cpp ) diff --git a/src/mac/macdelegate.h b/src/mac/macdelegate.h new file mode 100644 index 000000000..7d684d39e --- /dev/null +++ b/src/mac/macdelegate.h @@ -0,0 +1,40 @@ +#ifndef MACDELEGATE_H +#define MACDELEGATE_H + +// This file inspired by clementine's macdelegate.h + +#import + +#include "SPMediaKeyTap.h" + +namespace Tomahawk { + class MacShortcutHandler; + class PlatformInterface; +} + +#ifdef SNOW_LEOPARD +@interface AppDelegate :NSObject { +#else +@interface AppDelegate :NSObject { +#endif + Tomahawk::PlatformInterface* application_handler_; + NSMenu* dock_menu_; + SPMediaKeyTap* key_tap_; + Tomahawk::MacShortcutHandler* shortcut_handler_; +} + +- (id) initWithHandler: (Tomahawk::PlatformInterface*)handler; +// NSApplicationDelegate +- (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag; +- (NSMenu*) applicationDockMenu: (NSApplication*)sender; +- (void) setDockMenu: (NSMenu*)menu; +- (Tomahawk::MacShortcutHandler*) shortcutHandler; +- (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)backend; +- (void)applicationDidFinishLaunching:(NSNotification*)aNotification; +- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender; +- (void) mediaKeyTap: (SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event; +@end + + + +#endif // MACDELEGATE_H diff --git a/src/mac/tomahawkapp_mac.mm b/src/mac/tomahawkapp_mac.mm index 44660e742..144a33853 100644 --- a/src/mac/tomahawkapp_mac.mm +++ b/src/mac/tomahawkapp_mac.mm @@ -17,7 +17,7 @@ */ #include "tomahawkapp_mac.h" -#include "tomahawkapp_macdelegate.h" +#include "macdelegate.h" #include "macshortcuthandler.h" #include @@ -42,6 +42,7 @@ // See: http://www.rogueamoeba.com/utm/2007/09/29/apple-keyboard-media-key-event-handling/ @interface MacApplication :NSApplication { + AppDelegate* delegate_; Tomahawk::MacShortcutHandler* shortcut_handler_; Tomahawk::PlatformInterface* application_handler_; } @@ -51,7 +52,6 @@ - (Tomahawk::PlatformInterface*) application_handler; - (void) setApplicationHandler: (Tomahawk::PlatformInterface*)handler; -- (void) mediaKeyEvent: (int)key state: (BOOL)state repeat: (BOOL)repeat; @end @@ -59,14 +59,22 @@ - (id) init { if ((self = [super init])) { - application_handler_ = nil; -// dock_menu_ = nil; + application_handler_ = nil; + shortcut_handler_ = nil; + //dock_menu_ = nil; } return self; } - (id) initWithHandler: (Tomahawk::PlatformInterface*)handler { application_handler_ = handler; + + // Register defaults for the whitelist of apps that want to use media keys + [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys: + [SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers], @"SPApplicationsNeedingMediaKeys", + nil]]; + + return self; } @@ -76,7 +84,7 @@ } return YES; } -/* + - (void) setDockMenu: (NSMenu*)menu { dock_menu_ = menu; } @@ -84,7 +92,45 @@ - (NSMenu*) applicationDockMenu: (NSApplication*)sender { return dock_menu_; } -*/ + + +- (Tomahawk::MacShortcutHandler*) shortcutHandler { + return shortcut_handler_; +} + +- (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)handler { + qDebug() << "Setting shortcut handler of MacApp"; + // should be the same as MacApplication's + shortcut_handler_ = handler; +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + key_tap_ = [[SPMediaKeyTap alloc] initWithDelegate:self]; + if([SPMediaKeyTap usesGlobalMediaKeyTap]) + [key_tap_ startWatchingMediaKeys]; + else + qWarning()<<"Media key monitoring disabled"; + +} + +- (void) mediaKeyTap: (SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event { + NSAssert([event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys, @"Unexpected NSEvent in mediaKeyTap:receivedMediaKeyEvent:"); + + int key_code = (([event data1] & 0xFFFF0000) >> 16); + int key_flags = ([event data1] & 0x0000FFFF); + BOOL key_is_pressed = (((key_flags & 0xFF00) >> 8)) == 0xA; + // not used. keep just in case + // int key_repeat = (key_flags & 0x1); + + if (!shortcut_handler_) { + qWarning() << "No shortcut handler when we get a media key event..."; + return; + } + if (key_is_pressed) { + shortcut_handler_->macMediaKeyPressed(key_code); + } +} + - (BOOL) application: (NSApplication*)app openFile:(NSString*)filename { qDebug() << "Wants to open:" << [filename UTF8String]; @@ -94,6 +140,11 @@ return NO; } + +- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*) sender { + return NSTerminateNow; +} + @end @implementation MacApplication @@ -127,7 +178,7 @@ } - (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)handler { - qDebug() << "Setting shortcut handler of MacAPp"; + // should be the same as AppDelegate's shortcut_handler_ = handler; } @@ -136,30 +187,22 @@ } - (void) setApplicationHandler: (Tomahawk::PlatformInterface*)handler { - AppDelegate* delegate = [[AppDelegate alloc] initWithHandler:handler]; - [self setDelegate:delegate]; + delegate_ = [[AppDelegate alloc] initWithHandler:handler]; + // App-shortcut-handler set before delegate is set. + // this makes sure the delegate's shortcut_handler is set + [delegate_ setShortcutHandler:shortcut_handler_]; + [self setDelegate:delegate_]; } -(void) sendEvent: (NSEvent*)event { - if ([event type] == NSSystemDefined && [event subtype] == 8) { - int keycode = (([event data1] & 0xFFFF0000) >> 16); - int keyflags = ([event data1] & 0x0000FFFF); - int keystate = (((keyflags & 0xFF00) >> 8)) == 0xA; - int keyrepeat = (keyflags & 0x1); + // If event tap is not installed, handle events that reach the app instead + BOOL shouldHandleMediaKeyEventLocally = ![SPMediaKeyTap usesGlobalMediaKeyTap]; - [self mediaKeyEvent: keycode state: keystate repeat: keyrepeat]; - } + if(shouldHandleMediaKeyEventLocally && [event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys) { + [(id)[self delegate] mediaKeyTap: nil receivedMediaKeyEvent: event]; + } - [super sendEvent: event]; -} - --(void) mediaKeyEvent: (int)key state: (BOOL)state repeat: (BOOL)repeat { - if (!shortcut_handler_) { - return; - } - if (state == 0) { - shortcut_handler_->macMediaKeyPressed(key); - } + [super sendEvent: event]; } @end diff --git a/src/tomahawkapp_macdelegate.h b/src/tomahawkapp_macdelegate.h deleted file mode 100644 index 01ef7a401..000000000 --- a/src/tomahawkapp_macdelegate.h +++ /dev/null @@ -1,43 +0,0 @@ -/* === 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 . - */ - -#import - -#include "config.h" - -// this file copied and inspired by mac_startup.* in clementine player, -// copyright David Sansome 2010 -namespace Tomahawk { - class PlatformInterface; -} - -#ifdef SNOW_LEOPARD -@interface AppDelegate : NSObject { -#else -@interface AppDelegate : NSObject { -#endif - Tomahawk::PlatformInterface* application_handler_; - //NSMenu* dock_menu_; -} - -- (id) initWithHandler: (Tomahawk::PlatformInterface*)handler; -// NSApplicationDelegate -- (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag; -//- (NSMenu*) applicationDockMenu: (NSApplication*)sender; -//- (void) setDockMenu: (NSMenu*)menu; -@end diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 04dc95eb4..096668ed2 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,2 +1,5 @@ ADD_SUBDIRECTORY( qxt ) ADD_SUBDIRECTORY( liblastfm2 ) +IF( APPLE ) + ADD_SUBDIRECTORY( SPMediaKeyTap ) +ENDIF() From 7176b7f0a930150a3c9154a13339541798a5bf45 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 31 May 2011 18:20:29 -0400 Subject: [PATCH 09/53] Add the SPMediaKeyTap thirdparty lib. --- thirdparty/SPMediaKeyTap/CMakeLists.txt | 13 + thirdparty/SPMediaKeyTap/LICENSE | 8 + thirdparty/SPMediaKeyTap/README.md | 12 + .../SPInvocationGrabbing/.svn/all-wcprops | 35 ++ .../SPInvocationGrabbing/.svn/entries | 198 ++++++++++++ .../NSObject+SPInvocationGrabbing.h.svn-base | 30 ++ .../NSObject+SPInvocationGrabbing.m.svn-base | 128 ++++++++ .../.svn/text-base/gistfile3.m.svn-base | 28 ++ .../.svn/text-base/gistfile4.m.svn-base | 12 + .../.svn/text-base/main.m.svn-base | 38 +++ .../NSObject+SPInvocationGrabbing.h | 30 ++ .../NSObject+SPInvocationGrabbing.m | 128 ++++++++ .../SPInvocationGrabbing/gistfile3.m | 28 ++ .../SPInvocationGrabbing/gistfile4.m | 12 + .../SPMediaKeyTap/SPInvocationGrabbing/main.m | 38 +++ thirdparty/SPMediaKeyTap/SPMediaKeyTap.h | 34 ++ thirdparty/SPMediaKeyTap/SPMediaKeyTap.m | 300 ++++++++++++++++++ .../SPMediaKeyTap/SPMediaKeyTapDelegate.m | 25 ++ 18 files changed, 1097 insertions(+) create mode 100644 thirdparty/SPMediaKeyTap/CMakeLists.txt create mode 100644 thirdparty/SPMediaKeyTap/LICENSE create mode 100644 thirdparty/SPMediaKeyTap/README.md create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/all-wcprops create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/entries create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.h.svn-base create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.m.svn-base create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile3.m.svn-base create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile4.m.svn-base create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/main.m.svn-base create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile3.m create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile4.m create mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/main.m create mode 100644 thirdparty/SPMediaKeyTap/SPMediaKeyTap.h create mode 100644 thirdparty/SPMediaKeyTap/SPMediaKeyTap.m create mode 100644 thirdparty/SPMediaKeyTap/SPMediaKeyTapDelegate.m diff --git a/thirdparty/SPMediaKeyTap/CMakeLists.txt b/thirdparty/SPMediaKeyTap/CMakeLists.txt new file mode 100644 index 000000000..9f51aa5bb --- /dev/null +++ b/thirdparty/SPMediaKeyTap/CMakeLists.txt @@ -0,0 +1,13 @@ +set(SPMEDIAKEY-SOURCES + SPMediaKeyTap.m + SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m +) + +set(SPMEDIAKEY-HEADERS + SPMediaKeyTap.h + SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h +) + +ADD_LIBRARY(SPMediaKeyTap STATIC + ${SPMEDIAKEY-SOURCES} +) diff --git a/thirdparty/SPMediaKeyTap/LICENSE b/thirdparty/SPMediaKeyTap/LICENSE new file mode 100644 index 000000000..a43e4122e --- /dev/null +++ b/thirdparty/SPMediaKeyTap/LICENSE @@ -0,0 +1,8 @@ +Copyright (c) 2011, Joachim Bengtsson +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Neither the name of the organization nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/thirdparty/SPMediaKeyTap/README.md b/thirdparty/SPMediaKeyTap/README.md new file mode 100644 index 000000000..8027d2452 --- /dev/null +++ b/thirdparty/SPMediaKeyTap/README.md @@ -0,0 +1,12 @@ +SPMediaKeyTap +============= + +`SPMediaKeyTap` abstracts a `CGEventHook` and other nastiness in order to give you a relatively simple API to receive media key events (prev/next/playpause, on F7 to F9 on modern MacBook Pros) exclusively, without them reaching other applications like iTunes. `SPMediaKeyTap` is clever enough to resign its exclusive lock on media keys by looking for which application was active most recently: if that application is in `SPMediaKeyTap`'s whitelist, it will resign the keys. This is similar to the behavior of Apple's applications collaborating on media key handling exclusivity, but unfortunately, Apple are not exposing any APIs allowing third-parties to join in on this collaboration. + +For now, the whitelist is just a hardcoded array in `+[SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers]`. If your app starts using `SPMediaKeyTap`, please [mail me](mailto:nevyn@spotify.com) your bundle ID, and I'll include it in the canonical repository. This is a bad solution; a better solution would be to use distributed notifications to collaborate in creating this whitelist at runtime. Hopefully someone'll have the time and energy to write this soon. + +In `Example/SPMediaKeyTapExampleAppDelegate.m` is an example of both how you use `SPMediaKeyTap`, and how you handle the semi-private `NSEvent` subtypes involved in media keys, including on how to fall back to non-event tap handling of these events. + +`SPMediaKeyTap` and other `CGEventHook`s on the event type `NSSystemDefined` is known to interfere with each other and applications doing weird stuff with mouse input, because mouse clicks are also part of the `NSSystemDefined` category. The single issue we have had reported here at Spotify is Adobe Fireworks, in which item selection stops working with `SPMediaKeyTap` is active. + +`SPMediaKeyTap` requires 10.5 to work, and disables itself on 10.4. \ No newline at end of file diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/all-wcprops b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/all-wcprops new file mode 100644 index 000000000..657122656 --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/all-wcprops @@ -0,0 +1,35 @@ +K 25 +svn:wc:ra_dav:version-url +V 68 +/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing +END +main.m +K 25 +svn:wc:ra_dav:version-url +V 75 +/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing/main.m +END +NSObject+SPInvocationGrabbing.h +K 25 +svn:wc:ra_dav:version-url +V 100 +/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h +END +gistfile3.m +K 25 +svn:wc:ra_dav:version-url +V 80 +/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile3.m +END +gistfile4.m +K 25 +svn:wc:ra_dav:version-url +V 80 +/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile4.m +END +NSObject+SPInvocationGrabbing.m +K 25 +svn:wc:ra_dav:version-url +V 100 +/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m +END diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/entries b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/entries new file mode 100644 index 000000000..83ab274af --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/entries @@ -0,0 +1,198 @@ +10 + +dir +3354 +http://clementine-player.googlecode.com/svn/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing +http://clementine-player.googlecode.com/svn + + + +2011-05-30T10:09:34.688096Z +3341 +john.maguire + + + + + + + + + + + + + + +94c5599e-fc6c-11de-b061-8119ef04aefe + +main.m +file + + + + +2011-05-30T19:32:29.000000Z +64cedb4901f14b8f82160d41834812c7 +2011-05-30T10:09:34.688096Z +3341 +john.maguire + + + + + + + + + + + + + + + + + + + + + +778 + +NSObject+SPInvocationGrabbing.h +file + + + + +2011-05-30T19:32:29.000000Z +21417129fd15adb3e8e88f53c96a5249 +2011-05-30T10:09:34.688096Z +3341 +john.maguire + + + + + + + + + + + + + + + + + + + + + +841 + +gistfile3.m +file + + + + +2011-05-30T19:32:29.000000Z +1794e4fc655ea831def78ad9b3b22f5d +2011-05-30T10:09:34.688096Z +3341 +john.maguire + + + + + + + + + + + + + + + + + + + + + +1080 + +gistfile4.m +file + + + + +2011-05-30T19:32:29.000000Z +4a243c33e49a1d8b7212def259a1873a +2011-05-30T10:09:34.688096Z +3341 +john.maguire + + + + + + + + + + + + + + + + + + + + + +385 + +NSObject+SPInvocationGrabbing.m +file + + + + +2011-05-30T19:32:29.000000Z +52da2f8cede4bf66b97df4df3a002086 +2011-05-30T10:09:34.688096Z +3341 +john.maguire + + + + + + + + + + + + + + + + + + + + + +2915 + diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.h.svn-base b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.h.svn-base new file mode 100644 index 000000000..d30233daf --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.h.svn-base @@ -0,0 +1,30 @@ +#import + +@interface SPInvocationGrabber : NSObject { + id _object; + NSInvocation *_invocation; + int frameCount; + char **frameStrings; + BOOL backgroundAfterForward; + BOOL onMainAfterForward; + BOOL waitUntilDone; +} +-(id)initWithObject:(id)obj; +-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack; +@property (readonly, retain, nonatomic) id object; +@property (readonly, retain, nonatomic) NSInvocation *invocation; +@property BOOL backgroundAfterForward; +@property BOOL onMainAfterForward; +@property BOOL waitUntilDone; +-(void)invoke; // will release object and invocation +-(void)printBacktrace; +-(void)saveBacktrace; +@end + +@interface NSObject (SPInvocationGrabbing) +-(id)grab; +-(id)invokeAfter:(NSTimeInterval)delta; +-(id)nextRunloop; +-(id)inBackground; +-(id)onMainAsync:(BOOL)async; +@end diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.m.svn-base b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.m.svn-base new file mode 100644 index 000000000..8ba4adb8f --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.m.svn-base @@ -0,0 +1,128 @@ +#import "NSObject+SPInvocationGrabbing.h" +#import + +#pragma mark Invocation grabbing +@interface SPInvocationGrabber () +@property (readwrite, retain, nonatomic) id object; +@property (readwrite, retain, nonatomic) NSInvocation *invocation; + +@end + +@implementation SPInvocationGrabber +- (id)initWithObject:(id)obj; +{ + return [self initWithObject:obj stacktraceSaving:YES]; +} + +-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack; +{ + self.object = obj; + + if(saveStack) + [self saveBacktrace]; + + return self; +} +-(void)dealloc; +{ + free(frameStrings); + self.object = nil; + self.invocation = nil; + [super dealloc]; +} +@synthesize invocation = _invocation, object = _object; + +@synthesize backgroundAfterForward, onMainAfterForward, waitUntilDone; +- (void)runInBackground; +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + @try { + [self invoke]; + } + @finally { + [pool drain]; + } +} + + +- (void)forwardInvocation:(NSInvocation *)anInvocation { + [anInvocation retainArguments]; + anInvocation.target = _object; + self.invocation = anInvocation; + + if(backgroundAfterForward) + [NSThread detachNewThreadSelector:@selector(runInBackground) toTarget:self withObject:nil]; + else if(onMainAfterForward) + [self performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:waitUntilDone]; +} +- (NSMethodSignature *)methodSignatureForSelector:(SEL)inSelector { + NSMethodSignature *signature = [super methodSignatureForSelector:inSelector]; + if (signature == NULL) + signature = [_object methodSignatureForSelector:inSelector]; + + return signature; +} + +- (void)invoke; +{ + + @try { + [_invocation invoke]; + } + @catch (NSException * e) { + NSLog(@"SPInvocationGrabber's target raised %@:\n\t%@\nInvocation was originally scheduled at:", e.name, e); + [self printBacktrace]; + printf("\n"); + [e raise]; + } + + self.invocation = nil; + self.object = nil; +} + +-(void)saveBacktrace; +{ + void *backtraceFrames[128]; + frameCount = backtrace(&backtraceFrames[0], 128); + frameStrings = backtrace_symbols(&backtraceFrames[0], frameCount); +} +-(void)printBacktrace; +{ + int x; + for(x = 3; x < frameCount; x++) { + if(frameStrings[x] == NULL) { break; } + printf("%s\n", frameStrings[x]); + } +} +@end + +@implementation NSObject (SPInvocationGrabbing) +-(id)grab; +{ + return [[[SPInvocationGrabber alloc] initWithObject:self] autorelease]; +} +-(id)invokeAfter:(NSTimeInterval)delta; +{ + id grabber = [self grab]; + [NSTimer scheduledTimerWithTimeInterval:delta target:grabber selector:@selector(invoke) userInfo:nil repeats:NO]; + return grabber; +} +- (id)nextRunloop; +{ + return [self invokeAfter:0]; +} +-(id)inBackground; +{ + SPInvocationGrabber *grabber = [self grab]; + grabber.backgroundAfterForward = YES; + return grabber; +} +-(id)onMainAsync:(BOOL)async; +{ + SPInvocationGrabber *grabber = [self grab]; + grabber.onMainAfterForward = YES; + grabber.waitUntilDone = !async; + return grabber; +} + +@end diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile3.m.svn-base b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile3.m.svn-base new file mode 100644 index 000000000..712293780 --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile3.m.svn-base @@ -0,0 +1,28 @@ +// A ++(UIView*)flashAt:(CGRect)r in:(UIView*)parent color:(UIColor*)color; +{ + float duration = 0.5; + UIView *flash = [[[UIView alloc] initWithFrame:r] autorelease]; + flash.backgroundColor = color; + [parent addSubview:flash]; + [[flash invokeAfter:duration+0.1] removeFromSuperview]; + + [UIView beginAnimations:@"SPFlash" context:NULL]; + [UIView setAnimationDuration:duration]; + flash.alpha = 0.0; + [UIView commitAnimations]; + return flash; +} + +// B +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + // Force the animation to happen by calling this method again after a small + // delay - see http://blog.instapaper.com/post/53568356 + [[self nextRunloop] delayedTableViewDidSelectRowAtIndexPath: indexPath]; +} + +// C +[[tableView invokeAfter:0.15] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone]; +[[tableView invokeAfter:0.30] deselectRowAtIndexPath:indexPath animated:YES]; +[[tableView invokeAfter:0.45] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone]; diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile4.m.svn-base b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile4.m.svn-base new file mode 100644 index 000000000..8255abab0 --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile4.m.svn-base @@ -0,0 +1,12 @@ +@interface MyClass : NSObject +-(BOOL)areTheNewViewersGoneYet:(Duck*)duck; +@end +... +MyClass *myInstance = [[MyClass alloc] init]; +id invocationGrabber = [[[SPInvocationGrabber alloc] initWithTarget:myInstance] autorelease]; + + +[invocationGrabber areTheNewViewersGoneYet:[Duck yellowDuck]]; // line 9 + + +NSInvocation *invocationForAreTheNewViewersGoneYet = [invocationGrabber invocation]; diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/main.m.svn-base b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/main.m.svn-base new file mode 100644 index 000000000..a6ce17f39 --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/main.m.svn-base @@ -0,0 +1,38 @@ +#import +#import "NSObject+SPInvocationGrabbing.h" + +@interface Foo : NSObject { + int a; +} +-(void)startIt; +-(void)theBackgroundStuff; +-(void)theForegroundStuff; +@end + +@implementation Foo +-(void)startIt; +{ + NSLog(@"Starting out on the main thread..."); + a = 3; + [[self inBackground] theBackgroundStuff]; +} +-(void)theBackgroundStuff; +{ + NSLog(@"Woah, this is a background thread!"); + a += 6; + [[self onMainAsync:YES] theForegroundStuff]; +} +-(void)theForegroundStuff; +{ + NSLog(@"Hey presto: %d", a); +} +@end + +int main() { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + Foo *foo = [Foo new]; + [foo startIt]; + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; + [pool release]; + return 0; +} \ No newline at end of file diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h new file mode 100644 index 000000000..d30233daf --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h @@ -0,0 +1,30 @@ +#import + +@interface SPInvocationGrabber : NSObject { + id _object; + NSInvocation *_invocation; + int frameCount; + char **frameStrings; + BOOL backgroundAfterForward; + BOOL onMainAfterForward; + BOOL waitUntilDone; +} +-(id)initWithObject:(id)obj; +-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack; +@property (readonly, retain, nonatomic) id object; +@property (readonly, retain, nonatomic) NSInvocation *invocation; +@property BOOL backgroundAfterForward; +@property BOOL onMainAfterForward; +@property BOOL waitUntilDone; +-(void)invoke; // will release object and invocation +-(void)printBacktrace; +-(void)saveBacktrace; +@end + +@interface NSObject (SPInvocationGrabbing) +-(id)grab; +-(id)invokeAfter:(NSTimeInterval)delta; +-(id)nextRunloop; +-(id)inBackground; +-(id)onMainAsync:(BOOL)async; +@end diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m new file mode 100644 index 000000000..8ba4adb8f --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m @@ -0,0 +1,128 @@ +#import "NSObject+SPInvocationGrabbing.h" +#import + +#pragma mark Invocation grabbing +@interface SPInvocationGrabber () +@property (readwrite, retain, nonatomic) id object; +@property (readwrite, retain, nonatomic) NSInvocation *invocation; + +@end + +@implementation SPInvocationGrabber +- (id)initWithObject:(id)obj; +{ + return [self initWithObject:obj stacktraceSaving:YES]; +} + +-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack; +{ + self.object = obj; + + if(saveStack) + [self saveBacktrace]; + + return self; +} +-(void)dealloc; +{ + free(frameStrings); + self.object = nil; + self.invocation = nil; + [super dealloc]; +} +@synthesize invocation = _invocation, object = _object; + +@synthesize backgroundAfterForward, onMainAfterForward, waitUntilDone; +- (void)runInBackground; +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + @try { + [self invoke]; + } + @finally { + [pool drain]; + } +} + + +- (void)forwardInvocation:(NSInvocation *)anInvocation { + [anInvocation retainArguments]; + anInvocation.target = _object; + self.invocation = anInvocation; + + if(backgroundAfterForward) + [NSThread detachNewThreadSelector:@selector(runInBackground) toTarget:self withObject:nil]; + else if(onMainAfterForward) + [self performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:waitUntilDone]; +} +- (NSMethodSignature *)methodSignatureForSelector:(SEL)inSelector { + NSMethodSignature *signature = [super methodSignatureForSelector:inSelector]; + if (signature == NULL) + signature = [_object methodSignatureForSelector:inSelector]; + + return signature; +} + +- (void)invoke; +{ + + @try { + [_invocation invoke]; + } + @catch (NSException * e) { + NSLog(@"SPInvocationGrabber's target raised %@:\n\t%@\nInvocation was originally scheduled at:", e.name, e); + [self printBacktrace]; + printf("\n"); + [e raise]; + } + + self.invocation = nil; + self.object = nil; +} + +-(void)saveBacktrace; +{ + void *backtraceFrames[128]; + frameCount = backtrace(&backtraceFrames[0], 128); + frameStrings = backtrace_symbols(&backtraceFrames[0], frameCount); +} +-(void)printBacktrace; +{ + int x; + for(x = 3; x < frameCount; x++) { + if(frameStrings[x] == NULL) { break; } + printf("%s\n", frameStrings[x]); + } +} +@end + +@implementation NSObject (SPInvocationGrabbing) +-(id)grab; +{ + return [[[SPInvocationGrabber alloc] initWithObject:self] autorelease]; +} +-(id)invokeAfter:(NSTimeInterval)delta; +{ + id grabber = [self grab]; + [NSTimer scheduledTimerWithTimeInterval:delta target:grabber selector:@selector(invoke) userInfo:nil repeats:NO]; + return grabber; +} +- (id)nextRunloop; +{ + return [self invokeAfter:0]; +} +-(id)inBackground; +{ + SPInvocationGrabber *grabber = [self grab]; + grabber.backgroundAfterForward = YES; + return grabber; +} +-(id)onMainAsync:(BOOL)async; +{ + SPInvocationGrabber *grabber = [self grab]; + grabber.onMainAfterForward = YES; + grabber.waitUntilDone = !async; + return grabber; +} + +@end diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile3.m b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile3.m new file mode 100644 index 000000000..712293780 --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile3.m @@ -0,0 +1,28 @@ +// A ++(UIView*)flashAt:(CGRect)r in:(UIView*)parent color:(UIColor*)color; +{ + float duration = 0.5; + UIView *flash = [[[UIView alloc] initWithFrame:r] autorelease]; + flash.backgroundColor = color; + [parent addSubview:flash]; + [[flash invokeAfter:duration+0.1] removeFromSuperview]; + + [UIView beginAnimations:@"SPFlash" context:NULL]; + [UIView setAnimationDuration:duration]; + flash.alpha = 0.0; + [UIView commitAnimations]; + return flash; +} + +// B +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + // Force the animation to happen by calling this method again after a small + // delay - see http://blog.instapaper.com/post/53568356 + [[self nextRunloop] delayedTableViewDidSelectRowAtIndexPath: indexPath]; +} + +// C +[[tableView invokeAfter:0.15] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone]; +[[tableView invokeAfter:0.30] deselectRowAtIndexPath:indexPath animated:YES]; +[[tableView invokeAfter:0.45] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone]; diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile4.m b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile4.m new file mode 100644 index 000000000..8255abab0 --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile4.m @@ -0,0 +1,12 @@ +@interface MyClass : NSObject +-(BOOL)areTheNewViewersGoneYet:(Duck*)duck; +@end +... +MyClass *myInstance = [[MyClass alloc] init]; +id invocationGrabber = [[[SPInvocationGrabber alloc] initWithTarget:myInstance] autorelease]; + + +[invocationGrabber areTheNewViewersGoneYet:[Duck yellowDuck]]; // line 9 + + +NSInvocation *invocationForAreTheNewViewersGoneYet = [invocationGrabber invocation]; diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/main.m b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/main.m new file mode 100644 index 000000000..a6ce17f39 --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/main.m @@ -0,0 +1,38 @@ +#import +#import "NSObject+SPInvocationGrabbing.h" + +@interface Foo : NSObject { + int a; +} +-(void)startIt; +-(void)theBackgroundStuff; +-(void)theForegroundStuff; +@end + +@implementation Foo +-(void)startIt; +{ + NSLog(@"Starting out on the main thread..."); + a = 3; + [[self inBackground] theBackgroundStuff]; +} +-(void)theBackgroundStuff; +{ + NSLog(@"Woah, this is a background thread!"); + a += 6; + [[self onMainAsync:YES] theForegroundStuff]; +} +-(void)theForegroundStuff; +{ + NSLog(@"Hey presto: %d", a); +} +@end + +int main() { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + Foo *foo = [Foo new]; + [foo startIt]; + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; + [pool release]; + return 0; +} \ No newline at end of file diff --git a/thirdparty/SPMediaKeyTap/SPMediaKeyTap.h b/thirdparty/SPMediaKeyTap/SPMediaKeyTap.h new file mode 100644 index 000000000..f33ad7040 --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPMediaKeyTap.h @@ -0,0 +1,34 @@ +#include +#import +#import + +// http://overooped.com/post/2593597587/mediakeys + +#define SPSystemDefinedEventMediaKeys 8 + +@interface SPMediaKeyTap : NSObject { + EventHandlerRef _app_switching_ref; + EventHandlerRef _app_terminating_ref; + CFMachPortRef _eventPort; + CFRunLoopSourceRef _eventPortSource; + CFRunLoopRef _tapThreadRL; + BOOL _shouldInterceptMediaKeyEvents; + id _delegate; + // The app that is frontmost in this list owns media keys + NSMutableArray *_mediaKeyAppList; +} ++ (NSArray*)defaultMediaKeyUserBundleIdentifiers; + +-(id)initWithDelegate:(id)delegate; + ++(BOOL)usesGlobalMediaKeyTap; +-(void)startWatchingMediaKeys; +-(void)stopWatchingMediaKeys; +-(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event; +@end + +@interface NSObject (SPMediaKeyTapDelegate) +-(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event; +@end + +extern NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey; \ No newline at end of file diff --git a/thirdparty/SPMediaKeyTap/SPMediaKeyTap.m b/thirdparty/SPMediaKeyTap/SPMediaKeyTap.m new file mode 100644 index 000000000..a349f5922 --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPMediaKeyTap.m @@ -0,0 +1,300 @@ +// Copyright (c) 2010 Spotify AB +#import "SPMediaKeyTap.h" +#import "SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h" // https://gist.github.com/511181, in submodule + +@interface SPMediaKeyTap () +-(BOOL)shouldInterceptMediaKeyEvents; +-(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting; +-(void)startWatchingAppSwitching; +-(void)stopWatchingAppSwitching; +-(void)eventTapThread; +@end +static SPMediaKeyTap *singleton = nil; + +static pascal OSStatus appSwitched (EventHandlerCallRef nextHandler, EventRef evt, void* userData); +static pascal OSStatus appTerminated (EventHandlerCallRef nextHandler, EventRef evt, void* userData); +static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon); + + +// Inspired by http://gist.github.com/546311 + +@implementation SPMediaKeyTap + +#pragma mark - +#pragma mark Setup and teardown +-(id)initWithDelegate:(id)delegate; +{ + _delegate = delegate; + [self startWatchingAppSwitching]; + singleton = self; + _mediaKeyAppList = [NSMutableArray new]; + return self; +} +-(void)dealloc; +{ + [self stopWatchingMediaKeys]; + [self stopWatchingAppSwitching]; + [_mediaKeyAppList release]; + [super dealloc]; +} + +-(void)startWatchingAppSwitching; +{ + // Listen to "app switched" event, so that we don't intercept media keys if we + // weren't the last "media key listening" app to be active + EventTypeSpec eventType = { kEventClassApplication, kEventAppFrontSwitched }; + OSStatus err = InstallApplicationEventHandler(NewEventHandlerUPP(appSwitched), 1, &eventType, self, &_app_switching_ref); + assert(err == noErr); + + eventType.eventKind = kEventAppTerminated; + err = InstallApplicationEventHandler(NewEventHandlerUPP(appTerminated), 1, &eventType, self, &_app_terminating_ref); + assert(err == noErr); +} +-(void)stopWatchingAppSwitching; +{ + if(!_app_switching_ref) return; + RemoveEventHandler(_app_switching_ref); + _app_switching_ref = NULL; +} + +-(void)startWatchingMediaKeys;{ + [self setShouldInterceptMediaKeyEvents:YES]; + + // Add an event tap to intercept the system defined media key events + _eventPort = CGEventTapCreate(kCGSessionEventTap, + kCGHeadInsertEventTap, + kCGEventTapOptionDefault, + CGEventMaskBit(NX_SYSDEFINED), + tapEventCallback, + self); + assert(_eventPort != NULL); + + _eventPortSource = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, _eventPort, 0); + assert(_eventPortSource != NULL); + + // Let's do this in a separate thread so that a slow app doesn't lag the event tap + [NSThread detachNewThreadSelector:@selector(eventTapThread) toTarget:self withObject:nil]; +} +-(void)stopWatchingMediaKeys; +{ + // TODO: Shut down thread, remove event tap port and source +} + +#pragma mark - +#pragma mark Accessors + ++(BOOL)usesGlobalMediaKeyTap +{ +#ifdef _DEBUG + // breaking in gdb with a key tap inserted sometimes locks up all mouse and keyboard input forever, forcing reboot + return NO; +#else + // XXX(nevyn): MediaKey event tap doesn't work on 10.4, feel free to figure out why if you have the energy. + return floor(NSAppKitVersionNumber) >= 949/*NSAppKitVersionNumber10_5*/; +#endif +} + ++ (NSArray*)defaultMediaKeyUserBundleIdentifiers; +{ + return [NSArray arrayWithObjects: + [[NSBundle mainBundle] bundleIdentifier], // your app + @"com.spotify.client", + @"com.apple.iTunes", + @"com.apple.QuickTimePlayerX", + @"com.apple.quicktimeplayer", + @"com.apple.iWork.Keynote", + @"com.apple.iPhoto", + @"org.videolan.vlc", + @"com.apple.Aperture", + @"com.plexsquared.Plex", + @"com.soundcloud.desktop", + @"com.macromedia.fireworks", // the tap messes up their mouse input + nil + ]; +} + + +-(BOOL)shouldInterceptMediaKeyEvents; +{ + BOOL shouldIntercept = NO; + @synchronized(self) { + shouldIntercept = _shouldInterceptMediaKeyEvents; + } + return shouldIntercept; +} + +-(void)pauseTapOnTapThread:(BOOL)yeahno; +{ + CGEventTapEnable(self->_eventPort, yeahno); +} +-(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting; +{ + BOOL oldSetting; + @synchronized(self) { + oldSetting = _shouldInterceptMediaKeyEvents; + _shouldInterceptMediaKeyEvents = newSetting; + } + if(_tapThreadRL && oldSetting != newSetting) { + id grab = [self grab]; + [grab pauseTapOnTapThread:newSetting]; + NSTimer *timer = [NSTimer timerWithTimeInterval:0 invocation:[grab invocation] repeats:NO]; + CFRunLoopAddTimer(_tapThreadRL, (CFRunLoopTimerRef)timer, kCFRunLoopCommonModes); + } +} + +#pragma mark +#pragma mark - +#pragma mark Event tap callbacks + +// Note: method called on background thread + +static CGEventRef tapEventCallback2(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) +{ + SPMediaKeyTap *self = refcon; + + if(type == kCGEventTapDisabledByTimeout) { + NSLog(@"Media key event tap was disabled by timeout"); + CGEventTapEnable(self->_eventPort, TRUE); + return event; + } else if(type == kCGEventTapDisabledByUserInput) { + // Was disabled manually by -[pauseTapOnTapThread] + return event; + } + NSEvent *nsEvent = nil; + @try { + nsEvent = [NSEvent eventWithCGEvent:event]; + } + @catch (NSException * e) { + NSLog(@"Strange CGEventType: %d: %@", type, e); + assert(0); + return event; + } + + if (type != NX_SYSDEFINED || [nsEvent subtype] != SPSystemDefinedEventMediaKeys) + return event; + + int keyCode = (([nsEvent data1] & 0xFFFF0000) >> 16); + if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_FAST && keyCode != NX_KEYTYPE_REWIND) + return event; + + if (![self shouldInterceptMediaKeyEvents]) + return event; + + [nsEvent retain]; // matched in handleAndReleaseMediaKeyEvent: + [self performSelectorOnMainThread:@selector(handleAndReleaseMediaKeyEvent:) withObject:nsEvent waitUntilDone:NO]; + + return NULL; +} + +static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) +{ + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + CGEventRef ret = tapEventCallback2(proxy, type, event, refcon); + [pool drain]; + return ret; +} + + +// event will have been retained in the other thread +-(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event { + [event autorelease]; + + [_delegate mediaKeyTap:self receivedMediaKeyEvent:event]; +} + + +-(void)eventTapThread; +{ + _tapThreadRL = CFRunLoopGetCurrent(); + CFRunLoopAddSource(_tapThreadRL, _eventPortSource, kCFRunLoopCommonModes); + CFRunLoopRun(); +} + +#pragma mark Task switching callbacks + +NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey = @"SPApplicationsNeedingMediaKeys"; + + +-(void)mediaKeyAppListChanged; +{ + if([_mediaKeyAppList count] == 0) return; + + /*NSLog(@"--"); + int i = 0; + for (NSValue *psnv in _mediaKeyAppList) { + ProcessSerialNumber psn; [psnv getValue:&psn]; + NSDictionary *processInfo = [(id)ProcessInformationCopyDictionary( + &psn, + kProcessDictionaryIncludeAllInformationMask + ) autorelease]; + NSString *bundleIdentifier = [processInfo objectForKey:(id)kCFBundleIdentifierKey]; + NSLog(@"%d: %@", i++, bundleIdentifier); + }*/ + + ProcessSerialNumber mySerial, topSerial; + GetCurrentProcess(&mySerial); + [[_mediaKeyAppList objectAtIndex:0] getValue:&topSerial]; + + Boolean same; + OSErr err = SameProcess(&mySerial, &topSerial, &same); + [self setShouldInterceptMediaKeyEvents:(err == noErr && same)]; + +} +-(void)appIsNowFrontmost:(ProcessSerialNumber)psn; +{ + NSValue *psnv = [NSValue valueWithBytes:&psn objCType:@encode(ProcessSerialNumber)]; + + NSDictionary *processInfo = [(id)ProcessInformationCopyDictionary( + &psn, + kProcessDictionaryIncludeAllInformationMask + ) autorelease]; + NSString *bundleIdentifier = [processInfo objectForKey:(id)kCFBundleIdentifierKey]; + + NSArray *whitelistIdentifiers = [[NSUserDefaults standardUserDefaults] arrayForKey:kMediaKeyUsingBundleIdentifiersDefaultsKey]; + if(![whitelistIdentifiers containsObject:bundleIdentifier]) return; + + [_mediaKeyAppList removeObject:psnv]; + [_mediaKeyAppList insertObject:psnv atIndex:0]; + [self mediaKeyAppListChanged]; +} +-(void)appTerminated:(ProcessSerialNumber)psn; +{ + NSValue *psnv = [NSValue valueWithBytes:&psn objCType:@encode(ProcessSerialNumber)]; + [_mediaKeyAppList removeObject:psnv]; + [self mediaKeyAppListChanged]; +} + +static pascal OSStatus appSwitched (EventHandlerCallRef nextHandler, EventRef evt, void* userData) +{ + SPMediaKeyTap *self = (id)userData; + + ProcessSerialNumber newSerial; + GetFrontProcess(&newSerial); + + [self appIsNowFrontmost:newSerial]; + + return CallNextEventHandler(nextHandler, evt); +} + +static pascal OSStatus appTerminated (EventHandlerCallRef nextHandler, EventRef evt, void* userData) +{ + SPMediaKeyTap *self = (id)userData; + + ProcessSerialNumber deadPSN; + + GetEventParameter( + evt, + kEventParamProcessID, + typeProcessSerialNumber, + NULL, + sizeof(deadPSN), + NULL, + &deadPSN + ); + + + [self appTerminated:deadPSN]; + return CallNextEventHandler(nextHandler, evt); +} + +@end diff --git a/thirdparty/SPMediaKeyTap/SPMediaKeyTapDelegate.m b/thirdparty/SPMediaKeyTap/SPMediaKeyTapDelegate.m new file mode 100644 index 000000000..2e7a01541 --- /dev/null +++ b/thirdparty/SPMediaKeyTap/SPMediaKeyTapDelegate.m @@ -0,0 +1,25 @@ +-(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event; +{ + assert([event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys); + + int keyCode = (([event data1] & 0xFFFF0000) >> 16); + int keyFlags = ([event data1] & 0x0000FFFF); + int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA; + int keyRepeat = (keyFlags & 0x1); + + if (keyState == 1 && windowController != NULL) { + + + switch (keyCode) { + + case NX_KEYTYPE_PLAY: +... return; + + case NX_KEYTYPE_FAST: +... return; + + case NX_KEYTYPE_REWIND: +... return; + } + } +} From 615b2ff5cb8e3c6e9ee987a48548bba48563e9cd Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 31 May 2011 18:21:41 -0400 Subject: [PATCH 10/53] And remove cruft. --- .../SPInvocationGrabbing/.svn/all-wcprops | 35 ---- .../SPInvocationGrabbing/.svn/entries | 198 ------------------ .../NSObject+SPInvocationGrabbing.h.svn-base | 30 --- .../NSObject+SPInvocationGrabbing.m.svn-base | 128 ----------- .../.svn/text-base/gistfile3.m.svn-base | 28 --- .../.svn/text-base/gistfile4.m.svn-base | 12 -- .../.svn/text-base/main.m.svn-base | 38 ---- 7 files changed, 469 deletions(-) delete mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/all-wcprops delete mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/entries delete mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.h.svn-base delete mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.m.svn-base delete mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile3.m.svn-base delete mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile4.m.svn-base delete mode 100644 thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/main.m.svn-base diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/all-wcprops b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/all-wcprops deleted file mode 100644 index 657122656..000000000 --- a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/all-wcprops +++ /dev/null @@ -1,35 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 68 -/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing -END -main.m -K 25 -svn:wc:ra_dav:version-url -V 75 -/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing/main.m -END -NSObject+SPInvocationGrabbing.h -K 25 -svn:wc:ra_dav:version-url -V 100 -/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h -END -gistfile3.m -K 25 -svn:wc:ra_dav:version-url -V 80 -/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile3.m -END -gistfile4.m -K 25 -svn:wc:ra_dav:version-url -V 80 -/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile4.m -END -NSObject+SPInvocationGrabbing.m -K 25 -svn:wc:ra_dav:version-url -V 100 -/svn/!svn/ver/3341/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m -END diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/entries b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/entries deleted file mode 100644 index 83ab274af..000000000 --- a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/entries +++ /dev/null @@ -1,198 +0,0 @@ -10 - -dir -3354 -http://clementine-player.googlecode.com/svn/trunk/3rdparty/SPMediaKeyTap/SPInvocationGrabbing -http://clementine-player.googlecode.com/svn - - - -2011-05-30T10:09:34.688096Z -3341 -john.maguire - - - - - - - - - - - - - - -94c5599e-fc6c-11de-b061-8119ef04aefe - -main.m -file - - - - -2011-05-30T19:32:29.000000Z -64cedb4901f14b8f82160d41834812c7 -2011-05-30T10:09:34.688096Z -3341 -john.maguire - - - - - - - - - - - - - - - - - - - - - -778 - -NSObject+SPInvocationGrabbing.h -file - - - - -2011-05-30T19:32:29.000000Z -21417129fd15adb3e8e88f53c96a5249 -2011-05-30T10:09:34.688096Z -3341 -john.maguire - - - - - - - - - - - - - - - - - - - - - -841 - -gistfile3.m -file - - - - -2011-05-30T19:32:29.000000Z -1794e4fc655ea831def78ad9b3b22f5d -2011-05-30T10:09:34.688096Z -3341 -john.maguire - - - - - - - - - - - - - - - - - - - - - -1080 - -gistfile4.m -file - - - - -2011-05-30T19:32:29.000000Z -4a243c33e49a1d8b7212def259a1873a -2011-05-30T10:09:34.688096Z -3341 -john.maguire - - - - - - - - - - - - - - - - - - - - - -385 - -NSObject+SPInvocationGrabbing.m -file - - - - -2011-05-30T19:32:29.000000Z -52da2f8cede4bf66b97df4df3a002086 -2011-05-30T10:09:34.688096Z -3341 -john.maguire - - - - - - - - - - - - - - - - - - - - - -2915 - diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.h.svn-base b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.h.svn-base deleted file mode 100644 index d30233daf..000000000 --- a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.h.svn-base +++ /dev/null @@ -1,30 +0,0 @@ -#import - -@interface SPInvocationGrabber : NSObject { - id _object; - NSInvocation *_invocation; - int frameCount; - char **frameStrings; - BOOL backgroundAfterForward; - BOOL onMainAfterForward; - BOOL waitUntilDone; -} --(id)initWithObject:(id)obj; --(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack; -@property (readonly, retain, nonatomic) id object; -@property (readonly, retain, nonatomic) NSInvocation *invocation; -@property BOOL backgroundAfterForward; -@property BOOL onMainAfterForward; -@property BOOL waitUntilDone; --(void)invoke; // will release object and invocation --(void)printBacktrace; --(void)saveBacktrace; -@end - -@interface NSObject (SPInvocationGrabbing) --(id)grab; --(id)invokeAfter:(NSTimeInterval)delta; --(id)nextRunloop; --(id)inBackground; --(id)onMainAsync:(BOOL)async; -@end diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.m.svn-base b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.m.svn-base deleted file mode 100644 index 8ba4adb8f..000000000 --- a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/NSObject+SPInvocationGrabbing.m.svn-base +++ /dev/null @@ -1,128 +0,0 @@ -#import "NSObject+SPInvocationGrabbing.h" -#import - -#pragma mark Invocation grabbing -@interface SPInvocationGrabber () -@property (readwrite, retain, nonatomic) id object; -@property (readwrite, retain, nonatomic) NSInvocation *invocation; - -@end - -@implementation SPInvocationGrabber -- (id)initWithObject:(id)obj; -{ - return [self initWithObject:obj stacktraceSaving:YES]; -} - --(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack; -{ - self.object = obj; - - if(saveStack) - [self saveBacktrace]; - - return self; -} --(void)dealloc; -{ - free(frameStrings); - self.object = nil; - self.invocation = nil; - [super dealloc]; -} -@synthesize invocation = _invocation, object = _object; - -@synthesize backgroundAfterForward, onMainAfterForward, waitUntilDone; -- (void)runInBackground; -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - @try { - [self invoke]; - } - @finally { - [pool drain]; - } -} - - -- (void)forwardInvocation:(NSInvocation *)anInvocation { - [anInvocation retainArguments]; - anInvocation.target = _object; - self.invocation = anInvocation; - - if(backgroundAfterForward) - [NSThread detachNewThreadSelector:@selector(runInBackground) toTarget:self withObject:nil]; - else if(onMainAfterForward) - [self performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:waitUntilDone]; -} -- (NSMethodSignature *)methodSignatureForSelector:(SEL)inSelector { - NSMethodSignature *signature = [super methodSignatureForSelector:inSelector]; - if (signature == NULL) - signature = [_object methodSignatureForSelector:inSelector]; - - return signature; -} - -- (void)invoke; -{ - - @try { - [_invocation invoke]; - } - @catch (NSException * e) { - NSLog(@"SPInvocationGrabber's target raised %@:\n\t%@\nInvocation was originally scheduled at:", e.name, e); - [self printBacktrace]; - printf("\n"); - [e raise]; - } - - self.invocation = nil; - self.object = nil; -} - --(void)saveBacktrace; -{ - void *backtraceFrames[128]; - frameCount = backtrace(&backtraceFrames[0], 128); - frameStrings = backtrace_symbols(&backtraceFrames[0], frameCount); -} --(void)printBacktrace; -{ - int x; - for(x = 3; x < frameCount; x++) { - if(frameStrings[x] == NULL) { break; } - printf("%s\n", frameStrings[x]); - } -} -@end - -@implementation NSObject (SPInvocationGrabbing) --(id)grab; -{ - return [[[SPInvocationGrabber alloc] initWithObject:self] autorelease]; -} --(id)invokeAfter:(NSTimeInterval)delta; -{ - id grabber = [self grab]; - [NSTimer scheduledTimerWithTimeInterval:delta target:grabber selector:@selector(invoke) userInfo:nil repeats:NO]; - return grabber; -} -- (id)nextRunloop; -{ - return [self invokeAfter:0]; -} --(id)inBackground; -{ - SPInvocationGrabber *grabber = [self grab]; - grabber.backgroundAfterForward = YES; - return grabber; -} --(id)onMainAsync:(BOOL)async; -{ - SPInvocationGrabber *grabber = [self grab]; - grabber.onMainAfterForward = YES; - grabber.waitUntilDone = !async; - return grabber; -} - -@end diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile3.m.svn-base b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile3.m.svn-base deleted file mode 100644 index 712293780..000000000 --- a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile3.m.svn-base +++ /dev/null @@ -1,28 +0,0 @@ -// A -+(UIView*)flashAt:(CGRect)r in:(UIView*)parent color:(UIColor*)color; -{ - float duration = 0.5; - UIView *flash = [[[UIView alloc] initWithFrame:r] autorelease]; - flash.backgroundColor = color; - [parent addSubview:flash]; - [[flash invokeAfter:duration+0.1] removeFromSuperview]; - - [UIView beginAnimations:@"SPFlash" context:NULL]; - [UIView setAnimationDuration:duration]; - flash.alpha = 0.0; - [UIView commitAnimations]; - return flash; -} - -// B -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - - // Force the animation to happen by calling this method again after a small - // delay - see http://blog.instapaper.com/post/53568356 - [[self nextRunloop] delayedTableViewDidSelectRowAtIndexPath: indexPath]; -} - -// C -[[tableView invokeAfter:0.15] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone]; -[[tableView invokeAfter:0.30] deselectRowAtIndexPath:indexPath animated:YES]; -[[tableView invokeAfter:0.45] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone]; diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile4.m.svn-base b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile4.m.svn-base deleted file mode 100644 index 8255abab0..000000000 --- a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/gistfile4.m.svn-base +++ /dev/null @@ -1,12 +0,0 @@ -@interface MyClass : NSObject --(BOOL)areTheNewViewersGoneYet:(Duck*)duck; -@end -... -MyClass *myInstance = [[MyClass alloc] init]; -id invocationGrabber = [[[SPInvocationGrabber alloc] initWithTarget:myInstance] autorelease]; - - -[invocationGrabber areTheNewViewersGoneYet:[Duck yellowDuck]]; // line 9 - - -NSInvocation *invocationForAreTheNewViewersGoneYet = [invocationGrabber invocation]; diff --git a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/main.m.svn-base b/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/main.m.svn-base deleted file mode 100644 index a6ce17f39..000000000 --- a/thirdparty/SPMediaKeyTap/SPInvocationGrabbing/.svn/text-base/main.m.svn-base +++ /dev/null @@ -1,38 +0,0 @@ -#import -#import "NSObject+SPInvocationGrabbing.h" - -@interface Foo : NSObject { - int a; -} --(void)startIt; --(void)theBackgroundStuff; --(void)theForegroundStuff; -@end - -@implementation Foo --(void)startIt; -{ - NSLog(@"Starting out on the main thread..."); - a = 3; - [[self inBackground] theBackgroundStuff]; -} --(void)theBackgroundStuff; -{ - NSLog(@"Woah, this is a background thread!"); - a += 6; - [[self onMainAsync:YES] theForegroundStuff]; -} --(void)theForegroundStuff; -{ - NSLog(@"Hey presto: %d", a); -} -@end - -int main() { - NSAutoreleasePool *pool = [NSAutoreleasePool new]; - Foo *foo = [Foo new]; - [foo startIt]; - [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; - [pool release]; - return 0; -} \ No newline at end of file From b35679822931ba2aa7d3185a60fd2dc724dae651 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 31 May 2011 22:09:53 -0400 Subject: [PATCH 11/53] Add an 'Add to my ' option for non-local playlists to copy locally --- src/libtomahawk/globalactionmanager.cpp | 20 ++++++------ src/libtomahawk/globalactionmanager.h | 4 +-- src/sourcetree/sourcetreeview.cpp | 43 ++++++++++++++++++++++++- src/sourcetree/sourcetreeview.h | 2 ++ 4 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/libtomahawk/globalactionmanager.cpp b/src/libtomahawk/globalactionmanager.cpp index 664550688..1dd335571 100644 --- a/src/libtomahawk/globalactionmanager.cpp +++ b/src/libtomahawk/globalactionmanager.cpp @@ -85,14 +85,14 @@ GlobalActionManager::openLinkFromQuery( const Tomahawk::query_ptr& query ) const return link; } -void +QString GlobalActionManager::copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist ) { QUrl link( QString( "tomahawk://%1/create/" ).arg( playlist->mode() == Tomahawk::OnDemand ? "station" : "autoplaylist" ) ); if( playlist->generator()->type() != "echonest" ) { qDebug() << "Only echonest generators are supported"; - return; + return QString(); } link.addEncodedQueryItem( "type", "echonest" ); @@ -123,6 +123,8 @@ GlobalActionManager::copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& p QClipboard* cb = QApplication::clipboard(); cb->setText( link.toEncoded() ); + + return link.toString(); } void @@ -380,22 +382,22 @@ GlobalActionManager::handleSearchCommand( const QUrl& url ) bool GlobalActionManager::handleAutoPlaylistCommand( const QUrl& url ) { - return loadDynamicPlaylist( url, false ); + return !loadDynamicPlaylist( url, false ).isNull(); } -bool +Tomahawk::dynplaylist_ptr GlobalActionManager::loadDynamicPlaylist( const QUrl& url, bool station ) { QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command if( parts.isEmpty() ) { qDebug() << "No specific station command:" << url.toString(); - return false; + return Tomahawk::dynplaylist_ptr(); } if( parts[ 0 ] == "create" ) { if( !url.hasQueryItem( "title" ) || !url.hasQueryItem( "type" ) ) { qDebug() << "Station create command needs title and type..." << url.toString(); - return false; + return Tomahawk::dynplaylist_ptr(); } QString title = url.queryItemValue( "title" ); QString type = url.queryItemValue( "type" ); @@ -520,17 +522,17 @@ GlobalActionManager::loadDynamicPlaylist( const QUrl& url, bool station ) else pl->createNewRevision( uuid(), pl->currentrevision(), type, controls, pl->entries() ); - return true; + return pl; } - return false; + return Tomahawk::dynplaylist_ptr(); } bool GlobalActionManager::handleStationCommand( const QUrl& url ) { - return loadDynamicPlaylist( url, true ); + return !loadDynamicPlaylist( url, true ).isNull(); } bool diff --git a/src/libtomahawk/globalactionmanager.h b/src/libtomahawk/globalactionmanager.h index 061d1609a..c7b9d71dc 100644 --- a/src/libtomahawk/globalactionmanager.h +++ b/src/libtomahawk/globalactionmanager.h @@ -38,13 +38,14 @@ public: QUrl openLinkFromQuery( const Tomahawk::query_ptr& query ) const; void copyToClipboard( const Tomahawk::query_ptr& query ) const; - void copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist ); + QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist ); void savePlaylistToFile( const Tomahawk::playlist_ptr& playlist, const QString& filename ); public slots: bool parseTomahawkLink( const QString& link ); void waitingForResolved( bool ); + Tomahawk::dynplaylist_ptr loadDynamicPlaylist( const QUrl& url, bool station ); private slots: void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl ); void showPlaylist(); @@ -65,7 +66,6 @@ private: bool handleBookmarkCommand(const QUrl& url ); bool handleOpenCommand(const QUrl& url ); - bool loadDynamicPlaylist( const QUrl& url, bool station ); bool doQueueAdd( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems ); Tomahawk::playlist_ptr m_toShow; diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp index fe94ff5e9..8b21bb176 100644 --- a/src/sourcetree/sourcetreeview.cpp +++ b/src/sourcetree/sourcetreeview.cpp @@ -143,10 +143,20 @@ SourceTreeView::setupMenus() m_copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) ); m_deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) ); - m_roPlaylistMenu.addAction( m_copyPlaylistAction ); + QString addToText = QString( "Add to my %1" ); + if ( type == SourcesModel::StaticPlaylist ) + addToText = addToText.arg( "Playlists" ); + if ( type == SourcesModel::AutomaticPlaylist ) + addToText = addToText.arg( "Automatic Playlists" ); + else if ( type == SourcesModel::Station ) + addToText = addToText.arg( "Stations" ); + m_addToLocalAction = m_roPlaylistMenu.addAction( tr( addToText.toUtf8(), "Adds the given playlist, dynamic playlist, or station to the users's own list" ) ); + + m_roPlaylistMenu.addAction( m_copyPlaylistAction ); m_deletePlaylistAction->setEnabled( !readonly ); m_renamePlaylistAction->setEnabled( !readonly ); + m_addToLocalAction->setEnabled( readonly ); if ( type == SourcesModel::StaticPlaylist ) m_copyPlaylistAction->setText( tr( "&Export Playlist" ) ); @@ -155,6 +165,7 @@ SourceTreeView::setupMenus() connect( m_renamePlaylistAction, SIGNAL( triggered() ), SLOT( renamePlaylist() ) ); connect( m_deletePlaylistAction, SIGNAL( triggered() ), SLOT( deletePlaylist() ) ); connect( m_copyPlaylistAction, SIGNAL( triggered() ), SLOT( copyPlaylistLink() ) ); + connect( m_addToLocalAction, SIGNAL( triggered() ), SLOT( addToLocal() ) ); } @@ -259,6 +270,36 @@ SourceTreeView::copyPlaylistLink() } } +void SourceTreeView::addToLocal() +{ + QModelIndex idx = m_contextMenuIndex; + if ( !idx.isValid() ) + return; + + SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt(); + if( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) + { + DynamicPlaylistItem* item = itemFromIndex< DynamicPlaylistItem >( m_contextMenuIndex ); + dynplaylist_ptr playlist = item->dynPlaylist(); + + // copy to a link and then generate a new playlist from that + // this way we cheaply regenerate the needed controls + QString link = GlobalActionManager::instance()->copyPlaylistToClipboard( playlist ); + dynplaylist_ptr p = GlobalActionManager::instance()->loadDynamicPlaylist( link, type == SourcesModel::Station ); + } else if ( type == SourcesModel::StaticPlaylist ) + { + PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex ); + playlist_ptr playlist = item->playlist(); + + // just create the new playlist with the same values + QList< query_ptr > queries; + foreach( const plentry_ptr& e, playlist->entries() ) + queries << e->query(); + + playlist_ptr newpl = Playlist::create( SourceList::instance()->getLocal(), uuid(), playlist->title(), playlist->info(), playlist->creator(), playlist->shared(), queries ); + } +} + void SourceTreeView::renamePlaylist() diff --git a/src/sourcetree/sourcetreeview.h b/src/sourcetree/sourcetreeview.h index d3d6eb97e..7964122f0 100644 --- a/src/sourcetree/sourcetreeview.h +++ b/src/sourcetree/sourcetreeview.h @@ -54,6 +54,7 @@ private slots: void loadPlaylist(); void deletePlaylist( const QModelIndex& = QModelIndex() ); void copyPlaylistLink(); + void addToLocal(); void onCustomContextMenu( const QPoint& pos ); protected: @@ -84,6 +85,7 @@ private: QAction* m_renamePlaylistAction; QAction* m_deletePlaylistAction; QAction* m_copyPlaylistAction; + QAction* m_addToLocalAction; bool m_dragging; QRect m_dropRect; From c52e7e4cdbf11e8852bf1c537fe75f85d7885d51 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 1 Jun 2011 04:21:01 +0200 Subject: [PATCH 12/53] * Allow seeking in songs - if possible. --- src/CMakeLists.txt | 2 + src/audiocontrols.cpp | 37 ++-- src/libtomahawk/audio/audioengine.cpp | 37 +++- src/libtomahawk/audio/audioengine.h | 2 + src/libtomahawk/pipeline.cpp | 1 + src/libtomahawk/pipeline.h | 4 + src/libtomahawk/playlist/playlistview.cpp | 1 + src/libtomahawk/playlist/queueview.cpp | 16 +- src/libtomahawk/playlist/queueview.h | 6 +- src/libtomahawk/utils/animatedsplitter.cpp | 240 ++++++++------------- src/libtomahawk/utils/animatedsplitter.h | 34 ++- src/tomahawkwindow.cpp | 8 +- src/transferview.cpp | 8 +- src/transferview.h | 4 +- 14 files changed, 183 insertions(+), 217 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index efedc8706..9c0c1223b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,6 +60,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} sourcetree/items/genericpageitems.cpp transferview.cpp + PipelineStatusView.cpp tomahawktrayicon.cpp audiocontrols.cpp settingsdialog.cpp @@ -102,6 +103,7 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui} sourcetree/items/genericpageitems.h transferview.h + PipelineStatusView.h tomahawktrayicon.h audiocontrols.h settingsdialog.h diff --git a/src/audiocontrols.cpp b/src/audiocontrols.cpp index 7be1bc26e..01536818c 100644 --- a/src/audiocontrols.cpp +++ b/src/audiocontrols.cpp @@ -80,27 +80,23 @@ AudioControls::AudioControls( QWidget* parent ) ui->metaDataArea->setStyleSheet( "QWidget#metaDataArea {\nborder-width: 4px;\nborder-image: url(" RESPATH "images/now-playing-panel.png) 4 4 4 4 stretch stretch; }" ); ui->seekSlider->setFixedHeight( 20 ); - ui->seekSlider->setEnabled( false ); + ui->seekSlider->setEnabled( true ); ui->seekSlider->setStyleSheet( "QSlider::groove::horizontal {" "margin: 5px; border-width: 3px;" "border-image: url(" RESPATH "images/seek-slider-bkg.png) 3 3 3 3 stretch stretch;" "}" - "QSlider::handle::horizontal {" - "margin-left: 5px; margin-right: -5px; " - "width: 0px;" - - //"margin-bottom: -7px; margin-top: -7px;" - //"height: 17px; width: 16px;" - //"background-image: url(" RESPATH "images/seek-and-volume-knob-rest.png);" - //"background-repeat: no-repeat;" - "}" - "QSlider::sub-page:horizontal {" "margin: 5px; border-width: 3px;" "border-image: url(" RESPATH "images/seek-slider-level.png) 3 3 3 3 stretch stretch;" "}" - ); + + "QSlider::handle::horizontal {" + "margin-bottom: -7px; margin-top: -7px;" + "height: 17px; width: 16px;" + "background-image: url(" RESPATH "images/seek-and-volume-knob-rest.png);" + "background-repeat: no-repeat;" + "}" ); ui->volumeSlider->setFixedHeight( 20 ); ui->volumeSlider->setRange( 0, 100 ); @@ -120,9 +116,7 @@ AudioControls::AudioControls( QWidget* parent ) "height: 17px; width: 16px;" "background-image: url(" RESPATH "images/seek-and-volume-knob-rest.png);" "background-repeat: no-repeat;" - "}" - - ); + "}" ); /* m_playAction = new QAction( this ); m_pauseAction = new QAction( this ); @@ -134,6 +128,7 @@ AudioControls::AudioControls( QWidget* parent ) connect( m_prevAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( previous() ) ); connect( m_nextAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( next() ) ); */ + connect( ui->seekSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( seek( int ) ) ); connect( ui->volumeSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( setVolume( int ) ) ); connect( ui->prevButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( previous() ) ); connect( ui->playPauseButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( play() ) ); @@ -283,13 +278,11 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result ) ui->ownerLabel->setText( result->friendlySource() ); ui->coverImage->setPixmap( m_defaultCover ); - if ( ui->timeLabel->text().isEmpty() ) - ui->timeLabel->setText( TomahawkUtils::timeToString( 0 ) ); - - if ( ui->timeLeftLabel->text().isEmpty() ) - ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( result->duration() ) ); + ui->timeLabel->setText( TomahawkUtils::timeToString( 0 ) ); + ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( result->duration() ) ); ui->seekSlider->setRange( 0, m_currentTrack->duration() * 1000 ); + ui->seekSlider->setValue( 0 ); ui->seekSlider->setVisible( true ); /* m_playAction->setEnabled( false ); @@ -357,10 +350,14 @@ AudioControls::onPlaybackTimer( qint64 msElapsed ) if ( m_currentTrack.isNull() ) return; + ui->seekSlider->blockSignals( true ); + const int seconds = msElapsed / 1000; ui->timeLabel->setText( TomahawkUtils::timeToString( seconds ) ); ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( m_currentTrack->duration() - seconds ) ); ui->seekSlider->setValue( msElapsed ); + + ui->seekSlider->blockSignals( false ); } diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 51f1aea1a..70d6f9afe 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -136,6 +136,17 @@ AudioEngine::next() } +void +AudioEngine::seek( int ms ) +{ + if ( isPlaying() || isPaused() ) + { + qDebug() << Q_FUNC_INFO << ms; + m_mediaObject->seek( ms ); + } +} + + void AudioEngine::setVolume( int percentage ) { @@ -176,7 +187,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) { setCurrentTrack( result ); - if ( !isHttpResult( m_currentTrack->url() ) ) + if ( !isHttpResult( m_currentTrack->url() ) && !isLocalResult( m_currentTrack->url() ) ) { io = Servent::instance()->getIODeviceForUrl( m_currentTrack ); @@ -204,7 +215,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) m_expectStop = true; } - if ( !isHttpResult( m_currentTrack->url() ) ) + if ( !isHttpResult( m_currentTrack->url() ) && !isLocalResult( m_currentTrack->url() ) ) { m_mediaObject->setCurrentSource( io.data() ); m_mediaObject->currentSource().setAutoDelete( false ); @@ -217,7 +228,6 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) { furl = QUrl( m_currentTrack->url().left( m_currentTrack->url().indexOf( '?' ) ) ); furl.setEncodedQuery( QString( m_currentTrack->url().mid( m_currentTrack->url().indexOf( '?' ) + 1 ) ).toLocal8Bit() ); - qDebug() << Q_FUNC_INFO << furl; } m_mediaObject->setCurrentSource( furl ); m_mediaObject->currentSource().setAutoDelete( true ); @@ -306,11 +316,22 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState ) { qDebug() << "Phonon Error:" << m_mediaObject->errorString() << m_mediaObject->errorType(); } - if ( oldState == Phonon::PlayingState && newState == Phonon::StoppedState ) { + qDebug() << "Expecting stop?" << m_expectStop; if ( !m_expectStop ) { + qDebug() << "Loading next track."; + m_expectStop = false; + loadNextTrack(); + } + } + else if ( oldState == Phonon::PlayingState && newState == Phonon::PausedState ) + { + qDebug() << m_mediaObject->currentTime() << m_mediaObject->totalTime(); + if ( m_mediaObject->currentTime() == m_mediaObject->totalTime() ) + { + qDebug() << "Loading next track."; m_expectStop = false; loadNextTrack(); } @@ -365,8 +386,16 @@ AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result ) m_currentTrack = result; } + bool AudioEngine::isHttpResult( const QString& url ) const { return url.startsWith( "http://" ); } + + +bool +AudioEngine::isLocalResult( const QString& url ) const +{ + return url.startsWith( "file://" ); +} diff --git a/src/libtomahawk/audio/audioengine.h b/src/libtomahawk/audio/audioengine.h index 580f9e044..d7fc8c954 100644 --- a/src/libtomahawk/audio/audioengine.h +++ b/src/libtomahawk/audio/audioengine.h @@ -64,6 +64,7 @@ public slots: void previous(); void next(); + void seek( int ms ); void setVolume( int percentage ); void lowerVolume() { setVolume( volume() - AUDIO_VOLUME_STEP ); } void raiseVolume() { setVolume( volume() + AUDIO_VOLUME_STEP ); } @@ -106,6 +107,7 @@ private slots: private: bool isHttpResult( const QString& ) const; + bool isLocalResult( const QString& ) const; bool m_isPlayingHttp; QSharedPointer m_input; diff --git a/src/libtomahawk/pipeline.cpp b/src/libtomahawk/pipeline.cpp index 3bae02c19..70b7edcdf 100644 --- a/src/libtomahawk/pipeline.cpp +++ b/src/libtomahawk/pipeline.cpp @@ -311,6 +311,7 @@ Pipeline::shunt( const query_ptr& q ) qDebug() << "Dispatching to resolver" << r->name() << q->toString() << q->solved() << q->id(); r->resolve( q ); + emit resolving( q ); } else break; diff --git a/src/libtomahawk/pipeline.h b/src/libtomahawk/pipeline.h index d07608747..7c41e03ab 100644 --- a/src/libtomahawk/pipeline.h +++ b/src/libtomahawk/pipeline.h @@ -46,6 +46,9 @@ public: explicit Pipeline( QObject* parent = 0 ); virtual ~Pipeline(); + unsigned int pendingQueryCount() const { return m_queries_pending.count(); } + unsigned int activeQueryCount() const { return m_qidsState.count(); } + void reportResults( QID qid, const QList< result_ptr >& results ); /// sorter to rank resolver priority @@ -75,6 +78,7 @@ public slots: signals: void idle(); + void resolving( const Tomahawk::query_ptr& query ); private slots: void timeoutShunt( const query_ptr& q ); diff --git a/src/libtomahawk/playlist/playlistview.cpp b/src/libtomahawk/playlist/playlistview.cpp index 5000bd80c..8d59cb6d4 100644 --- a/src/libtomahawk/playlist/playlistview.cpp +++ b/src/libtomahawk/playlist/playlistview.cpp @@ -99,6 +99,7 @@ PlaylistView::setupMenus() foreach( QAction* a, actions() ) m_itemMenu.addAction( a ); + // m_addItemsToPlaylistAction = m_itemMenu.addAction( tr( "&Add to Playlist" ) ); // m_itemMenu.addSeparator(); m_deleteItemsAction = m_itemMenu.addAction( i > 1 ? tr( "&Delete Items" ) : tr( "&Delete Item" ) ); diff --git a/src/libtomahawk/playlist/queueview.cpp b/src/libtomahawk/playlist/queueview.cpp index 1d060db73..d361b7342 100644 --- a/src/libtomahawk/playlist/queueview.cpp +++ b/src/libtomahawk/playlist/queueview.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 @@ -45,7 +45,7 @@ QueueView::QueueView( AnimatedSplitter* parent ) m_queue->setFrameShape( QFrame::NoFrame ); m_queue->setAttribute( Qt::WA_MacShowFocusRect, 0 ); m_queue->overlay()->setEnabled( false ); - + m_button = new QPushButton(); m_button->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ); m_button->setText( tr( "Click to show queue" ) ); @@ -64,13 +64,13 @@ QueueView::~QueueView() void -QueueView::onShown( QWidget* widget ) +QueueView::onShown( QWidget* widget, bool animated ) { qDebug() << Q_FUNC_INFO << widget; if ( widget != this ) return; - AnimatedWidget::onShown( widget ); + AnimatedWidget::onShown( widget, animated ); m_button->setText( tr( "Click to hide queue" ) ); disconnect( m_button, SIGNAL( clicked() ), this, SIGNAL( showWidget() ) ); @@ -79,14 +79,14 @@ QueueView::onShown( QWidget* widget ) void -QueueView::onHidden( QWidget* widget ) +QueueView::onHidden( QWidget* widget, bool animated ) { qDebug() << Q_FUNC_INFO << widget; if ( widget != this ) return; - - AnimatedWidget::onHidden( widget ); - + + AnimatedWidget::onHidden( widget, animated ); + m_button->setText( tr( "Click to show queue" ) ); disconnect( m_button, SIGNAL( clicked() ), this, SIGNAL( hideWidget() ) ); connect( m_button, SIGNAL( clicked() ), SIGNAL( showWidget() ) ); diff --git a/src/libtomahawk/playlist/queueview.h b/src/libtomahawk/playlist/queueview.h index f617831f9..a8549fffa 100644 --- a/src/libtomahawk/playlist/queueview.h +++ b/src/libtomahawk/playlist/queueview.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 @@ -39,8 +39,8 @@ public: QSize sizeHint() const { return QSize( 0, 200 ); } public slots: - virtual void onShown( QWidget* ); - virtual void onHidden( QWidget* ); + virtual void onShown( QWidget*, bool animated ); + virtual void onHidden( QWidget*, bool animated ); private: PlaylistView* m_queue; diff --git a/src/libtomahawk/utils/animatedsplitter.cpp b/src/libtomahawk/utils/animatedsplitter.cpp index 3ec748052..fc5d4898d 100644 --- a/src/libtomahawk/utils/animatedsplitter.cpp +++ b/src/libtomahawk/utils/animatedsplitter.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 @@ -23,83 +23,25 @@ AnimatedSplitter::AnimatedSplitter( QWidget* parent ) : QSplitter( parent ) - , m_animateIndex( -1 ) , m_greedyIndex( 0 ) { setHandleWidth( 1 ); - - m_timeLine = new QTimeLine( ANIMATION_TIME, this ); - m_timeLine->setUpdateInterval( 5 ); - m_timeLine->setEasingCurve( QEasingCurve::OutBack ); - - connect( m_timeLine, SIGNAL( frameChanged( int ) ), SLOT( onAnimationStep( int ) ) ); - connect( m_timeLine, SIGNAL( finished() ), SLOT( onAnimationFinished() ) ); } void AnimatedSplitter::show( int index, bool animate ) { - m_animateIndex = index; - QWidget* w = widget( index ); - QSize size = w->sizeHint(); - - if ( w->height() == size.height() ) - return; - - emit shown( w ); - w->setMaximumHeight( QWIDGETSIZE_MAX ); - qDebug() << "animating to:" << size.height() << "from" << w->height(); - - m_animateForward = true; - if ( animate ) - { - if ( m_timeLine->state() == QTimeLine::Running ) - m_timeLine->stop(); - - m_timeLine->setFrameRange( w->height(), size.height() ); - m_timeLine->setDirection( QTimeLine::Forward ); - m_timeLine->start(); - } - else - { - onAnimationStep( size.height() ); - onAnimationFinished(); - } + emit shown( w, animate ); } void AnimatedSplitter::hide( int index, bool animate ) { - m_animateIndex = index; - QWidget* w = widget( index ); - int minHeight = m_sizes.at( index ).height(); - - if ( w->height() == minHeight ) - return; - - emit hidden( w ); - w->setMinimumHeight( minHeight ); -// qDebug() << "animating to:" << w->height() << "from" << minHeight; - - m_animateForward = false; - if ( animate ) - { - if ( m_timeLine->state() == QTimeLine::Running ) - m_timeLine->stop(); - - m_timeLine->setFrameRange( minHeight, w->height() ); - m_timeLine->setDirection( QTimeLine::Backward ); - m_timeLine->start(); - } - else - { - onAnimationStep( minHeight ); - onAnimationFinished(); - } + emit hidden( w, animate ); } @@ -107,7 +49,6 @@ void AnimatedSplitter::addWidget( QWidget* widget ) { QSplitter::addWidget( widget ); - m_sizes << widget->minimumSize(); } @@ -116,13 +57,11 @@ AnimatedSplitter::addWidget( AnimatedWidget* widget ) { qDebug() << Q_FUNC_INFO << widget; QSplitter::addWidget( widget ); - m_sizes << widget->hiddenSize(); connect( widget, SIGNAL( showWidget() ), SLOT( onShowRequest() ) ); connect( widget, SIGNAL( hideWidget() ), SLOT( onHideRequest() ) ); - connect( widget, SIGNAL( hiddenSizeChanged() ), SLOT( onHiddenSizeChanged() ) ); - connect( this, SIGNAL( shown( QWidget* ) ), widget, SLOT( onShown( QWidget* ) ) ); - connect( this, SIGNAL( hidden( QWidget* ) ), widget, SLOT( onHidden( QWidget* ) ) ); + connect( this, SIGNAL( shown( QWidget*, bool ) ), widget, SLOT( onShown( QWidget*, bool ) ) ); + connect( this, SIGNAL( hidden( QWidget*, bool ) ), widget, SLOT( onHidden( QWidget*, bool ) ) ); } @@ -131,18 +70,9 @@ AnimatedSplitter::onShowRequest() { qDebug() << Q_FUNC_INFO << sender(); - int j = -1; - for ( int i = 0; i < count(); i ++ ) - { - if ( widget( i ) == sender() ) - { - j = i; - break; - } - } - - if ( j > 0 ) - show( j ); + AnimatedWidget* w = (AnimatedWidget*)(sender()); + if ( indexOf( w ) > 0 ) + show( indexOf( w ) ); else qDebug() << "Could not find widget:" << sender(); } @@ -151,72 +81,16 @@ AnimatedSplitter::onShowRequest() void AnimatedSplitter::onHideRequest() { - int j = -1; - for ( int i = 0; i < count(); i ++ ) - { - if ( widget( i ) == sender() ) - { - j = i; - break; - } - } - - if ( j > 0 ) - hide( j ); + AnimatedWidget* w = (AnimatedWidget*)(sender()); + if ( indexOf( w ) > 0 ) + hide( indexOf( w ) ); else qDebug() << "Could not find widget:" << sender(); } void -AnimatedSplitter::onAnimationStep( int frame ) -{ - QList< int > sizes; - - for ( int i = 0; i < count(); i ++ ) - { - int j = 0; - - if ( i == m_greedyIndex ) - { - j = height() - frame; // FIXME - } - else if ( i == m_animateIndex ) - { - j = frame; - } - else - { - j = widget( i )->height(); - } - - sizes << j; - } - - setSizes( sizes ); -} - - -void -AnimatedSplitter::onAnimationFinished() -{ - qDebug() << Q_FUNC_INFO; - - QWidget* w = widget( m_animateIndex ); - if ( m_animateForward ) - { - w->setMinimumHeight( w->minimumHeight() ); - } - else - { - w->setMaximumHeight( m_sizes.at( m_animateIndex ).height() ); - } - - m_animateIndex = -1; -} - -void -AnimatedSplitter::setGreedyWidget(int index) +AnimatedSplitter::setGreedyWidget( int index ) { m_greedyIndex = index; if( !widget( index ) ) @@ -227,17 +101,7 @@ AnimatedSplitter::setGreedyWidget(int index) else policy.setVerticalStretch( 1 ); widget( m_greedyIndex )->setSizePolicy( policy ); - -} - -void -AnimatedSplitter::onHiddenSizeChanged() -{ - AnimatedWidget* w = (AnimatedWidget*)(sender()); - int i = indexOf( w ); - - m_sizes.replace( i, w->hiddenSize() ); } @@ -246,24 +110,98 @@ AnimatedWidget::AnimatedWidget( AnimatedSplitter* parent ) , m_isHidden( false ) { qDebug() << Q_FUNC_INFO; + + m_timeLine = new QTimeLine( ANIMATION_TIME, this ); + m_timeLine->setUpdateInterval( 5 ); + m_timeLine->setEasingCurve( QEasingCurve::OutBack ); + + connect( m_timeLine, SIGNAL( frameChanged( int ) ), SLOT( onAnimationStep( int ) ) ); + connect( m_timeLine, SIGNAL( finished() ), SLOT( onAnimationFinished() ) ); } + AnimatedWidget::~AnimatedWidget() { - } + void -AnimatedWidget::onShown( QWidget* ) +AnimatedWidget::onShown( QWidget* widget, bool animated ) { + if ( widget != this ) + return; + qDebug() << Q_FUNC_INFO << this; + + m_animateForward = true; + if ( animated ) + { + if ( m_timeLine->state() == QTimeLine::Running ) + m_timeLine->stop(); + + m_timeLine->setFrameRange( height(), sizeHint().height() ); + m_timeLine->setDirection( QTimeLine::Forward ); + m_timeLine->start(); + } + else + { + onAnimationStep( sizeHint().height() ); + onAnimationFinished(); + } + m_isHidden = false; } void -AnimatedWidget::onHidden( QWidget* ) +AnimatedWidget::onHidden( QWidget* widget, bool animated ) { + if ( widget != this ) + return; + qDebug() << Q_FUNC_INFO << this; + + m_animateForward = false; + int minHeight = hiddenSize().height(); + + if ( animated ) + { + if ( m_timeLine->state() == QTimeLine::Running ) + m_timeLine->stop(); + + m_timeLine->setFrameRange( minHeight, height() ); + m_timeLine->setDirection( QTimeLine::Backward ); + m_timeLine->start(); + } + else + { + onAnimationStep( minHeight ); + onAnimationFinished(); + } + m_isHidden = true; } + + +void +AnimatedWidget::onAnimationStep( int frame ) +{ + setFixedHeight( frame ); +} + + +void +AnimatedWidget::onAnimationFinished() +{ + qDebug() << Q_FUNC_INFO; + + if ( m_animateForward ) + { + setMinimumHeight( hiddenSize().height() ); + setMaximumHeight( QWIDGETSIZE_MAX ); + } + else + { + setFixedHeight( hiddenSize().height() ); + } +} diff --git a/src/libtomahawk/utils/animatedsplitter.h b/src/libtomahawk/utils/animatedsplitter.h index ba1671f4e..20cb283eb 100644 --- a/src/libtomahawk/utils/animatedsplitter.h +++ b/src/libtomahawk/utils/animatedsplitter.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 @@ -43,56 +43,52 @@ public: void addWidget( AnimatedWidget* widget ); signals: - void shown( QWidget* ); - void hidden( QWidget* ); + void shown( QWidget*, bool animated ); + void hidden( QWidget*, bool animated ); private slots: void onShowRequest(); void onHideRequest(); - void onAnimationStep( int frame ); - void onAnimationFinished(); - - void onHiddenSizeChanged(); - private: - int m_animateIndex; - bool m_animateForward; - int m_greedyIndex; - QList m_sizes; - QTimeLine* m_timeLine; }; class DLLEXPORT AnimatedWidget : public QWidget { Q_OBJECT public: - explicit AnimatedWidget( AnimatedSplitter* parent = 0 ); + explicit AnimatedWidget( AnimatedSplitter* parent ); virtual ~AnimatedWidget(); - + QSize hiddenSize() const { return m_hiddenSize; } void setHiddenSize( const QSize& size ) { m_hiddenSize = size; emit hiddenSizeChanged(); } bool isHidden() const { return m_isHidden; } public slots: - virtual void onShown( QWidget* ); - virtual void onHidden( QWidget* ); + virtual void onShown( QWidget*, bool animated ); + virtual void onHidden( QWidget*, bool animated ); signals: void showWidget(); void hideWidget(); void hiddenSizeChanged(); + +private slots: + void onAnimationStep( int frame ); + void onAnimationFinished(); + protected: - AnimatedSplitter* splitter() { return m_parent; } - + private: AnimatedSplitter* m_parent; + bool m_animateForward; QSize m_hiddenSize; bool m_isHidden; + QTimeLine* m_timeLine; }; #endif //ANIMATEDSPLITTER_H diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index 13989b4d4..c83332f70 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -57,6 +57,7 @@ #include "diagnosticsdialog.h" #include "tomahawksettings.h" #include "sourcelist.h" +#include "PipelineStatusView.h" #include "transferview.h" #include "tomahawktrayicon.h" #include "playlist/dynamic/GeneratorInterface.h" @@ -107,18 +108,19 @@ TomahawkWindow::TomahawkWindow( QWidget* parent ) sidebar->setOrientation( Qt::Vertical ); sidebar->setChildrenCollapsible( false ); sidebar->setGreedyWidget( 0 ); - sidebar->setStretchFactor( 0, 3 ); - sidebar->setStretchFactor( 1, 1 ); m_sourcetree = new SourceTreeView(); - TransferView* transferView = new TransferView(); + TransferView* transferView = new TransferView( sidebar ); + PipelineStatusView* pipelineView = new PipelineStatusView( sidebar ); connect( ui->actionHideOfflineSources, SIGNAL( triggered() ), m_sourcetree, SLOT( hideOfflineSources() ) ); connect( ui->actionShowOfflineSources, SIGNAL( triggered() ), m_sourcetree, SLOT( showOfflineSources() ) ); sidebar->addWidget( m_sourcetree ); sidebar->addWidget( transferView ); + sidebar->addWidget( pipelineView ); sidebar->hide( 1, false ); + sidebar->hide( 2, false ); /* QWidget* buttonWidget = new QWidget(); buttonWidget->setLayout( new QVBoxLayout() ); diff --git a/src/transferview.cpp b/src/transferview.cpp index af8ba3ed2..4ae9948e3 100644 --- a/src/transferview.cpp +++ b/src/transferview.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 @@ -80,12 +80,6 @@ TransferView::streamFinished( StreamConnection* sc ) emit showWidget(); else emit hideWidget(); - -/* if ( m_index.contains( sc ) ) - { - int i = m_index.value( sc ); - m_tree->invisibleRootItem()->child( i )->setText( 1, tr( "Finished" ) ); - }*/ } diff --git a/src/transferview.h b/src/transferview.h index 560088bbf..d517c57bf 100644 --- a/src/transferview.h +++ b/src/transferview.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 @@ -32,7 +32,7 @@ class TransferView : public AnimatedWidget Q_OBJECT public: - explicit TransferView( AnimatedSplitter* parent = 0 ); + explicit TransferView( AnimatedSplitter* parent ); virtual ~TransferView() { qDebug() << Q_FUNC_INFO; From aeedf286eb64e0f281ae7951d32ac62f5e9de7d5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 1 Jun 2011 04:21:35 +0200 Subject: [PATCH 13/53] * Added Pipeline status view. WIP. --- src/PipelineStatusView.cpp | 104 +++++++++++++++++++++++++++++++++++++ src/PipelineStatusView.h | 51 ++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 src/PipelineStatusView.cpp create mode 100644 src/PipelineStatusView.h diff --git a/src/PipelineStatusView.cpp b/src/PipelineStatusView.cpp new file mode 100644 index 000000000..de0efe281 --- /dev/null +++ b/src/PipelineStatusView.cpp @@ -0,0 +1,104 @@ +/* === 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 "PipelineStatusView.h" + +#include +#include + +#include "libtomahawk/pipeline.h" + +using namespace Tomahawk; + + +PipelineStatusView::PipelineStatusView( AnimatedSplitter* parent ) + : AnimatedWidget( parent ) + , m_parent( parent ) +{ + setHiddenSize( QSize( 0, 0 ) ); + setLayout( new QVBoxLayout() ); + m_tree = new QTreeWidget( this ); + + layout()->setMargin( 0 ); + layout()->addWidget( m_tree ); + + QStringList headers; + headers << tr( "Searching For" ) << tr( "Pending" ); + m_tree->setHeaderLabels( headers ); + + m_tree->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored ); + m_tree->setColumnCount( 2 ); + m_tree->setColumnWidth( 0, 200 ); + m_tree->setColumnWidth( 1, 50 ); + + m_tree->header()->setStretchLastSection( true ); + m_tree->setRootIsDecorated( false ); + + m_tree->setFrameShape( QFrame::NoFrame ); + m_tree->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + new QTreeWidgetItem( m_tree ); + + connect( Pipeline::instance(), SIGNAL( resolving( Tomahawk::query_ptr ) ), SLOT( onPipelineUpdate( Tomahawk::query_ptr ) ) ); + connect( Pipeline::instance(), SIGNAL( idle() ), SLOT( onPipelineUpdate() ) ); + + onPipelineUpdate(); +} + + +void +PipelineStatusView::onPipelineUpdate( const query_ptr& query ) +{ + qDebug() << Q_FUNC_INFO; + + QTreeWidgetItem* ti = m_tree->invisibleRootItem()->child( 0 ); + + if ( Pipeline::instance()->activeQueryCount() && !query.isNull() ) + { + ti->setText( 0, QString( "%1 - %2" ).arg( query->artist() ).arg( query->track() ) ); + ti->setText( 1, QString( "%1" ).arg( Pipeline::instance()->activeQueryCount() + Pipeline::instance()->pendingQueryCount() ) ); + + if ( isHidden() ) + emit showWidget(); + } + else + { + ti->setText( 0, tr( "Idle" ) ); + ti->setText( 1, QString( "None" ) ); + + if ( !isHidden() ) + emit hideWidget(); + } +} + + +QSize +PipelineStatusView::sizeHint() const +{ + unsigned int y = 0; + y += m_tree->header()->height(); + y += m_tree->contentsMargins().top() + m_tree->contentsMargins().bottom(); + + if ( m_tree->invisibleRootItem()->childCount() ) + { + unsigned int rowheight = m_tree->sizeHintForRow( 0 ); + y += rowheight * m_tree->invisibleRootItem()->childCount() + 2; + } + + return QSize( 0, y ); +} diff --git a/src/PipelineStatusView.h b/src/PipelineStatusView.h new file mode 100644 index 000000000..df3a72542 --- /dev/null +++ b/src/PipelineStatusView.h @@ -0,0 +1,51 @@ +/* === 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 PIPELINESTATUSVIEW_H +#define PIPELINESTATUSVIEW_H + +#include +#include + +#include "typedefs.h" +#include "utils/animatedsplitter.h" + +class StreamConnection; + +class PipelineStatusView : public AnimatedWidget +{ +Q_OBJECT + +public: + explicit PipelineStatusView( AnimatedSplitter* parent ); + virtual ~PipelineStatusView() + { + qDebug() << Q_FUNC_INFO; + } + + QSize sizeHint() const; + +private slots: + void onPipelineUpdate( const Tomahawk::query_ptr& query = Tomahawk::query_ptr() ); + +private: + QTreeWidget* m_tree; + AnimatedSplitter* m_parent; +}; + +#endif // TRANSFERVIEW_H From b4e0674e2bf0ebc10c74ddf250653e670b044956 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Wed, 1 Jun 2011 17:41:44 -0400 Subject: [PATCH 14/53] SHow initial config dialog as sheet on osx, WIP --- src/settingsdialog.cpp | 61 +++++++++++++++++++++++++++++++++++------- src/settingsdialog.h | 4 ++- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index fc67ff18a..1a3ea88a6 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -382,7 +382,7 @@ SettingsDialog::onLastFmFinished() 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" ) ); @@ -528,6 +528,15 @@ SettingsDialog::sipFactoryClicked( SipPluginFactory* factory ) SipPlugin* p = factory->createPlugin(); bool added = false; if( p->configWidget() ) { + +#ifdef Q_OS_MAC + // on osx a sheet needs to be non-modal + DelegateConfigWrapper* dialog = new DelegateConfigWrapper( p->configWidget(), QString("%1 Config" ).arg( p->friendlyName() ), this, Qt::Sheet ); + dialog->setProperty( "sipplugin", QVariant::fromValue< QObject* >( p ) ); + connect( dialog, SIGNAL( finished( int ) ), this, SLOT( sipCreateConfigClosed( int ) ) ); + + dialog->show(); +#else DelegateConfigWrapper dialog( p->configWidget(), QString("%1 Config" ).arg( p->friendlyName() ), this ); QWeakPointer< DelegateConfigWrapper > watcher( &dialog ); int ret = dialog.exec(); @@ -544,13 +553,44 @@ SettingsDialog::sipFactoryClicked( SipPluginFactory* factory ) // canceled, delete it added = false; } + + handleSipPluginAdded( p, added ); +#endif } else { // no config, so just add it added = true; TomahawkSettings::instance()->addSipPlugin( p->pluginId() ); SipHandler::instance()->addSipPlugin( p ); + + handleSipPluginAdded( p, added ); } +} + +void +SettingsDialog::sipCreateConfigClosed( int finished ) +{ + DelegateConfigWrapper* dialog = qobject_cast< DelegateConfigWrapper* >( sender() ); + SipPlugin* p = qobject_cast< SipPlugin* >( dialog->property( "sipplugin" ).value< QObject* >() ); + Q_ASSERT( p ); + + bool added = false; + if( finished == QDialog::Accepted ) { + + p->saveConfig(); + TomahawkSettings::instance()->addSipPlugin( p->pluginId() ); + SipHandler::instance()->addSipPlugin( p ); + + added = true; + } + + handleSipPluginAdded( p, added ); +} + + +void +SettingsDialog::handleSipPluginAdded( SipPlugin* p, bool added ) +{ SipPluginFactory* f = SipHandler::instance()->factoryFromPlugin( p ); if( added && f && f->isUnique() ) { // remove from actions list @@ -570,6 +610,7 @@ SettingsDialog::sipFactoryClicked( SipPluginFactory* factory ) } } + void SettingsDialog::sipContextMenuRequest( const QPoint& p ) { @@ -625,9 +666,9 @@ ProxyDialog::ProxyDialog( QWidget *parent ) , ui( new Ui::ProxyDialog ) { ui->setupUi( this ); - + // ugly, I know, but... - + int i = 0; ui->typeBox->insertItem( i, "No Proxy", QNetworkProxy::NoProxy ); m_forwardMap[ QNetworkProxy::NoProxy ] = i; @@ -637,9 +678,9 @@ ProxyDialog::ProxyDialog( QWidget *parent ) m_forwardMap[ QNetworkProxy::Socks5Proxy ] = i; m_backwardMap[ i ] = QNetworkProxy::Socks5Proxy; i++; - + TomahawkSettings* s = TomahawkSettings::instance(); - + ui->typeBox->setCurrentIndex( m_forwardMap[s->proxyType()] ); ui->hostLineEdit->setText( s->proxyHost() ); ui->portSpinBox->setValue( s->proxyPort() ); @@ -681,18 +722,18 @@ ProxyDialog::proxyTypeChangedSlot( int index ) ui->passwordLineEdit->setEnabled( true ); ui->checkBoxUseProxyForDns->setEnabled( true ); ui->noHostLineEdit->setEnabled( true ); - } + } } void ProxyDialog::saveSettings() { qDebug() << Q_FUNC_INFO; - + //First set settings TomahawkSettings* s = TomahawkSettings::instance(); s->setProxyHost( ui->hostLineEdit->text() ); - + int port = ui->portSpinBox->value(); s->setProxyPort( port ); s->setProxyNoProxyHosts( ui->noHostLineEdit->text() ); @@ -700,10 +741,10 @@ ProxyDialog::saveSettings() s->setProxyPassword( ui->passwordLineEdit->text() ); s->setProxyType( ui->typeBox->itemData( ui->typeBox->currentIndex() ).toInt() ); s->setProxyDns( ui->checkBoxUseProxyForDns->checkState() == Qt::Checked ); - + if( s->proxyHost().isEmpty() ) return; - + TomahawkUtils::NetworkProxyFactory* proxyFactory = new TomahawkUtils::NetworkProxyFactory(); QNetworkProxy proxy( static_cast(s->proxyType()), s->proxyHost(), s->proxyPort(), s->proxyUsername(), s->proxyPassword() ); proxyFactory->setProxy( proxy ); diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 78e1f55e3..5cebb30a1 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -48,7 +48,7 @@ public: private slots: void proxyTypeChangedSlot( int index ); - + private: Ui::ProxyDialog* ui; QHash m_forwardMap; @@ -95,12 +95,14 @@ private slots: // dialog slots void resolverConfigClosed( int value ); void sipConfigClosed( int value ); + void sipCreateConfigClosed( int value ); void changePage( QListWidgetItem*, QListWidgetItem* ); private: void createIcons(); void setupSipButtons(); + void handleSipPluginAdded( SipPlugin* p, bool added ); Ui_StackedSettingsDialog* ui; From e130fc41ed66a2bfef578d568890a44586c98fc5 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Wed, 1 Jun 2011 20:29:54 -0400 Subject: [PATCH 15/53] resize dialog when it changes size, and hide/show otherwise osx goes CRAZY PANTS --- src/delegateconfigwrapper.h | 11 +++++++++++ src/sip/twitter/twitterconfigwidget.cpp | 2 ++ src/sip/twitter/twitterconfigwidget.h | 1 + 3 files changed, 14 insertions(+) diff --git a/src/delegateconfigwrapper.h b/src/delegateconfigwrapper.h index 463261deb..6dc40700a 100644 --- a/src/delegateconfigwrapper.h +++ b/src/delegateconfigwrapper.h @@ -47,6 +47,8 @@ public: setSizeGripEnabled( false ); setMinimumSize( sizeHint() ); setMaximumSize( sizeHint() ); // to remove the resize grip on osx this is the only way + + connect( conf, SIGNAL( sizeHintChanged() ), this, SLOT( updateSizeHint() ) ); #endif } public slots: @@ -72,6 +74,15 @@ public slots: m_widget->setVisible( false ); } + void updateSizeHint() { + hide(); + setSizeGripEnabled( false ); + setMinimumSize( sizeHint() ); + setMaximumSize( sizeHint() ); + + show(); + } + private: QWidget* m_widget; }; diff --git a/src/sip/twitter/twitterconfigwidget.cpp b/src/sip/twitter/twitterconfigwidget.cpp index 115147cd9..ddf5e89df 100644 --- a/src/sip/twitter/twitterconfigwidget.cpp +++ b/src/sip/twitter/twitterconfigwidget.cpp @@ -132,6 +132,7 @@ TwitterConfigWidget::authenticateVerifyReply( const QTweetUser &user ) m_plugin->connectPlugin( false ); emit twitterAuthed( true ); + emit sizeHintChanged(); } void @@ -161,6 +162,7 @@ TwitterConfigWidget::deauthenticateTwitter() ui->twitterTweetComboBox->setVisible( false ); emit twitterAuthed( false ); + emit sizeHintChanged(); } void diff --git a/src/sip/twitter/twitterconfigwidget.h b/src/sip/twitter/twitterconfigwidget.h index 5de30c7a7..d06c08737 100644 --- a/src/sip/twitter/twitterconfigwidget.h +++ b/src/sip/twitter/twitterconfigwidget.h @@ -45,6 +45,7 @@ public: signals: void twitterAuthed( bool authed ); + void sizeHintChanged(); private slots: void authDeauthTwitter(); void startPostGotTomahawkStatus(); From 59452f6163f2e98b22ac10a68aa068b7ed6514b3 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 2 Jun 2011 17:24:44 -0400 Subject: [PATCH 16/53] Try to avoid showing the window before placing it --- src/delegateconfigwrapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/delegateconfigwrapper.h b/src/delegateconfigwrapper.h index 6dc40700a..b7986ba88 100644 --- a/src/delegateconfigwrapper.h +++ b/src/delegateconfigwrapper.h @@ -28,7 +28,6 @@ class DelegateConfigWrapper : public QDialog public: DelegateConfigWrapper( QWidget* conf, const QString& title, QWidget* parent, Qt::WindowFlags flags = 0 ) : QDialog( parent, flags ), m_widget( conf ) { - m_widget->setVisible( true ); m_widget->setWindowFlags( Qt::Sheet ); setWindowTitle( title ); @@ -50,6 +49,7 @@ public: connect( conf, SIGNAL( sizeHintChanged() ), this, SLOT( updateSizeHint() ) ); #endif + m_widget->setVisible( true ); } public slots: void closed( QAbstractButton* b ) From e5cc13ac57bfb002573cf053dbdf843436e03243 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Thu, 2 Jun 2011 18:53:36 -0700 Subject: [PATCH 17/53] Fixes for style. --- .../infosystem/infoplugins/adium.mm | 13 +++--- .../infosystem/infoplugins/adiumplugin.cpp | 46 +++++++++---------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/adium.mm b/src/libtomahawk/infosystem/infoplugins/adium.mm index 576bc0624..08de70ab2 100644 --- a/src/libtomahawk/infosystem/infoplugins/adium.mm +++ b/src/libtomahawk/infosystem/infoplugins/adium.mm @@ -20,11 +20,12 @@ #import #import "adium.h" -void script( const char* status ) +void +script( const char* status ) { - NSString *stat = [NSString stringWithUTF8String:status]; - NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:stat]; - NSDictionary *errorDictionary; - NSAppleEventDescriptor *eventDescriptor = [appleScript executeAndReturnError:&errorDictionary]; - [appleScript release]; + NSString *stat = [NSString stringWithUTF8String:status]; + NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:stat]; + NSDictionary *errorDictionary; + NSAppleEventDescriptor *eventDescriptor = [appleScript executeAndReturnError:&errorDictionary]; + [appleScript release]; } diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index bbd8d7cfb..1c2771e8c 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -28,13 +28,12 @@ static void setStatus(const QString &status) { - QString adiumStatus = "tell application \"Adium\"\n"; - adiumStatus.append("set the status message of every account to \""); - adiumStatus.append(status); - adiumStatus.append("\"\nend tell\n"); - const char* scriptstr = adiumStatus.toUtf8(); - script( scriptstr ); - + QString adiumStatus = "tell application \"Adium\"\n"; + adiumStatus.append("set the status message of every account to \""); + adiumStatus.append(status); + adiumStatus.append("\"\nend tell\n"); + const char* scriptstr = adiumStatus.toUtf8(); + script( scriptstr ); } using namespace Tomahawk::InfoSystem; @@ -60,12 +59,12 @@ AdiumPlugin::~AdiumPlugin() void AdiumPlugin::settingsChanged() { - m_active = TomahawkSettings::instance()->nowPlayingEnabled(); - if( !m_active ) - setStatus( "" ); + m_active = TomahawkSettings::instance()->nowPlayingEnabled(); + if( !m_active ) + setStatus( "" ); } -void +void AdiumPlugin::getInfo( const QString caller, const InfoType type, const QVariant data, InfoCustomData customData ) { switch (type) @@ -84,25 +83,25 @@ AdiumPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoTyp qDebug() << Q_FUNC_INFO; if( !m_active ) - return; - + return; + switch ( type ) { case InfoNowPlaying: - audioStarted( input ); - break; + audioStarted( input ); + break; case InfoNowPaused: - audioPaused(); - break; + audioPaused(); + break; case InfoNowResumed: - audioResumed( input ); - break; + audioResumed( input ); + break; case InfoNowStopped: - audioStopped(); - break; + audioStopped(); + break; default: - return; + return; } } @@ -126,7 +125,7 @@ void AdiumPlugin::audioStarted( const QVariant &input ) setStatus( nowPlaying ); } -void +void AdiumPlugin::audioFinished( const QVariant &input ) { //qDebug() << Q_FUNC_INFO; @@ -152,4 +151,3 @@ void AdiumPlugin::audioResumed( const QVariant &input ) // TODO: audio resumed, so push update status to Adium with playing track audioStarted( input ); } - From 4619cd420aec0cfaa4d96a5159e33aab5df6021e Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Thu, 2 Jun 2011 21:13:57 -0700 Subject: [PATCH 18/53] More style fixes. --- .../infosystem/infoplugins/adiumplugin.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index 1c2771e8c..8d97f5107 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -106,7 +106,8 @@ AdiumPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoTyp } /** Audio state slots */ -void AdiumPlugin::audioStarted( const QVariant &input ) +void +AdiumPlugin::audioStarted( const QVariant &input ) //void AdiumPlugin::audioStarted( const Tomahawk::result_ptr& track ) { qDebug() << Q_FUNC_INFO; @@ -131,21 +132,24 @@ AdiumPlugin::audioFinished( const QVariant &input ) //qDebug() << Q_FUNC_INFO; } -void AdiumPlugin::audioStopped() +void +AdiumPlugin::audioStopped() { qDebug() << Q_FUNC_INFO; // TODO: audio stopped, so push update status to Adium that says "stopped" setStatus( "Stopped" ); } -void AdiumPlugin::audioPaused() +void +AdiumPlugin::audioPaused() { qDebug() << Q_FUNC_INFO; // TODO: audio paused, so push update status to Adium that says "paused" setStatus( "Paused" ); } -void AdiumPlugin::audioResumed( const QVariant &input ) +void +AdiumPlugin::audioResumed( const QVariant &input ) { qDebug() << Q_FUNC_INFO; // TODO: audio resumed, so push update status to Adium with playing track From 6f4b43f9ff18120dd9d11727c08ffc59bc66da85 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 3 Jun 2011 15:26:52 +0200 Subject: [PATCH 19/53] * Fixed AudioEngine deleting a sharedptr while it's being used by Phonon. --- src/libtomahawk/audio/audioengine.cpp | 12 ++--- src/libtomahawk/audio/dummytranscode.cpp | 64 ------------------------ src/libtomahawk/audio/dummytranscode.h | 63 ----------------------- src/tomahawk.protocol | 12 ----- 4 files changed, 6 insertions(+), 145 deletions(-) delete mode 100644 src/libtomahawk/audio/dummytranscode.cpp delete mode 100644 src/libtomahawk/audio/dummytranscode.h delete mode 100644 src/tomahawk.protocol diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index b8d7abad3..9baeaeb71 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -219,12 +219,6 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) if ( !m_input.isNull() || m_isPlayingHttp ) { - if ( !m_input.isNull() ) - { - m_input->close(); - m_input.clear(); - } - m_expectStop = true; } @@ -233,6 +227,12 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) m_mediaObject->setCurrentSource( io.data() ); m_mediaObject->currentSource().setAutoDelete( false ); m_isPlayingHttp = false; + + if ( !m_input.isNull() ) + { + m_input->close(); + m_input.clear(); + } } else { diff --git a/src/libtomahawk/audio/dummytranscode.cpp b/src/libtomahawk/audio/dummytranscode.cpp deleted file mode 100644 index 92b5efc6e..000000000 --- a/src/libtomahawk/audio/dummytranscode.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* === 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 "dummytranscode.h" - -#include - -DummyTranscode::DummyTranscode() - : m_init( false ) -{ - qDebug() << Q_FUNC_INFO; -} - - -DummyTranscode::~DummyTranscode() -{ - qDebug() << Q_FUNC_INFO; -} - - -void -DummyTranscode::processData( const QByteArray &buffer, bool finish ) -{ - Q_UNUSED( finish ); - m_buffer.append( buffer ); -// qDebug() << "DUMMYTRANSCODING:" << buffer.size(); - - if( !m_init && m_buffer.size() >= 16364 ) { - m_init = true; - emit streamInitialized( 44100, 2 ); - } -} - - -void -DummyTranscode::onSeek( int seconds ) -{ - Q_UNUSED( seconds ); - m_buffer.clear(); -} - - -void -DummyTranscode::clearBuffers() -{ - m_buffer.clear(); - m_init = false; -} - diff --git a/src/libtomahawk/audio/dummytranscode.h b/src/libtomahawk/audio/dummytranscode.h deleted file mode 100644 index d38774ffd..000000000 --- a/src/libtomahawk/audio/dummytranscode.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - - Copyright (C) 2011 Leo Franchi - - This program 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. - - This program 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 this program. If not, see . -*/ - - -#ifndef DUMMYTRANSCODE_H -#define DUMMYTRANSCODE_H - -#include "audio/transcodeinterface.h" -#include "dllmacro.h" - -#define _BUFFER_PREFERRED 32768 - -class DLLEXPORT DummyTranscode : public TranscodeInterface -{ - Q_OBJECT - -public: - DummyTranscode(); - virtual ~DummyTranscode(); - - const QStringList supportedTypes() const { QStringList l; l << "audio/basic"; return l; } - - int needData() { return true; } // always eats data - bool haveData() { return !m_buffer.isEmpty(); } - - unsigned int preferredDataSize() { return _BUFFER_PREFERRED; } - - QByteArray data() { QByteArray b = m_buffer; m_buffer.clear(); return b; } - - virtual void setBufferCapacity( int bytes ) { m_bufferCapacity = bytes; } - int bufferSize() { return m_buffer.size(); } - -public slots: - virtual void clearBuffers(); - virtual void onSeek( int seconds ); - virtual void processData( const QByteArray& data, bool finish ); - -signals: - void streamInitialized( long sampleRate, int channels ); - void timeChanged( int seconds ); - -private: - QByteArray m_buffer; - int m_bufferCapacity; - bool m_init; -}; - -#endif // DUMMYTRANSCODE_H diff --git a/src/tomahawk.protocol b/src/tomahawk.protocol deleted file mode 100644 index 3a393aa61..000000000 --- a/src/tomahawk.protocol +++ /dev/null @@ -1,12 +0,0 @@ -[Protocol] -exec=/home/leo/kde/tomahawk/build/tomahawk "%u" -protocol=tomahawk -input=none -output=none -helper=true -listing= -reading=false -writing=false -makedir=false -deleting=false - From aed838193feb1a1b490217b99be0dd3172c9ee0c Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 3 Jun 2011 11:01:27 -0400 Subject: [PATCH 20/53] See if defines are causing the twitter issues on Win --- src/sip/twitter/tomahawkoauthtwitter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sip/twitter/tomahawkoauthtwitter.cpp b/src/sip/twitter/tomahawkoauthtwitter.cpp index 144ce8c8c..7afb76da4 100644 --- a/src/sip/twitter/tomahawkoauthtwitter.cpp +++ b/src/sip/twitter/tomahawkoauthtwitter.cpp @@ -6,7 +6,7 @@ #define CONSUMER_SECRET "zXSjU6bjrvg6UVMJX4JufqHyjj3iextY14SR9uBEAo" TomahawkOAuthTwitter::TomahawkOAuthTwitter( QNetworkAccessManager *nam, QObject* parent ) - : OAuthTwitter( CONSUMER_KEY, CONSUMER_SECRET, parent ) + : OAuthTwitter( QString( "C4v4Wfa21rfIDck4HMR3A" ), QString( "zXSjU6bjrvg6UVMJX4JufqHyjj3iextY14SR9uBEAo" ), parent ) { setNetworkAccessManager( nam ); } From 95e2b845595765a5b3a9d1437614f89f9a85dd0a Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 3 Jun 2011 11:05:01 -0400 Subject: [PATCH 21/53] No sense having it in two places... --- src/sip/twitter/tomahawkoauthtwitter.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sip/twitter/tomahawkoauthtwitter.cpp b/src/sip/twitter/tomahawkoauthtwitter.cpp index 7afb76da4..976d4210f 100644 --- a/src/sip/twitter/tomahawkoauthtwitter.cpp +++ b/src/sip/twitter/tomahawkoauthtwitter.cpp @@ -2,9 +2,6 @@ #include #include -#define CONSUMER_KEY "C4v4Wfa21rfIDck4HMR3A" -#define CONSUMER_SECRET "zXSjU6bjrvg6UVMJX4JufqHyjj3iextY14SR9uBEAo" - TomahawkOAuthTwitter::TomahawkOAuthTwitter( QNetworkAccessManager *nam, QObject* parent ) : OAuthTwitter( QString( "C4v4Wfa21rfIDck4HMR3A" ), QString( "zXSjU6bjrvg6UVMJX4JufqHyjj3iextY14SR9uBEAo" ), parent ) { From c2ffbbc5ac3265a35e62380e7bb5db0a6b276470 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 3 Jun 2011 11:07:53 -0400 Subject: [PATCH 22/53] Fix compile, doh --- src/sip/twitter/tomahawkoauthtwitter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sip/twitter/tomahawkoauthtwitter.cpp b/src/sip/twitter/tomahawkoauthtwitter.cpp index 976d4210f..4778635b5 100644 --- a/src/sip/twitter/tomahawkoauthtwitter.cpp +++ b/src/sip/twitter/tomahawkoauthtwitter.cpp @@ -3,7 +3,7 @@ #include TomahawkOAuthTwitter::TomahawkOAuthTwitter( QNetworkAccessManager *nam, QObject* parent ) - : OAuthTwitter( QString( "C4v4Wfa21rfIDck4HMR3A" ), QString( "zXSjU6bjrvg6UVMJX4JufqHyjj3iextY14SR9uBEAo" ), parent ) + : OAuthTwitter( QByteArray( "C4v4Wfa21rfIDck4HMR3A" ), QByteArray( "zXSjU6bjrvg6UVMJX4JufqHyjj3iextY14SR9uBEAo" ), parent ) { setNetworkAccessManager( nam ); } From 34d9a723dd23da3cdbb1c162476b3926ac82e92c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 4 Jun 2011 14:42:54 +0200 Subject: [PATCH 23/53] * Fixed potential memleak. --- src/libtomahawk/audio/audioengine.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 9baeaeb71..e3cf26096 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -227,12 +227,6 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) m_mediaObject->setCurrentSource( io.data() ); m_mediaObject->currentSource().setAutoDelete( false ); m_isPlayingHttp = false; - - if ( !m_input.isNull() ) - { - m_input->close(); - m_input.clear(); - } } else { @@ -247,6 +241,11 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) m_isPlayingHttp = true; } + if ( !m_input.isNull() ) + { + m_input->close(); + m_input.clear(); + } m_input = io; m_mediaObject->play(); emit started( m_currentTrack ); @@ -261,7 +260,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowPlaying, QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) ); - + } } From 2d3f712f957588c5389692f0a47ba4e2fb7c3811 Mon Sep 17 00:00:00 2001 From: Ruslan Nigmatullin Date: Sat, 4 Jun 2011 23:48:27 +0600 Subject: [PATCH 24/53] Fixes due to changed Jreen API --- src/sip/jabber/avatarmanager.cpp | 16 +++++---- src/sip/jabber/avatarmanager.h | 2 +- src/sip/jabber/jabber.cpp | 37 ++++++++++++-------- src/sip/jabber/jabber.h | 2 +- src/sip/jabber/tomahawksipmessage.h | 4 +-- src/sip/jabber/tomahawksipmessagefactory.cpp | 8 ++--- src/sip/jabber/tomahawksipmessagefactory.h | 6 ++-- 7 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/sip/jabber/avatarmanager.cpp b/src/sip/jabber/avatarmanager.cpp index 204ba8c6f..b1abde919 100644 --- a/src/sip/jabber/avatarmanager.cpp +++ b/src/sip/jabber/avatarmanager.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -20,8 +21,8 @@ AvatarManager::AvatarManager(Jreen::Client *client) : m_cachedAvatars = m_cacheDir.entryList(); connect(m_client, SIGNAL(serverFeaturesReceived(QSet)), SLOT(onNewConnection())); - connect(m_client, SIGNAL(newPresence(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence))); - connect(m_client, SIGNAL(newIQ(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); + connect(m_client, SIGNAL(presenceReceived(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence))); + connect(m_client, SIGNAL(iqReceived(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); connect(this, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString))); } @@ -42,12 +43,13 @@ void AvatarManager::fetchVCard(const QString &jid) Jreen::IQ iq(Jreen::IQ::Get, jid ); iq.addExtension(new Jreen::VCard()); - m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), 0 ); + Jreen::IQReply *reply = m_client->send(iq); + connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); } void AvatarManager::onNewPresence(const Jreen::Presence& presence) { - Jreen::VCardUpdate::Ptr update = presence.findExtension(); + Jreen::VCardUpdate::Ptr update = presence.payload(); if(update) { // qDebug() << "vcard: found update for" << presence.from().full(); @@ -74,9 +76,9 @@ void AvatarManager::onNewPresence(const Jreen::Presence& presence) } } -void AvatarManager::onNewIq(const Jreen::IQ& iq, int context) +void AvatarManager::onNewIq(const Jreen::IQ& iq) { - Jreen::VCard *vcard = iq.findExtension().data(); + Jreen::VCard::Ptr vcard = iq.payload(); if(vcard) { iq.accept(); @@ -119,7 +121,7 @@ void AvatarManager::onNewIq(const Jreen::IQ& iq, int context) // qDebug() << Q_FUNC_INFO << "got own vcard"; Jreen::Presence presence = m_client->presence(); - Jreen::VCardUpdate::Ptr update = presence.findExtension(); + Jreen::VCardUpdate::Ptr update = presence.payload(); if (update->photoHash() != avatarHash) { qDebug() << Q_FUNC_INFO << "Updating own presence..."; diff --git a/src/sip/jabber/avatarmanager.h b/src/sip/jabber/avatarmanager.h index a1a43d46c..fc022f1b4 100644 --- a/src/sip/jabber/avatarmanager.h +++ b/src/sip/jabber/avatarmanager.h @@ -23,7 +23,7 @@ signals: private slots: void onNewPresence( const Jreen::Presence& presence ); - void onNewIq(const Jreen::IQ &iq, int context = 0 ); + void onNewIq(const Jreen::IQ &iq); void onNewConnection(); void onNewAvatar( const QString &jid ); diff --git a/src/sip/jabber/jabber.cpp b/src/sip/jabber/jabber.cpp index 94fafa734..eece626f1 100644 --- a/src/sip/jabber/jabber.cpp +++ b/src/sip/jabber/jabber.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -91,7 +92,7 @@ JabberPlugin::JabberPlugin( const QString& pluginId ) m_client = new Jreen::Client( jid, m_currentPassword ); setupClientHelper(); - m_client->registerStanzaExtension(new TomahawkSipMessageFactory); + m_client->registerPayload(new TomahawkSipMessageFactory); m_currentResource = QString::fromAscii( "tomahawk%1" ).arg( QString::number( qrand() % 10000 ) ); m_client->setResource( m_currentResource ); @@ -117,7 +118,7 @@ JabberPlugin::JabberPlugin( const QString& pluginId ) m_client->disco()->addFeature( TOMAHAWK_FEATURE ); // setup caps node, legacy peer detection - used before 0.1 - Jreen::Capabilities::Ptr caps = m_client->presence().findExtension(); + Jreen::Capabilities::Ptr caps = m_client->presence().payload(); caps->setNode( TOMAHAWK_CAP_NODE_NAME ); //FIXME: caps->setVersion( TOMAHAWK_VERSION ); @@ -129,9 +130,9 @@ JabberPlugin::JabberPlugin( const QString& pluginId ) // setup slots connect(m_client, SIGNAL(serverFeaturesReceived(QSet)), SLOT(onConnect())); connect(m_client, SIGNAL(disconnected(Jreen::Client::DisconnectReason)), SLOT(onDisconnect(Jreen::Client::DisconnectReason))); - connect(m_client, SIGNAL(newMessage(Jreen::Message)), SLOT(onNewMessage(Jreen::Message))); + connect(m_client, SIGNAL(messageReceived(Jreen::Message)), SLOT(onNewMessage(Jreen::Message))); - connect(m_client, SIGNAL(newIQ(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); + connect(m_client, SIGNAL(iqReceived(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); connect(m_roster, SIGNAL(presenceReceived(Jreen::RosterItem::Ptr,Jreen::Presence)), SLOT(onPresenceReceived(Jreen::RosterItem::Ptr,Jreen::Presence))); @@ -445,8 +446,9 @@ JabberPlugin::sendMsg(const QString& to, const QString& msg) qDebug() << "Send sip messsage to " << to; Jreen::IQ iq( Jreen::IQ::Set, to ); iq.addExtension( sipMessage ); - - m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), SipMessageSent ); + Jreen::IQReply *reply = m_client->send(iq); + reply->setData(SipMessageSent); + connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); } void @@ -648,7 +650,7 @@ void JabberPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const } // ignore anyone not Running tomahawk: - Jreen::Capabilities::Ptr caps = presence.findExtension(); + Jreen::Capabilities::Ptr caps = presence.payload(); /* Disabled this, because it's somewhat ugly and we should rely on nothing but the features if ( caps && ( caps->node() == TOMAHAWK_CAP_NODE_NAME ) ) { @@ -666,8 +668,10 @@ void JabberPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const Jreen::IQ featuresIq( Jreen::IQ::Get, jid ); featuresIq.addExtension( new Jreen::Disco::Info( node ) ); - - m_client->send( featuresIq, this, SLOT( onNewIq( Jreen::IQ, int ) ), RequestDisco ); + + Jreen::IQReply *reply = m_client->send(featuresIq); + reply->setData(RequestDisco); + connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); } else if( !caps ) { @@ -761,15 +765,18 @@ JabberPlugin::onSubscriptionRequestConfirmed( int result ) m_roster->allowSubscription( jid, allowSubscription == QMessageBox::Yes ); } -void JabberPlugin::onNewIq(const Jreen::IQ& iq, int context) +void JabberPlugin::onNewIq(const Jreen::IQ& iq) { if ( m_state != Connected ) return; + Jreen::IQReply *reply = qobject_cast(sender()); + int context = reply ? reply->data().toInt() : NoContext; + if( context == RequestDisco ) { // qDebug() << Q_FUNC_INFO << "Received disco IQ..."; - Jreen::Disco::Info *discoInfo = iq.findExtension().data(); + Jreen::Disco::Info *discoInfo = iq.payload().data(); if(!discoInfo) return; iq.accept(); @@ -803,7 +810,7 @@ void JabberPlugin::onNewIq(const Jreen::IQ& iq, int context) } else if(context == RequestVersion) { - Jreen::SoftwareVersion* softwareVersion = iq.findExtension().data(); + Jreen::SoftwareVersion::Ptr softwareVersion = iq.payload(); if( softwareVersion ) { QString versionString = QString("%1 %2 %3").arg( softwareVersion->name(), softwareVersion->os(), softwareVersion->version() ); @@ -825,7 +832,7 @@ void JabberPlugin::onNewIq(const Jreen::IQ& iq, int context) }*/ else { - TomahawkSipMessage *sipMessage = iq.findExtension().data(); + TomahawkSipMessage::Ptr sipMessage = iq.payload(); if(sipMessage) { iq.accept(); @@ -910,7 +917,9 @@ void JabberPlugin::handlePeerStatus(const Jreen::JID& jid, Jreen::Presence::Type // request software version Jreen::IQ versionIq( Jreen::IQ::Get, jid ); versionIq.addExtension( new Jreen::SoftwareVersion() ); - m_client->send( versionIq, this, SLOT( onNewIq( Jreen::IQ, int ) ), RequestVersion ); + Jreen::IQReply *reply = m_client->send(versionIq); + reply->setData(RequestVersion); + connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); return; } diff --git a/src/sip/jabber/jabber.h b/src/sip/jabber/jabber.h index 89b067525..9d25ff2e8 100644 --- a/src/sip/jabber/jabber.h +++ b/src/sip/jabber/jabber.h @@ -113,7 +113,7 @@ private slots: { qDebug() << e; } - void onNewIq( const Jreen::IQ &iq, int context = NoContext ); + void onNewIq( const Jreen::IQ &iq ); void onNewAvatar( const QString &jid ); private: diff --git a/src/sip/jabber/tomahawksipmessage.h b/src/sip/jabber/tomahawksipmessage.h index 70289750e..bf1fb73f2 100644 --- a/src/sip/jabber/tomahawksipmessage.h +++ b/src/sip/jabber/tomahawksipmessage.h @@ -8,9 +8,9 @@ #include "../sipdllmacro.h" class TomahawkSipMessagePrivate; -class SIPDLLEXPORT TomahawkSipMessage : public Jreen::StanzaExtension +class SIPDLLEXPORT TomahawkSipMessage : public Jreen::Payload { - J_EXTENSION(TomahawkSipMessage, "") + J_PAYLOAD(TomahawkSipMessage) Q_DECLARE_PRIVATE(TomahawkSipMessage) public: // sets visible to true diff --git a/src/sip/jabber/tomahawksipmessagefactory.cpp b/src/sip/jabber/tomahawksipmessagefactory.cpp index 5c21edf05..1c39d3739 100644 --- a/src/sip/jabber/tomahawksipmessagefactory.cpp +++ b/src/sip/jabber/tomahawksipmessagefactory.cpp @@ -86,7 +86,7 @@ void TomahawkSipMessageFactory::handleCharacterData(const QStringRef &text) Q_UNUSED(text); } -void TomahawkSipMessageFactory::serialize(StanzaExtension *extension, QXmlStreamWriter *writer) +void TomahawkSipMessageFactory::serialize(Payload *extension, QXmlStreamWriter *writer) { TomahawkSipMessage *sipMessage = se_cast(extension); @@ -118,10 +118,10 @@ void TomahawkSipMessageFactory::serialize(StanzaExtension *extension, QXmlStream writer->writeEndElement(); } -StanzaExtension::Ptr TomahawkSipMessageFactory::createExtension() +Payload::Ptr TomahawkSipMessageFactory::createPayload() { if(m_visible) - return StanzaExtension::Ptr(new TomahawkSipMessage(m_ip, m_port, m_uniqname, m_key)); + return Payload::Ptr(new TomahawkSipMessage(m_ip, m_port, m_uniqname, m_key)); else - return StanzaExtension::Ptr(new TomahawkSipMessage()); + return Payload::Ptr(new TomahawkSipMessage()); } diff --git a/src/sip/jabber/tomahawksipmessagefactory.h b/src/sip/jabber/tomahawksipmessagefactory.h index a89027c77..626eefdc6 100644 --- a/src/sip/jabber/tomahawksipmessagefactory.h +++ b/src/sip/jabber/tomahawksipmessagefactory.h @@ -23,7 +23,7 @@ #include "../sipdllmacro.h" -class SIPDLLEXPORT TomahawkSipMessageFactory : public Jreen::StanzaExtensionFactory +class SIPDLLEXPORT TomahawkSipMessageFactory : public Jreen::PayloadFactory { public: TomahawkSipMessageFactory(); @@ -33,8 +33,8 @@ public: void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); void handleEndElement(const QStringRef &name, const QStringRef &uri); void handleCharacterData(const QStringRef &text); - void serialize(Jreen::StanzaExtension *extension, QXmlStreamWriter *writer); - Jreen::StanzaExtension::Ptr createExtension(); + void serialize(Jreen::Payload *extension, QXmlStreamWriter *writer); + Jreen::Payload::Ptr createPayload(); private: enum State { AtNowhere, AtTransport, AtCandidate } m_state; int m_depth; From 2e9dc426962635ff05c8484a587c6dd4481966a3 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 4 Jun 2011 20:47:45 +0200 Subject: [PATCH 25/53] * Added basic search widget. --- src/CMakeLists.txt | 1 + src/libtomahawk/CMakeLists.txt | 3 + .../database/databasecommand_resolve.cpp | 167 ++++++++++++++++-- .../database/databasecommand_resolve.h | 5 +- src/libtomahawk/pipeline.cpp | 4 +- .../playlist/topbar/searchlineedit.h | 2 +- src/libtomahawk/playlist/trackproxymodel.cpp | 2 +- src/libtomahawk/query.cpp | 26 +++ src/libtomahawk/query.h | 15 +- src/libtomahawk/viewmanager.cpp | 9 +- src/libtomahawk/widgets/newplaylistwidget.cpp | 2 - src/resolvers/qtscriptresolver.cpp | 23 ++- src/resolvers/scriptresolver.cpp | 18 +- src/tomahawkwindow.cpp | 41 ++++- src/tomahawkwindow.h | 5 + 15 files changed, 281 insertions(+), 42 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c0c1223b..99bceddc3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -122,6 +122,7 @@ SET( tomahawkUI ${tomahawkUI} diagnosticsdialog.ui stackedsettingsdialog.ui proxydialog.ui + searchwidget.ui audiocontrols.ui ) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index cea658e02..a0027b2d1 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -161,6 +161,7 @@ set( libSources utils/xspfgenerator.cpp widgets/newplaylistwidget.cpp + widgets/searchwidget.cpp widgets/playlisttypeselectordlg.cpp widgets/welcomewidget.cpp widgets/welcomeplaylistmodel.cpp @@ -325,6 +326,7 @@ set( libHeaders utils/xspfgenerator.h widgets/newplaylistwidget.h + widgets/searchwidget.h widgets/playlisttypeselectordlg.h widgets/welcomewidget.h widgets/welcomeplaylistmodel.h @@ -343,6 +345,7 @@ set( libHeaders_NoMOC set( libUI ${libUI} widgets/playlisttypeselectordlg.ui widgets/newplaylistwidget.ui + widgets/searchwidget.ui widgets/welcomewidget.ui widgets/infowidgets/sourceinfowidget.ui playlist/topbar/topbar.ui diff --git a/src/libtomahawk/database/databasecommand_resolve.cpp b/src/libtomahawk/database/databasecommand_resolve.cpp index 18975a8a5..876a9685f 100644 --- a/src/libtomahawk/database/databasecommand_resolve.cpp +++ b/src/libtomahawk/database/databasecommand_resolve.cpp @@ -36,23 +36,35 @@ DatabaseCommand_Resolve::DatabaseCommand_Resolve( const query_ptr& query ) void DatabaseCommand_Resolve::exec( DatabaseImpl* lib ) { - QList res; if ( !m_query->resultHint().isEmpty() ) { qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint(); Tomahawk::result_ptr result = lib->resultFromHint( m_query ); -/* qDebug() << "Result null:" << result.isNull(); - qDebug() << "Collection null:" << result->collection().isNull(); - qDebug() << "Source null:" << result->collection()->source().isNull();*/ + /* qDebug() << "Result null:" << result.isNull(); + * qDebug() << "Collection null:" << result->collection().isNull(); + * qDebug() << "Source null:" << result->collection()->source().isNull();*/ if ( !result.isNull() && !result->collection().isNull() && result->collection()->source()->isOnline() ) { + QList res; res << result; emit results( m_query->id(), res ); return; } } + if ( m_query->isFullTextQuery() ) + fullTextResolve( lib ); + else + resolve( lib ); +} + + +void +DatabaseCommand_Resolve::resolve( DatabaseImpl* lib ) +{ + QList res; + /* Resolving is a 2 stage process. 1) find list of trk/art/alb IDs that are reasonable matches to the metadata given @@ -64,10 +76,10 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib ) // STEP 1 QList< int > artists = lib->searchTable( "artist", m_query->artist(), 10 ); - QList< int > tracks = lib->searchTable( "track", m_query->track(), 10 ); - QList< int > albums = lib->searchTable( "album", m_query->album(), 10 ); + QList< int > tracks = lib->searchTable( "track", m_query->track(), 10 ); + QList< int > albums = lib->searchTable( "album", m_query->album(), 10 ); - if( artists.length() == 0 || tracks.length() == 0 ) + if ( artists.length() == 0 || tracks.length() == 0 ) { qDebug() << "No candidates found in first pass, aborting resolve" << m_query->artist() << m_query->track(); emit results( m_query->id(), res ); @@ -83,6 +95,9 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib ) foreach( int i, tracks ) trksl.append( QString::number( i ) ); + QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) ); + QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) ); + QString sql = QString( "SELECT " "url, mtime, size, md5, mimetype, duration, bitrate, file_join.artist, file_join.album, file_join.track, " "artist.name as artname, " @@ -98,10 +113,9 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib ) "artist.id = file_join.artist AND " "track.id = file_join.track AND " "file.id = file_join.file AND " - "file_join.artist IN (%1) AND " - "file_join.track IN (%2)" ) - .arg( artsl.join( "," ) ) - .arg( trksl.join( "," ) ); + "(%1 AND %2)" ) + .arg( artsToken ) + .arg( trksToken ); files_query.prepare( sql ); files_query.exec(); @@ -160,7 +174,136 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib ) float score = how_similar( m_query, result ); result->setScore( score ); - if( score < MINSCORE ) + if ( m_query->fullTextQuery().isEmpty() && score < MINSCORE ) + continue; + + result->setCollection( s->collection() ); + res << result; + } + + emit results( m_query->id(), res ); +} + + +void +DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib ) +{ + QList res; + + /* + * Resolving is a 2 stage process. + * 1) find list of trk/art/alb IDs that are reasonable matches to the metadata given + * 2) find files in database by permitted sources and calculate score, ignoring + * results that are less than MINSCORE + */ + + typedef QPair scorepair_t; + + // STEP 1 + QList< int > artists = lib->searchTable( "artist", m_query->fullTextQuery(), 10 ); + QList< int > tracks = lib->searchTable( "track", m_query->fullTextQuery(), 10 ); + QList< int > albums = lib->searchTable( "album", m_query->fullTextQuery(), 10 ); + + if ( artists.length() == 0 && tracks.length() == 0 && albums.length() == 0 ) + { + qDebug() << "No candidates found in first pass, aborting resolve" << m_query->artist() << m_query->track(); + emit results( m_query->id(), res ); + return; + } + + // STEP 2 + TomahawkSqlQuery files_query = lib->newquery(); + + QStringList artsl, trksl, albsl; + foreach( int i, artists ) + artsl.append( QString::number( i ) ); + foreach( int i, tracks ) + trksl.append( QString::number( i ) ); + foreach( int i, albums ) + albsl.append( QString::number( i ) ); + + QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) ); + QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) ); + QString albsToken = QString( "file_join.album IN (%1)" ).arg( albsl.join( "," ) ); + + QString sql = QString( "SELECT " + "url, mtime, size, md5, mimetype, duration, bitrate, file_join.artist, file_join.album, file_join.track, " + "artist.name as artname, " + "album.name as albname, " + "track.name as trkname, " + "file.source, " + "file_join.albumpos, " + "artist.id as artid, " + "album.id as albid " + "FROM file, file_join, artist, track " + "LEFT JOIN album ON album.id = file_join.album " + "WHERE " + "artist.id = file_join.artist AND " + "track.id = file_join.track AND " + "file.id = file_join.file AND " + "(%1 OR %2 OR %3)" ) + .arg( artists.length() > 0 ? artsToken : QString( "0" ) ) + .arg( tracks.length() > 0 ? trksToken : QString( "0" ) ) + .arg( albums.length() > 0 ? albsToken : QString( "0" ) ); + + files_query.prepare( sql ); + files_query.exec(); + + while( files_query.next() ) + { + Tomahawk::result_ptr result( new Tomahawk::Result() ); + source_ptr s; + + const QString url_str = files_query.value( 0 ).toString(); + if( files_query.value( 13 ).toUInt() == 0 ) + { + s = SourceList::instance()->getLocal(); + result->setUrl( url_str ); + } + else + { + s = SourceList::instance()->get( files_query.value( 13 ).toUInt() ); + if( s.isNull() ) + { + qDebug() << "WTF: Could not find source" << files_query.value( 13 ).toUInt(); + continue; + } + + result->setUrl( QString( "servent://%1\t%2" ).arg( s->userName() ).arg( url_str ) ); + } + + Tomahawk::artist_ptr artist = Tomahawk::Artist::get( files_query.value( 15 ).toUInt(), files_query.value( 10 ).toString() ); + Tomahawk::album_ptr album = Tomahawk::Album::get( files_query.value( 16 ).toUInt(), files_query.value( 11 ).toString(), artist ); + + result->setModificationTime( files_query.value( 1 ).toUInt() ); + result->setSize( files_query.value( 2 ).toUInt() ); + result->setMimetype( files_query.value( 4 ).toString() ); + result->setDuration( files_query.value( 5 ).toUInt() ); + result->setBitrate( files_query.value( 6 ).toUInt() ); + result->setArtist( artist ); + result->setAlbum( album ); + result->setTrack( files_query.value( 12 ).toString() ); + result->setRID( uuid() ); + result->setAlbumPos( files_query.value( 14 ).toUInt() ); + result->setId( files_query.value( 9 ).toUInt() ); + result->setYear( files_query.value( 17 ).toUInt() ); + + TomahawkSqlQuery attrQuery = lib->newquery(); + QVariantMap attr; + + attrQuery.prepare( "SELECT k, v FROM track_attributes WHERE id = ?" ); + attrQuery.bindValue( 0, result->dbid() ); + attrQuery.exec(); + while ( attrQuery.next() ) + { + attr[ attrQuery.value( 0 ).toString() ] = attrQuery.value( 1 ).toString(); + } + + result->setAttributes( attr ); + + float score = how_similar( m_query, result ); + result->setScore( score ); + if ( m_query->fullTextQuery().isEmpty() && score < MINSCORE ) continue; result->setCollection( s->collection() ); diff --git a/src/libtomahawk/database/databasecommand_resolve.h b/src/libtomahawk/database/databasecommand_resolve.h index 8c194451e..bc46d0de5 100644 --- a/src/libtomahawk/database/databasecommand_resolve.h +++ b/src/libtomahawk/database/databasecommand_resolve.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 @@ -44,6 +44,9 @@ signals: public slots: private: + void fullTextResolve( DatabaseImpl* lib ); + void resolve( DatabaseImpl* lib ); + Tomahawk::query_ptr m_query; float how_similar( const Tomahawk::query_ptr& q, const Tomahawk::result_ptr& r ); diff --git a/src/libtomahawk/pipeline.cpp b/src/libtomahawk/pipeline.cpp index 70b7edcdf..e99755887 100644 --- a/src/libtomahawk/pipeline.cpp +++ b/src/libtomahawk/pipeline.cpp @@ -190,7 +190,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results ) m_rids.insert( r->id(), r ); } - if ( q->solved() ) + if ( q->solved() && !q->isFullTextQuery() ) { // qDebug() << "FINISHED RESOLVING EARLY" << q->toString(); q->onResolvingFinished(); @@ -206,7 +206,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results ) if ( decQIDState( q ) == 0 ) { - if ( !q->solved() ) + if ( !q->solved() || q->isFullTextQuery() ) q->onResolvingFinished(); if ( m_qidsTimeout.contains( q->id() ) ) diff --git a/src/libtomahawk/playlist/topbar/searchlineedit.h b/src/libtomahawk/playlist/topbar/searchlineedit.h index bdfeddc94..4b7859881 100644 --- a/src/libtomahawk/playlist/topbar/searchlineedit.h +++ b/src/libtomahawk/playlist/topbar/searchlineedit.h @@ -33,7 +33,7 @@ class ClearButton; class SearchButton; -class SearchLineEdit : public LineEdit +class DLLEXPORT SearchLineEdit : public LineEdit { Q_OBJECT diff --git a/src/libtomahawk/playlist/trackproxymodel.cpp b/src/libtomahawk/playlist/trackproxymodel.cpp index 91f082ecd..dbc22c543 100644 --- a/src/libtomahawk/playlist/trackproxymodel.cpp +++ b/src/libtomahawk/playlist/trackproxymodel.cpp @@ -174,7 +174,7 @@ TrackProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParen if ( q->numResults() ) r = q->results().first(); - if ( !m_showOfflineResults && !r.isNull() && !r->collection()->source()->isOnline() ) + if ( !m_showOfflineResults && !r.isNull() && !r->isOnline() ) return false; if ( filterRegExp().isEmpty() ) diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index 413ab4c96..96dad8007 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -42,6 +42,17 @@ Query::get( const QString& artist, const QString& track, const QString& album, c } +query_ptr +Query::get( const QString& query, const QID& qid ) +{ + query_ptr q = query_ptr( new Query( query, qid ) ); + + if ( !qid.isEmpty() ) + Pipeline::instance()->resolve( q ); + return q; +} + + Query::Query( const QString& artist, const QString& track, const QString& album, const QID& qid ) : m_solved( false ) , m_playable( false ) @@ -59,6 +70,21 @@ Query::Query( const QString& artist, const QString& track, const QString& album, } +Query::Query( const QString& query, const QID& qid ) + : m_solved( false ) + , m_playable( false ) + , m_resolveFinished( false ) + , m_qid( qid ) + , m_fullTextQuery( query ) + , m_duration( -1 ) +{ + if ( !qid.isEmpty() ) + { + connect( Database::instance(), SIGNAL( indexReady() ), SLOT( refreshResults() ), Qt::QueuedConnection ); + } +} + + void Query::addResults( const QList< Tomahawk::result_ptr >& newresults ) { diff --git a/src/libtomahawk/query.h b/src/libtomahawk/query.h index ddc447729..59a218f45 100644 --- a/src/libtomahawk/query.h +++ b/src/libtomahawk/query.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 @@ -46,7 +46,10 @@ friend class ::DatabaseCommand_LoadPlaylistEntries; public: static query_ptr get( const QString& artist, const QString& track, const QString& album, const QID& qid = QString() ); + static query_ptr get( const QString& query, const QID& qid ); + explicit Query( const QString& artist, const QString& track, const QString& album, const QID& qid ); + explicit Query( const QString& query, const QID& qid ); /// returns list of all results so far QList< result_ptr > results() const; @@ -64,8 +67,9 @@ public: /// true when any result has been found (score may be less than 1.0) bool playable() const { return m_playable; } + bool isFullTextQuery() const { return !m_fullTextQuery.isEmpty(); } bool resolvingFinished() const { return m_resolveFinished; } - + unsigned int lastPipelineWeight() const { return m_lastpipelineweight; } void setLastPipelineWeight( unsigned int w ) { m_lastpipelineweight = w; } @@ -75,7 +79,7 @@ public: void setResultHint( const QString& resultHint ) { m_resultHint = resultHint; } void setDuration( int duration ) { m_duration = duration; } void setResolveFinished( bool resolved ) { m_resolveFinished = resolved; } - + QVariant toVariant() const; QString toString() const; @@ -83,6 +87,7 @@ public: QString artist() const { return m_artist; } QString album() const { return m_album; } QString track() const { return m_track; } + QString fullTextQuery() const { return m_fullTextQuery; } int duration() const { return m_duration; } signals: @@ -92,7 +97,7 @@ signals: void resultsChanged(); void solvedStateChanged( bool state ); void resolvingFinished( bool hasResults ); - + public slots: /// (indirectly) called by resolver plugins when results are found void addResults( const QList< Tomahawk::result_ptr >& ); @@ -118,6 +123,8 @@ private: QString m_artist; QString m_album; QString m_track; + QString m_fullTextQuery; + int m_duration; QString m_resultHint; diff --git a/src/libtomahawk/viewmanager.cpp b/src/libtomahawk/viewmanager.cpp index 1fbd10fb9..806895722 100644 --- a/src/libtomahawk/viewmanager.cpp +++ b/src/libtomahawk/viewmanager.cpp @@ -584,7 +584,7 @@ ViewManager::setPage( ViewPage* page, bool trackHistory ) // save the old playlist shuffle state in config before we change playlists saveCurrentPlaylistSettings(); - + unlinkPlaylist(); if ( !m_pageHistory.contains( page ) ) @@ -630,6 +630,7 @@ ViewManager::setPage( ViewPage* page, bool trackHistory ) updateView(); } + bool ViewManager::isNewPlaylistPageVisible() const { @@ -661,7 +662,7 @@ ViewManager::saveCurrentPlaylistSettings() { TomahawkSettings* s = TomahawkSettings::instance(); Tomahawk::playlist_ptr pl = playlistForInterface( currentPlaylistInterface() ); - + if ( !pl.isNull() ) { s->setShuffleState( pl->guid(), currentPlaylistInterface()->shuffled() ); s->setRepeatMode( pl->guid(), currentPlaylistInterface()->repeatMode() ); @@ -726,7 +727,7 @@ ViewManager::updateView() m_infobar->setCaption( currentPage()->title() ); m_infobar->setDescription( currentPage()->description() ); m_infobar->setPixmap( currentPage()->pixmap() ); - + // turn on shuffle/repeat mode for the new playlist view if specified in config loadCurrentPlaylistSettings(); } @@ -739,7 +740,7 @@ ViewManager::loadCurrentPlaylistSettings() if ( !pl.isNull() ) { currentPlaylistInterface()->setShuffled( s->shuffleState( pl->guid() )); currentPlaylistInterface()->setRepeatMode( s->repeatMode( pl->guid() )); - } else { + } else { Tomahawk::dynplaylist_ptr dynPl = dynamicPlaylistForInterface( currentPlaylistInterface() ); if ( !dynPl.isNull() ) { currentPlaylistInterface()->setShuffled( s->shuffleState( dynPl->guid() )); diff --git a/src/libtomahawk/widgets/newplaylistwidget.cpp b/src/libtomahawk/widgets/newplaylistwidget.cpp index 30481b96b..2bb826b49 100644 --- a/src/libtomahawk/widgets/newplaylistwidget.cpp +++ b/src/libtomahawk/widgets/newplaylistwidget.cpp @@ -125,11 +125,9 @@ NewPlaylistWidget::suggestionsFound() m_suggestionsModel = new PlaylistModel( ui->suggestionsView ); ui->suggestionsView->setPlaylistModel( m_suggestionsModel ); - QList ql; foreach( const Tomahawk::query_ptr& query, m_queries ) { m_suggestionsModel->append( query ); - ql.append( query ); } loader->deleteLater(); diff --git a/src/resolvers/qtscriptresolver.cpp b/src/resolvers/qtscriptresolver.cpp index 4fe9704dc..a069ab5cf 100644 --- a/src/resolvers/qtscriptresolver.cpp +++ b/src/resolvers/qtscriptresolver.cpp @@ -75,11 +75,24 @@ QtScriptResolver::resolve( const Tomahawk::query_ptr& query ) } // qDebug() << Q_FUNC_INFO << query->toString(); - QString eval = QString( "resolve( '%1', '%2', '%3', '%4' );" ) - .arg( query->id().replace( "'", "\\'" ) ) - .arg( query->artist().replace( "'", "\\'" ) ) - .arg( query->album().replace( "'", "\\'" ) ) - .arg( query->track().replace( "'", "\\'" ) ); + QString eval; + + if ( !query->isFullTextQuery() ) + { + eval = QString( "resolve( '%1', '%2', '%3', '%4' );" ) + .arg( query->id().replace( "'", "\\'" ) ) + .arg( query->artist().replace( "'", "\\'" ) ) + .arg( query->album().replace( "'", "\\'" ) ) + .arg( query->track().replace( "'", "\\'" ) ); + } + else + { + eval = QString( "resolve( '%1', '%2', '%3', '%4' );" ) + .arg( query->id().replace( "'", "\\'" ) ) + .arg( query->fullTextQuery().replace( "'", "\\'" ) ) + .arg( QString() ) + .arg( QString() ); + } QList< Tomahawk::result_ptr > results; diff --git a/src/resolvers/scriptresolver.cpp b/src/resolvers/scriptresolver.cpp index 76e44d1f7..c9f6b9f48 100644 --- a/src/resolvers/scriptresolver.cpp +++ b/src/resolvers/scriptresolver.cpp @@ -208,12 +208,22 @@ ScriptResolver::resolve( const Tomahawk::query_ptr& query ) { QVariantMap m; m.insert( "_msgtype", "rq" ); - m.insert( "artist", query->artist() ); - m.insert( "track", query->track() ); - m.insert( "qid", query->id() ); + + if ( query->isFullTextQuery() ) + { + m.insert( "fulltext", query->fullTextQuery() ); + m.insert( "artist", query->artist() ); + m.insert( "track", query->fullTextQuery() ); + m.insert( "qid", query->id() ); + } + else + { + m.insert( "artist", query->artist() ); + m.insert( "track", query->track() ); + m.insert( "qid", query->id() ); + } const QByteArray msg = m_serializer.serialize( QVariant( m ) ); -// qDebug() << "ASKING SCRIPT RESOLVER TO RESOLVE:" << msg; sendMsg( msg ); } diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index c83332f70..1011b270c 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -18,6 +18,7 @@ #include "tomahawkwindow.h" #include "ui_tomahawkwindow.h" +#include "ui_searchwidget.h" #include "config.h" @@ -28,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +52,7 @@ #include "utils/widgetdragfilter.h" #include "utils/xspfloader.h" #include "widgets/newplaylistwidget.h" +#include "widgets/searchwidget.h" #include "widgets/playlisttypeselectordlg.h" #include "audiocontrols.h" @@ -74,6 +77,7 @@ using namespace Tomahawk; TomahawkWindow::TomahawkWindow( QWidget* parent ) : QMainWindow( parent ) , ui( new Ui::TomahawkWindow ) + , m_searchWidget( new Ui::SearchWidget ) , m_audioControls( new AudioControls( this ) ) , m_trayIcon( new TomahawkTrayIcon( this ) ) , m_sourcetree( 0 ) @@ -92,7 +96,9 @@ TomahawkWindow::TomahawkWindow( QWidget* parent ) connect( m_audioControls, SIGNAL( playPressed() ), pm, SLOT( onPlayClicked() ) ); connect( m_audioControls, SIGNAL( pausePressed() ), pm, SLOT( onPauseClicked() ) ); + m_searchBox = new QWidget(); ui->setupUi( this ); + m_searchWidget->setupUi( m_searchBox ); delete ui->sidebarWidget; delete ui->playlistWidget; @@ -186,6 +192,14 @@ TomahawkWindow::TomahawkWindow( QWidget* parent ) m_forwardAvailable = toolbar->addAction( QIcon( RESPATH "images/forward.png" ), tr( "Forward" ), ViewManager::instance(), SLOT( historyForward() ) ); m_forwardAvailable->setToolTip( tr( "Go forward one page" ) ); + m_searchWidget->searchEdit->setStyleSheet( "QLineEdit { border: 1px solid gray; border-radius: 6px; margin-right: 2px; }" ); +#ifdef Q_WS_MAC + ui->filterEdit->setAttribute( Qt::WA_MacShowFocusRect, 0 ); +#endif + + connect( m_searchWidget->searchEdit, SIGNAL( returnPressed() ), SLOT( onSearch() ) ); + toolbar->addWidget( m_searchBox ); + statusBar()->addPermanentWidget( m_audioControls, 1 ); // propagate sip menu @@ -488,14 +502,17 @@ TomahawkWindow::createPlaylist() PlaylistTypeSelectorDlg playlistSelectorDlg; int successfulReturn = playlistSelectorDlg.exec(); - if ( !playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn ) { - + if ( !playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn ) + { // only show if none is shown yet - if( !ViewManager::instance()->isNewPlaylistPageVisible() ) { + if ( !ViewManager::instance()->isNewPlaylistPageVisible() ) + { ViewManager::instance()->show( new NewPlaylistWidget() ); } - } else if ( playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn ) { + } + else if ( playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn ) + { // create Auto Playlist QString playlistName = playlistSelectorDlg.playlistName(); APP->mainWindow()->createAutomaticPlaylist( playlistName ); @@ -600,13 +617,23 @@ TomahawkWindow::checkForUpdates() } +void +TomahawkWindow::onSearch() +{ + ViewManager::instance()->show( new SearchWidget( m_searchWidget->searchEdit->text() ) ); + m_searchWidget->searchEdit->setText( QString() ); +} + + void TomahawkWindow::minimize() { if ( isMinimized() ) { showNormal(); - } else { + } + else + { showMinimized(); } } @@ -618,7 +645,9 @@ TomahawkWindow::maximize() if ( isMaximized() ) { showNormal(); - } else { + } + else + { showMaximized(); } } diff --git a/src/tomahawkwindow.h b/src/tomahawkwindow.h index e724f7313..a9799838a 100644 --- a/src/tomahawkwindow.h +++ b/src/tomahawkwindow.h @@ -38,6 +38,7 @@ class TomahawkTrayIcon; namespace Ui { class TomahawkWindow; + class SearchWidget; } class TomahawkWindow : public QMainWindow @@ -88,6 +89,8 @@ private slots: void onSipPluginAdded( SipPlugin* p ); void onSipPluginRemoved( SipPlugin* p ); + void onSearch(); + void minimize(); void maximize(); @@ -97,6 +100,8 @@ private: void setupSignals(); Ui::TomahawkWindow* ui; + Ui::SearchWidget* m_searchWidget; + QWidget* m_searchBox; AudioControls* m_audioControls; TomahawkTrayIcon* m_trayIcon; SourceTreeView* m_sourcetree; From 83ca3a1502c70525b32e484882041d727711e51b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 4 Jun 2011 20:50:49 +0200 Subject: [PATCH 26/53] * Forgot to add some search widgets. --- src/libtomahawk/widgets/searchwidget.cpp | 104 +++++++++++++++++++++++ src/libtomahawk/widgets/searchwidget.h | 77 +++++++++++++++++ src/libtomahawk/widgets/searchwidget.ui | 38 +++++++++ src/searchwidget.ui | 57 +++++++++++++ 4 files changed, 276 insertions(+) create mode 100644 src/libtomahawk/widgets/searchwidget.cpp create mode 100644 src/libtomahawk/widgets/searchwidget.h create mode 100644 src/libtomahawk/widgets/searchwidget.ui create mode 100644 src/searchwidget.ui diff --git a/src/libtomahawk/widgets/searchwidget.cpp b/src/libtomahawk/widgets/searchwidget.cpp new file mode 100644 index 000000000..34350f4df --- /dev/null +++ b/src/libtomahawk/widgets/searchwidget.cpp @@ -0,0 +1,104 @@ +/* === 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 "searchwidget.h" +#include "ui_searchwidget.h" + +#include +#include + +#include "utils/tomahawkutils.h" + +#include "viewmanager.h" +#include "playlist/playlistmodel.h" + +#include "widgets/overlaywidget.h" + +#include "sourcelist.h" + + +SearchWidget::SearchWidget( const QString& search, QWidget* parent ) + : QWidget( parent ) + , ui( new Ui::SearchWidget ) + , m_search( search ) +{ + ui->setupUi( this ); + + m_resultsModel = new PlaylistModel( ui->resultsView ); + ui->resultsView->setPlaylistModel( m_resultsModel ); + ui->resultsView->overlay()->setEnabled( false ); + + m_queries << Tomahawk::Query::get( search, uuid() ); + + foreach ( const Tomahawk::query_ptr& query, m_queries ) + { + connect( query.data(), SIGNAL( resultsAdded( QList ) ), SLOT( onResultsFound( QList ) ) ); + } + + connect( ui->buttonBox, SIGNAL( rejected() ), SLOT( cancel() ) ); +} + + +SearchWidget::~SearchWidget() +{ + delete ui; +} + + +void +SearchWidget::changeEvent( QEvent* e ) +{ + QWidget::changeEvent( e ); + switch ( e->type() ) + { + case QEvent::LanguageChange: + ui->retranslateUi( this ); + break; + + default: + break; + } +} + + +void +SearchWidget::onResultsFound( const QList& results ) +{ + foreach( const Tomahawk::result_ptr& result, results ) + { + if ( !result->collection().isNull() && !result->isOnline() ) + continue; + + QList< Tomahawk::result_ptr > rl; + rl << result; + + Tomahawk::query_ptr q = result->toQuery(); + q->addResults( rl ); + qDebug() << result->toString(); + + m_resultsModel->append( q ); + } +} + + +void +SearchWidget::cancel() +{ + emit destroyed( this ); + deleteLater(); +} diff --git a/src/libtomahawk/widgets/searchwidget.h b/src/libtomahawk/widgets/searchwidget.h new file mode 100644 index 000000000..2fbea9808 --- /dev/null +++ b/src/libtomahawk/widgets/searchwidget.h @@ -0,0 +1,77 @@ +/* === 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 SEARCHWIDGET_H +#define SEARCHWIDGET_H + +#include +#include + +#include "result.h" +#include "playlistinterface.h" +#include "viewpage.h" + +#include "dllmacro.h" + +class QPushButton; +class PlaylistModel; + +namespace Ui +{ + class SearchWidget; +} + +class DLLEXPORT SearchWidget : public QWidget, public Tomahawk::ViewPage +{ +Q_OBJECT + +public: + SearchWidget( const QString& search, QWidget* parent = 0 ); + ~SearchWidget(); + + virtual QWidget* widget() { return this; } + virtual PlaylistInterface* playlistInterface() const { return 0; } + + virtual QString title() const { return tr( "Search" ); } + virtual QString description() const { return tr( "Results for '%1'" ).arg( m_search ); } + + virtual bool showStatsBar() const { return false; } + + virtual bool jumpToCurrentTrack() { return false; } + +protected: + void changeEvent( QEvent* e ); + +signals: + void destroyed( QWidget* widget ); + +private slots: + void onResultsFound( const QList& results ); + + void cancel(); + +private: + Ui::SearchWidget *ui; + + QString m_search; + + PlaylistModel* m_resultsModel; + QList< Tomahawk::query_ptr > m_queries; +}; + +#endif // NEWPLAYLISTWIDGET_H diff --git a/src/libtomahawk/widgets/searchwidget.ui b/src/libtomahawk/widgets/searchwidget.ui new file mode 100644 index 000000000..7bace8edb --- /dev/null +++ b/src/libtomahawk/widgets/searchwidget.ui @@ -0,0 +1,38 @@ + + + SearchWidget + + + + 0 + 0 + 985 + 460 + + + + Qt::TabFocus + + + + + + + + + QDialogButtonBox::Cancel + + + + + + + + PlaylistView + QTreeView +
playlist/playlistview.h
+
+
+ + +
diff --git a/src/searchwidget.ui b/src/searchwidget.ui new file mode 100644 index 000000000..52f729a4b --- /dev/null +++ b/src/searchwidget.ui @@ -0,0 +1,57 @@ + + + SearchWidget + + + + 0 + 0 + 345 + 31 + + + + Form + + + + + + Qt::Horizontal + + + + 141 + 20 + + + + + + + + + 60 + 27 + + + + + 180 + 16777215 + + + + + + + + + SearchLineEdit + QLineEdit +
libtomahawk/playlist/topbar/searchlineedit.h
+
+
+ + +
From 65c33e70f557667cf5a2bb0a645e3972a38a7c5c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 4 Jun 2011 21:10:14 +0200 Subject: [PATCH 27/53] * Fixed OS X compilation. --- src/tomahawkwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index 1011b270c..8ebf60a88 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -194,7 +194,7 @@ TomahawkWindow::TomahawkWindow( QWidget* parent ) m_searchWidget->searchEdit->setStyleSheet( "QLineEdit { border: 1px solid gray; border-radius: 6px; margin-right: 2px; }" ); #ifdef Q_WS_MAC - ui->filterEdit->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + m_searchWidget->searchEdit->setAttribute( Qt::WA_MacShowFocusRect, 0 ); #endif connect( m_searchWidget->searchEdit, SIGNAL( returnPressed() ), SLOT( onSearch() ) ); From 2a43c7df7871b446552147e5877adb790d22bae8 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 4 Jun 2011 22:39:15 +0200 Subject: [PATCH 28/53] * Try it with a parent. --- src/tomahawkwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index 8ebf60a88..5ee307c71 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -620,7 +620,7 @@ TomahawkWindow::checkForUpdates() void TomahawkWindow::onSearch() { - ViewManager::instance()->show( new SearchWidget( m_searchWidget->searchEdit->text() ) ); + ViewManager::instance()->show( new SearchWidget( m_searchWidget->searchEdit->text(), this ) ); m_searchWidget->searchEdit->setText( QString() ); } From 33a9391ee7fcad4da198737cb4e32fc9e9745069 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 4 Jun 2011 22:58:58 +0200 Subject: [PATCH 29/53] * Try to fix SearchWidget crash. --- src/CMakeLists.txt | 2 +- src/{searchwidget.ui => searchbox.ui} | 0 src/tomahawkwindow.cpp | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{searchwidget.ui => searchbox.ui} (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 99bceddc3..b19d127d2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -122,7 +122,7 @@ SET( tomahawkUI ${tomahawkUI} diagnosticsdialog.ui stackedsettingsdialog.ui proxydialog.ui - searchwidget.ui + searchbox.ui audiocontrols.ui ) diff --git a/src/searchwidget.ui b/src/searchbox.ui similarity index 100% rename from src/searchwidget.ui rename to src/searchbox.ui diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index 5ee307c71..4f6ec35e3 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -18,7 +18,7 @@ #include "tomahawkwindow.h" #include "ui_tomahawkwindow.h" -#include "ui_searchwidget.h" +#include "ui_searchbox.h" #include "config.h" From d8d88826f5c5ded8ac9daf3669da04708ee65e2f Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 4 Jun 2011 17:11:22 -0400 Subject: [PATCH 30/53] rename SearchWidget to GlobalSearchWidget --- src/searchbox.ui | 4 ++-- src/tomahawkwindow.cpp | 2 +- src/tomahawkwindow.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/searchbox.ui b/src/searchbox.ui index 52f729a4b..f996396fa 100644 --- a/src/searchbox.ui +++ b/src/searchbox.ui @@ -1,7 +1,7 @@ - SearchWidget - + GlobalSearchWidget + 0 diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index 4f6ec35e3..ea513d8b8 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -77,7 +77,7 @@ using namespace Tomahawk; TomahawkWindow::TomahawkWindow( QWidget* parent ) : QMainWindow( parent ) , ui( new Ui::TomahawkWindow ) - , m_searchWidget( new Ui::SearchWidget ) + , m_searchWidget( new Ui::GlobalSearchWidget ) , m_audioControls( new AudioControls( this ) ) , m_trayIcon( new TomahawkTrayIcon( this ) ) , m_sourcetree( 0 ) diff --git a/src/tomahawkwindow.h b/src/tomahawkwindow.h index a9799838a..2720a4cfd 100644 --- a/src/tomahawkwindow.h +++ b/src/tomahawkwindow.h @@ -38,7 +38,7 @@ class TomahawkTrayIcon; namespace Ui { class TomahawkWindow; - class SearchWidget; + class GlobalSearchWidget; } class TomahawkWindow : public QMainWindow @@ -100,7 +100,7 @@ private: void setupSignals(); Ui::TomahawkWindow* ui; - Ui::SearchWidget* m_searchWidget; + Ui::GlobalSearchWidget* m_searchWidget; QWidget* m_searchBox; AudioControls* m_audioControls; TomahawkTrayIcon* m_trayIcon; From e5bdab9f9b7ba4bdbd091518d58ae22da2425f2d Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 4 Jun 2011 19:55:56 -0400 Subject: [PATCH 31/53] osx doesn't like hidden widgets added to layouts and shown later --- src/delegateconfigwrapper.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/delegateconfigwrapper.h b/src/delegateconfigwrapper.h index b7986ba88..1c93e7f71 100644 --- a/src/delegateconfigwrapper.h +++ b/src/delegateconfigwrapper.h @@ -29,6 +29,9 @@ public: DelegateConfigWrapper( QWidget* conf, const QString& title, QWidget* parent, Qt::WindowFlags flags = 0 ) : QDialog( parent, flags ), m_widget( conf ) { m_widget->setWindowFlags( Qt::Sheet ); +#ifdef Q_OS_MAC + m_widget->setVisible( true ); +#endif setWindowTitle( title ); QVBoxLayout* v = new QVBoxLayout( this ); From 73e5828d41382df09bacf695fa32fc913a2d64c3 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 4 Jun 2011 20:07:12 -0400 Subject: [PATCH 32/53] attempt strange fix --- src/delegateconfigwrapper.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/delegateconfigwrapper.h b/src/delegateconfigwrapper.h index 1c93e7f71..9155c2cd4 100644 --- a/src/delegateconfigwrapper.h +++ b/src/delegateconfigwrapper.h @@ -51,8 +51,10 @@ public: setMaximumSize( sizeHint() ); // to remove the resize grip on osx this is the only way connect( conf, SIGNAL( sizeHintChanged() ), this, SLOT( updateSizeHint() ) ); -#endif +#else m_widget->setVisible( true ); +#endif + } public slots: void closed( QAbstractButton* b ) From 4e2c5b23f7d72a2565c4e20b5f20d65e4ab321ce Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 4 Jun 2011 21:09:29 -0400 Subject: [PATCH 33/53] Show google-specific text in add contact popup, fixes TWK-217 --- src/sip/jabber/googlewrapper/googlewrapper.cpp | 14 ++++++++++++++ src/sip/jabber/googlewrapper/googlewrapper.h | 2 ++ src/sip/jabber/jabber.h | 2 +- thirdparty/jreen | 2 +- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/sip/jabber/googlewrapper/googlewrapper.cpp b/src/sip/jabber/googlewrapper/googlewrapper.cpp index 1a1865fb6..1bf736bd3 100644 --- a/src/sip/jabber/googlewrapper/googlewrapper.cpp +++ b/src/sip/jabber/googlewrapper/googlewrapper.cpp @@ -21,6 +21,7 @@ #include #include "ui_configwidget.h" +#include SipPlugin* GoogleWrapperFactory::createPlugin( const QString& pluginId ) @@ -52,6 +53,19 @@ GoogleWrapper::icon() const return QIcon( ":/gmail-logo.png" ); } +void +GoogleWrapper::showAddFriendDialog() +{ + bool ok; + QString id = QInputDialog::getText( 0, tr( "Add Friend" ), + tr( "Enter Google Address:" ), QLineEdit::Normal, + "", &ok ); + if ( !ok ) + return; + + qDebug() << "Attempting to add google contact to roster:" << id; + addContact( id ); +} #ifdef GOOGLE_WRAPPER Q_EXPORT_PLUGIN2( sipfactory, GoogleWrapperFactory ) diff --git a/src/sip/jabber/googlewrapper/googlewrapper.h b/src/sip/jabber/googlewrapper/googlewrapper.h index 09f2dc8e0..5478b882e 100644 --- a/src/sip/jabber/googlewrapper/googlewrapper.h +++ b/src/sip/jabber/googlewrapper/googlewrapper.h @@ -47,6 +47,8 @@ public: virtual const QString friendlyName() const { return "Google"; } virtual QIcon icon() const; +public slots: + void showAddFriendDialog(); }; #endif // GOOGLEWRAPPER_H diff --git a/src/sip/jabber/jabber.h b/src/sip/jabber/jabber.h index 89b067525..e361cae02 100644 --- a/src/sip/jabber/jabber.h +++ b/src/sip/jabber/jabber.h @@ -94,12 +94,12 @@ public slots: void broadcastMsg( const QString &msg ); void addContact( const QString &jid, const QString& msg = QString() ); void refreshProxy(); + void showAddFriendDialog(); protected: Ui_JabberConfig* m_ui; // so the google wrapper can change the config dialog a bit private slots: - void showAddFriendDialog(); void showXmlConsole(); void onConnect(); void onDisconnect(Jreen::Client::DisconnectReason reason); diff --git a/thirdparty/jreen b/thirdparty/jreen index 8f995f246..a231a2b38 160000 --- a/thirdparty/jreen +++ b/thirdparty/jreen @@ -1 +1 @@ -Subproject commit 8f995f246637f533feb7124744e113034a32b505 +Subproject commit a231a2b3868baf32312d65cb7e371828212d7745 From 424424cf7beb9e5387d705ebc9224008b20775ef Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 4 Jun 2011 21:59:39 -0400 Subject: [PATCH 34/53] Allow for omitting @foo.com domains for jabber and google. Also, make sip plugins clean up the config after themselves --- src/libtomahawk/sip/SipHandler.cpp | 2 ++ src/libtomahawk/sip/SipPlugin.cpp | 6 ++++ src/libtomahawk/sip/SipPlugin.h | 2 ++ .../jabber/googlewrapper/googlewrapper.cpp | 7 ++++ src/sip/jabber/googlewrapper/googlewrapper.h | 3 ++ src/sip/jabber/jabber.cpp | 33 ++++++++++++++++--- src/sip/jabber/jabber.h | 3 ++ src/sip/twitter/twitter.cpp | 12 +++++-- src/sip/twitter/twitter.h | 5 ++- 9 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/libtomahawk/sip/SipHandler.cpp b/src/libtomahawk/sip/SipHandler.cpp index 2955986d4..9fcedee97 100644 --- a/src/libtomahawk/sip/SipHandler.cpp +++ b/src/libtomahawk/sip/SipHandler.cpp @@ -283,6 +283,8 @@ void SipHandler::removeSipPlugin( SipPlugin* p ) { p->disconnectPlugin(); + p->deletePlugin(); + emit pluginRemoved( p ); // emit first so sipmodel can find the indexOf diff --git a/src/libtomahawk/sip/SipPlugin.cpp b/src/libtomahawk/sip/SipPlugin.cpp index b1cf939cc..6ddc1e298 100644 --- a/src/libtomahawk/sip/SipPlugin.cpp +++ b/src/libtomahawk/sip/SipPlugin.cpp @@ -111,3 +111,9 @@ SipPlugin::onPeerOffline(const QString& peerId) m_peersOnline.removeAll( peerId ); } +void +SipPlugin::deletePlugin() +{ + +} + diff --git a/src/libtomahawk/sip/SipPlugin.h b/src/libtomahawk/sip/SipPlugin.h index 11cc055a8..67ad39720 100644 --- a/src/libtomahawk/sip/SipPlugin.h +++ b/src/libtomahawk/sip/SipPlugin.h @@ -91,6 +91,8 @@ public slots: virtual void refreshProxy(); + // so plugins can clean up after themselves + virtual void deletePlugin(); signals: void error( int, const QString& ); void stateChanged( SipPlugin::ConnectionState state ); diff --git a/src/sip/jabber/googlewrapper/googlewrapper.cpp b/src/sip/jabber/googlewrapper/googlewrapper.cpp index 1bf736bd3..2f103d492 100644 --- a/src/sip/jabber/googlewrapper/googlewrapper.cpp +++ b/src/sip/jabber/googlewrapper/googlewrapper.cpp @@ -53,6 +53,13 @@ GoogleWrapper::icon() const return QIcon( ":/gmail-logo.png" ); } +QString +GoogleWrapper::defaultSuffix() const +{ + return "@gmail.com"; +} + + void GoogleWrapper::showAddFriendDialog() { diff --git a/src/sip/jabber/googlewrapper/googlewrapper.h b/src/sip/jabber/googlewrapper/googlewrapper.h index 5478b882e..f34238c6a 100644 --- a/src/sip/jabber/googlewrapper/googlewrapper.h +++ b/src/sip/jabber/googlewrapper/googlewrapper.h @@ -47,6 +47,9 @@ public: virtual const QString friendlyName() const { return "Google"; } virtual QIcon icon() const; +protected: + QString defaultSuffix() const; + public slots: void showAddFriendDialog(); }; diff --git a/src/sip/jabber/jabber.cpp b/src/sip/jabber/jabber.cpp index 94fafa734..167406c28 100644 --- a/src/sip/jabber/jabber.cpp +++ b/src/sip/jabber/jabber.cpp @@ -157,10 +157,10 @@ JabberPlugin::refreshProxy() if( !m_client->connection() ) return; - + QNetworkProxy proxyToUse = TomahawkUtils::proxyFactory()->queryProxy( QNetworkProxyQuery( m_currentServer, m_currentPort ) ).first(); m_usedProxy = proxyToUse; - + if( proxyToUse.type() != QNetworkProxy::NoProxy && ( m_currentServer.isEmpty() || !(m_currentPort > 0) ) ) { qDebug() << Q_FUNC_INFO << " proxy type is not noproxy but no server/port set"; @@ -467,7 +467,12 @@ void JabberPlugin::addContact(const QString& jid, const QString& msg) { // Add contact to the Tomahawk group on the roster - m_roster->subscribe( jid, msg, jid, QStringList() << "Tomahawk" ); + + QString realJid = jid; + if( !realJid.contains( '@' ) ) + realJid += defaultSuffix(); + + m_roster->subscribe( realJid, msg, realJid, QStringList() << "Tomahawk" ); return; } @@ -486,6 +491,13 @@ JabberPlugin::showAddFriendDialog() addContact( id ); } +QString +JabberPlugin::defaultSuffix() const +{ + return "@jabber.org"; +} + + void JabberPlugin::showXmlConsole() { @@ -513,13 +525,19 @@ JabberPlugin::checkSettings() proxyToUse.type() != m_usedProxy.type() || proxyToUse.capabilities() != m_usedProxy.capabilities() ) - reconnect = true; + reconnect = true; m_currentUsername = accountName(); m_currentPassword = readPassword(); m_currentServer = readServer(); m_currentPort = readPort(); + if ( !m_currentUsername.contains( '@' ) ) + { + m_currentUsername += defaultSuffix(); + TomahawkSettings::instance()->setValue( pluginId() + "/username", m_currentUsername ); + } + if ( reconnect ) { qDebug() << Q_FUNC_INFO << "Reconnecting jreen plugin..."; @@ -540,7 +558,6 @@ JabberPlugin::checkSettings() void JabberPlugin::setupClientHelper() { Jreen::JID jid = Jreen::JID( m_currentUsername ); - m_client->setJID( jid ); m_client->setPassword( m_currentPassword ); @@ -981,6 +998,12 @@ JabberPlugin::saveConfig() checkSettings(); } +void +JabberPlugin::deletePlugin() +{ + TomahawkSettings::instance()->remove( pluginId() ); +} + SipPlugin::ConnectionState JabberPlugin::connectionState() const diff --git a/src/sip/jabber/jabber.h b/src/sip/jabber/jabber.h index e361cae02..394de949d 100644 --- a/src/sip/jabber/jabber.h +++ b/src/sip/jabber/jabber.h @@ -82,6 +82,7 @@ public: virtual QIcon icon() const; virtual QWidget* configWidget(); virtual void saveConfig(); + virtual void deletePlugin(); signals: void jidChanged( const QString& ); @@ -97,6 +98,8 @@ public slots: void showAddFriendDialog(); protected: + virtual QString defaultSuffix() const; + Ui_JabberConfig* m_ui; // so the google wrapper can change the config dialog a bit private slots: diff --git a/src/sip/twitter/twitter.cpp b/src/sip/twitter/twitter.cpp index 3a6c8087f..5ae92bf7c 100644 --- a/src/sip/twitter/twitter.cpp +++ b/src/sip/twitter/twitter.cpp @@ -283,6 +283,12 @@ TwitterPlugin::connectAuthVerifyReply( const QTweetUser &user ) } } +void +TwitterPlugin::deletePlugin() +{ + TomahawkSettings::instance()->remove( pluginId() ); +} + void TwitterPlugin::checkTimerFired() { @@ -596,7 +602,7 @@ TwitterPlugin::registerOffer( const QString &screenName, const QHash< QString, Q if ( !m_cachedAvatars.contains( screenName ) ) QMetaObject::invokeMethod( this, "fetchAvatar", Q_ARG( QString, screenName ) ); - + QHash< QString, QVariant > _peerData( peerData ); if ( _peerData.contains( "dirty" ) ) @@ -906,7 +912,7 @@ TwitterPlugin::twitterCachedFriendsSinceId() const s->sync(); } s->endGroup(); - + return s->value( pluginId() + "/cachedfriendssinceid", 0 ).toLongLong(); } @@ -1004,7 +1010,7 @@ TwitterPlugin::twitterCachedPeers() const s->setValue( "cachedpeers", s->value( "cachedpeers_tmp" ).toHash() ); s->remove( "cachedpeers_tmp" ); - + s->sync(); } s->endGroup(); diff --git a/src/sip/twitter/twitter.h b/src/sip/twitter/twitter.h index fb1db6242..508cacceb 100644 --- a/src/sip/twitter/twitter.h +++ b/src/sip/twitter/twitter.h @@ -74,12 +74,13 @@ public: signals: void avatarReceived( QString, QPixmap ); - + public slots: virtual bool connectPlugin( bool startup ); void disconnectPlugin(); void checkSettings(); void refreshProxy(); + void deletePlugin(); void sendMsg( const QString& to, const QString& msg ) { @@ -135,8 +136,6 @@ private: void setTwitterCachedDirectMessagesSinceId( qint64 sinceid ); QHash twitterCachedPeers() const; void setTwitterCachedPeers( const QHash &cachedPeers ); - bool twitterAutoConnect() const; - void setTwitterAutoConnect( bool autoConnect ); QWeakPointer< TomahawkOAuthTwitter > m_twitterAuth; QWeakPointer< QTweetFriendsTimeline > m_friendsTimeline; From 297161c7666dbc6e18b969363d7e81668c2626b2 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 5 Jun 2011 17:20:04 +0200 Subject: [PATCH 35/53] * Update thirdparty/jreen submodule. --- thirdparty/jreen | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thirdparty/jreen b/thirdparty/jreen index a231a2b38..2957d0ff0 160000 --- a/thirdparty/jreen +++ b/thirdparty/jreen @@ -1 +1 @@ -Subproject commit a231a2b3868baf32312d65cb7e371828212d7745 +Subproject commit 2957d0ff03d9561af8afc4bd3a45947392868875 From 7742e3091af5b55c42ca7aeaf1a355b988b8b912 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 5 Jun 2011 13:55:53 -0400 Subject: [PATCH 36/53] show summary for songs as well --- .../playlist/dynamic/echonest/EchonestControl.cpp | 2 +- .../playlist/dynamic/echonest/EchonestGenerator.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp index bdd939a44..43a0d1555 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp @@ -643,7 +643,7 @@ Tomahawk::EchonestControl::calculateSummary() summary = QString( "similar to ~%1" ).arg( m_data.second.toString() ); } else if( selectedType() == "Artist Description" ) { summary = QString( "with genre ~%1" ).arg( m_data.second.toString() ); - } else if( selectedType() == "Artist Description" ) { + } else if( selectedType() == "Artist Description" || selectedType() == "Song" ) { summary = QString( "similar to ~%1" ).arg( m_data.second.toString() ); } else if( selectedType() == "Variety" || selectedType() == "Danceability" || selectedType() == "Artist Hotttnesss" || selectedType() == "Energy" || selectedType() == "Artist Familiarity" || selectedType() == "Song Hotttnesss" ) { QString modifier; diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp index ee55ae3a0..f4b8a5306 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp @@ -445,10 +445,10 @@ EchonestGenerator::sentenceSummary() /// Skip empty artists QList< dyncontrol_ptr > empty; - foreach( const dyncontrol_ptr& artist, required ) { - QString summary = artist.dynamicCast< EchonestControl >()->summary(); + foreach( const dyncontrol_ptr& artistOrTrack, required ) { + QString summary = artistOrTrack.dynamicCast< EchonestControl >()->summary(); if( summary.lastIndexOf( "~" ) == summary.length() - 1 ) - empty << artist; + empty << artistOrTrack; } foreach( const dyncontrol_ptr& toremove, empty ) { required.removeAll( toremove ); From 5ec7e3340b7f234fa16b32668f4d582f63fb31f5 Mon Sep 17 00:00:00 2001 From: Christopher Reichert Date: Fri, 3 Jun 2011 19:01:23 -0500 Subject: [PATCH 37/53] re-resolve tracks when a resolver is added or removed. The pipeline emits a signal to queries when a resolver is added/removed. The queries take action based on their solved() status and if not solved() inform the pipeline to re-resolve them. --- src/libtomahawk/pipeline.cpp | 4 +++- src/libtomahawk/pipeline.h | 3 +++ src/libtomahawk/query.cpp | 25 +++++++++++++++++++++++++ src/libtomahawk/query.h | 4 ++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/pipeline.cpp b/src/libtomahawk/pipeline.cpp index e99755887..ee6d12ff6 100644 --- a/src/libtomahawk/pipeline.cpp +++ b/src/libtomahawk/pipeline.cpp @@ -82,8 +82,9 @@ void Pipeline::removeResolver( Resolver* r ) { QMutexLocker lock( &m_mut ); - + m_resolvers.removeAll( r ); + emit resolverRemoved( r ); } @@ -100,6 +101,7 @@ Pipeline::addResolver( Resolver* r, bool sort ) Pipeline::resolverSorter ); } qDebug() << "Adding resolver" << r->name(); + emit resolverAdded( r ); /* qDebug() << "Current pipeline:"; foreach( Resolver * r, m_resolvers ) diff --git a/src/libtomahawk/pipeline.h b/src/libtomahawk/pipeline.h index 7c41e03ab..faee4a018 100644 --- a/src/libtomahawk/pipeline.h +++ b/src/libtomahawk/pipeline.h @@ -79,6 +79,9 @@ public slots: signals: void idle(); void resolving( const Tomahawk::query_ptr& query ); + + void resolverAdded( Resolver* ); + void resolverRemoved( Resolver* ); private slots: void timeoutShunt( const query_ptr& q ); diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index 96dad8007..471ac6fa9 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -67,6 +67,11 @@ Query::Query( const QString& artist, const QString& track, const QString& album, { connect( Database::instance(), SIGNAL( indexReady() ), SLOT( refreshResults() ), Qt::QueuedConnection ); } + + connect( Pipeline::instance(), SIGNAL( resolverAdded( Resolver* ) ), + SLOT( onResolverAdded() ), Qt::QueuedConnection ); + connect( Pipeline::instance(), SIGNAL( resolverRemoved( Resolver* ) ), + SLOT( onResolverRemoved() ), Qt::QueuedConnection ); } @@ -148,6 +153,26 @@ Query::onResolvingFinished() } +void +Query::onResolverAdded( ) +{ + if ( !solved() ) + { + refreshResults(); + } +} + +void +Query::onResolverRemoved( ) +{ + if ( !solved() ) + { + refreshResults(); + } + +} + + QList< result_ptr > Query::results() const { diff --git a/src/libtomahawk/query.h b/src/libtomahawk/query.h index 59a218f45..288c4ea52 100644 --- a/src/libtomahawk/query.h +++ b/src/libtomahawk/query.h @@ -105,6 +105,10 @@ public slots: void onResolvingFinished(); + // resolve if not solved() + void onResolverAdded( ); + void onResolverRemoved( ); + private slots: void onResultStatusChanged(); void refreshResults(); From aa076684dc085299e44057e34d71a0d174516617 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 5 Jun 2011 16:40:35 -0400 Subject: [PATCH 38/53] fix up checking for moods and styles --- .../playlist/dynamic/echonest/EchonestControl.cpp | 9 ++++++--- .../playlist/dynamic/echonest/EchonestControl.h | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp index bdd939a44..b04f9ce82 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp @@ -30,10 +30,11 @@ #include QHash< QString, QStringList > Tomahawk::EchonestControl::s_suggestCache = QHash< QString, QStringList >(); +bool Tomahawk::EchonestControl::s_fetchingMoodsAndStyles = false; +int Tomahawk::EchonestControl::s_stylePollCount = 0; Tomahawk::EchonestControl::EchonestControl( const QString& selectedType, const QStringList& typeSelectors, QObject* parent ) : DynamicControl ( selectedType.isEmpty() ? "Artist" : selectedType, typeSelectors, parent ) - , m_stylePollCount( 0 ) { setType( "echonest" ); m_editingTimer.setInterval( 500 ); //timeout to edits @@ -705,6 +706,7 @@ Tomahawk::EchonestControl::calculateSummary() void Tomahawk::EchonestControl::checkForMoodsOrStylesFetched() { + s_fetchingMoodsAndStyles = false; if( selectedType() == "Mood" || selectedType() == "Style" ) { QComboBox* cb = qobject_cast< QComboBox* >( m_input.data() ); if( cb && cb->count() == 0 ) { // got nothing, so lets populate @@ -728,10 +730,11 @@ Tomahawk::EchonestControl::insertMoodsAndStyles() } if( src.isEmpty() && !combo->count() ) { - if( m_stylePollCount <= 20 ) { // try for 20s to get the styles... + if( s_stylePollCount <= 20 && !s_fetchingMoodsAndStyles ) { // try for 20s to get the styles... + s_fetchingMoodsAndStyles = true; QTimer::singleShot( 1000, this, SLOT( checkForMoodsOrStylesFetched() ) ); } - m_stylePollCount++; + s_stylePollCount++; return false; } diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.h b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.h index 43e848f94..6544a8643 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.h +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.h @@ -91,7 +91,8 @@ private: Echonest::DynamicPlaylist::PlaylistParamData m_data; QVariant m_cacheData; - int m_stylePollCount; + static bool s_fetchingMoodsAndStyles; + static int s_stylePollCount; QSet< QNetworkReply* > m_suggestWorkers; static QHash< QString, QStringList > s_suggestCache; From 7cac0ed9bc586f2b5e5fb3c9c812fa79ac754b11 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 5 Jun 2011 16:47:32 -0400 Subject: [PATCH 39/53] Really don't go overboard asking for moods/styles --- .../dynamic/echonest/EchonestControl.cpp | 1 - .../dynamic/echonest/EchonestGenerator.cpp | 18 ++++++++++++------ .../dynamic/echonest/EchonestGenerator.h | 2 ++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp index b04f9ce82..6d9603e79 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestControl.cpp @@ -724,7 +724,6 @@ Tomahawk::EchonestControl::insertMoodsAndStyles() if( !combo ) return false; - qDebug() << "Inserting moods and or styles, here's the list" << src; foreach( const QString& item, src ) { combo->addItem( item, item ); } diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp index ee55ae3a0..2568b3569 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp @@ -26,6 +26,8 @@ using namespace Tomahawk; QVector< QString > EchonestGenerator::s_moods = QVector< QString >(); QVector< QString > EchonestGenerator::s_styles = QVector< QString >(); +QNetworkReply* EchonestGenerator::s_moodsJob = 0; +QNetworkReply* EchonestGenerator::s_stylesJob = 0; EchonestFactory::EchonestFactory() {} @@ -59,12 +61,14 @@ EchonestGenerator::EchonestGenerator ( QObject* parent ) m_mode = OnDemand; m_logo.load( RESPATH "/images/echonest_logo.png" ); - // fetch style and moods - QNetworkReply* style = Echonest::Artist::listTerms( "style" ); - connect( style, SIGNAL( finished() ), this, SLOT( stylesReceived() ) ); - - QNetworkReply* moods = Echonest::Artist::listTerms( "mood" ); - connect( moods, SIGNAL( finished() ), this, SLOT( moodsReceived() ) ); + if( !s_stylesJob && s_styles.isEmpty() ) { + // fetch style and moods + s_stylesJob = Echonest::Artist::listTerms( "style" ); + connect( s_stylesJob, SIGNAL( finished() ), this, SLOT( stylesReceived() ) ); + } else if( !s_moodsJob && s_moods.isEmpty() ) { + s_moodsJob = Echonest::Artist::listTerms( "mood" ); + connect( s_moodsJob, SIGNAL( finished() ), this, SLOT( moodsReceived() ) ); + } // qDebug() << "ECHONEST:" << m_logo.size(); } @@ -530,6 +534,7 @@ EchonestGenerator::moodsReceived() } catch( Echonest::ParseError& e ) { qWarning() << "Echonest failed to parse moods list"; } + s_moodsJob = 0; } QVector< QString > @@ -549,4 +554,5 @@ EchonestGenerator::stylesReceived() } catch( Echonest::ParseError& e ) { qWarning() << "Echonest failed to parse styles list"; } + s_stylesJob = 0; } diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h index 1af9fc12c..aac93b25b 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h @@ -95,6 +95,8 @@ private: static QVector< QString > s_styles; static QVector< QString > s_moods; + static QNetworkReply* s_stylesJob; + static QNetworkReply* s_moodsJob; // used for the intermediary song id lookup QSet< QNetworkReply* > m_waiting; From 1021e9c1b517f6d0dbb7d9b703517cf895599d39 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 5 Jun 2011 23:20:09 +0200 Subject: [PATCH 40/53] * Improved AudioEngine's internal phonon-state handling. --- src/libtomahawk/audio/audioengine.cpp | 49 ++++++++++++--------------- src/libtomahawk/audio/audioengine.h | 1 + src/libtomahawk/query.cpp | 28 +++++++-------- src/libtomahawk/query.h | 4 +-- 4 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index e3cf26096..d8b28857c 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -59,6 +59,7 @@ AudioEngine::AudioEngine() m_mediaObject->setTickInterval( 150 ); connect( m_mediaObject, SIGNAL( stateChanged( Phonon::State, Phonon::State ) ), SLOT( onStateChanged( Phonon::State, Phonon::State ) ) ); connect( m_mediaObject, SIGNAL( tick( qint64 ) ), SLOT( timerTriggered( qint64 ) ) ); + connect( m_mediaObject, SIGNAL( aboutToFinish() ), SLOT( onAboutToFinish() ) ); } @@ -123,7 +124,6 @@ AudioEngine::stop() { qDebug() << Q_FUNC_INFO; - m_expectStop = true; m_mediaObject->stop(); setCurrentTrack( Tomahawk::result_ptr() ); @@ -217,11 +217,6 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) qDebug() << "Starting new song from url:" << m_currentTrack->url(); emit loading( m_currentTrack ); - if ( !m_input.isNull() || m_isPlayingHttp ) - { - m_expectStop = true; - } - if ( !isHttpResult( m_currentTrack->url() ) && !isLocalResult( m_currentTrack->url() ) ) { m_mediaObject->setCurrentSource( io.data() ); @@ -328,37 +323,37 @@ AudioEngine::playItem( PlaylistInterface* playlist, const Tomahawk::result_ptr& } +void +AudioEngine::onAboutToFinish() +{ + qDebug() << Q_FUNC_INFO; + m_expectStop = true; +} + + void AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState ) { - qDebug() << Q_FUNC_INFO << oldState << newState; + qDebug() << Q_FUNC_INFO << oldState << newState << m_expectStop; if ( newState == Phonon::ErrorState ) { qDebug() << "Phonon Error:" << m_mediaObject->errorString() << m_mediaObject->errorType(); - } - if ( oldState == Phonon::PlayingState && newState == Phonon::StoppedState ) - { - qDebug() << "Expecting stop?" << m_expectStop; - if ( !m_expectStop ) - { - qDebug() << "Loading next track."; - m_expectStop = false; - loadNextTrack(); - } - } - else if ( oldState == Phonon::PlayingState && newState == Phonon::PausedState ) - { - qDebug() << m_mediaObject->currentTime() << m_mediaObject->totalTime(); - if ( m_mediaObject->currentTime() == m_mediaObject->totalTime() ) - { - qDebug() << "Loading next track."; - m_expectStop = false; - loadNextTrack(); - } + return; } + if ( !m_expectStop ) + return; m_expectStop = false; + + if ( oldState == Phonon::PlayingState ) + { + if ( newState == Phonon::PausedState || newState == Phonon::StoppedState ) + { + qDebug() << "Loading next track."; + loadNextTrack(); + } + } } diff --git a/src/libtomahawk/audio/audioengine.h b/src/libtomahawk/audio/audioengine.h index d7fc8c954..05b3b1bd5 100644 --- a/src/libtomahawk/audio/audioengine.h +++ b/src/libtomahawk/audio/audioengine.h @@ -100,6 +100,7 @@ private slots: void loadPreviousTrack(); void loadNextTrack(); + void onAboutToFinish(); void onStateChanged( Phonon::State newState, Phonon::State oldState ); void timerTriggered( qint64 time ); diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index 471ac6fa9..406a22a3f 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -67,11 +67,11 @@ Query::Query( const QString& artist, const QString& track, const QString& album, { connect( Database::instance(), SIGNAL( indexReady() ), SLOT( refreshResults() ), Qt::QueuedConnection ); } - - connect( Pipeline::instance(), SIGNAL( resolverAdded( Resolver* ) ), - SLOT( onResolverAdded() ), Qt::QueuedConnection ); + + connect( Pipeline::instance(), SIGNAL( resolverAdded( Resolver* ) ), + SLOT( onResolverAdded() ), Qt::QueuedConnection ); connect( Pipeline::instance(), SIGNAL( resolverRemoved( Resolver* ) ), - SLOT( onResolverRemoved() ), Qt::QueuedConnection ); + SLOT( onResolverRemoved() ), Qt::QueuedConnection ); } @@ -154,22 +154,22 @@ Query::onResolvingFinished() void -Query::onResolverAdded( ) -{ - if ( !solved() ) - { - refreshResults(); - } -} - -void -Query::onResolverRemoved( ) +Query::onResolverAdded() { if ( !solved() ) { refreshResults(); } +} + +void +Query::onResolverRemoved() +{ + if ( !solved() ) + { + refreshResults(); + } } diff --git a/src/libtomahawk/query.h b/src/libtomahawk/query.h index 288c4ea52..900860367 100644 --- a/src/libtomahawk/query.h +++ b/src/libtomahawk/query.h @@ -106,8 +106,8 @@ public slots: void onResolvingFinished(); // resolve if not solved() - void onResolverAdded( ); - void onResolverRemoved( ); + void onResolverAdded(); + void onResolverRemoved(); private slots: void onResultStatusChanged(); From 4f8165cc8ab39bc28613d326aa1e5e7ce1dd7010 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Sun, 5 Jun 2011 17:57:33 -0700 Subject: [PATCH 41/53] Check if Adium is running before setting status. Be more efficient about forming the Applescript string. --- .../infosystem/infoplugins/adiumplugin.cpp | 26 +++++++++++++++---- .../infosystem/infoplugins/adiumplugin.h | 2 ++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index 8d97f5107..b684b454e 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -26,13 +26,18 @@ #include "adiumplugin.h" #include "adium.h" +QString adium_beforeStatus; +QString adium_afterStatus; + static void setStatus(const QString &status) { - QString adiumStatus = "tell application \"Adium\"\n"; - adiumStatus.append("set the status message of every account to \""); - adiumStatus.append(status); - adiumStatus.append("\"\nend tell\n"); - const char* scriptstr = adiumStatus.toUtf8(); + // The command that updates the status + QString scriptqstr; + scriptqstr.append(adium_beforeStatus); + scriptqstr.append(status); + scriptqstr.append(adium_afterStatus); + + const char* scriptstr = scriptqstr.toUtf8(); script( scriptstr ); } @@ -42,6 +47,17 @@ AdiumPlugin::AdiumPlugin() : InfoPlugin() { qDebug() << Q_FUNC_INFO; + + adium_beforeStatus = "if appIsRunning(\"Adium\") then\n"; + adium_beforeStatus.append("tell application \"Adium\"\n"); + adium_beforeStatus.append("set the status message of every account to \""); + + adium_afterStatus.append("\"\nend tell\n"); + adium_afterStatus.append("end if\n"); + adium_afterStatus.append("on appIsRunning(appName)\n"); + adium_afterStatus.append("tell application \"System Events\" to (name of processes) contains appName\n"); + adium_afterStatus.append("end appIsRunning\n"); + m_supportedPushTypes << InfoNowPlaying << InfoNowPaused << InfoNowResumed << InfoNowStopped; m_active = TomahawkSettings::instance()->nowPlayingEnabled(); diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.h b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h index 8660ce3d8..776f62585 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.h +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h @@ -54,6 +54,8 @@ public slots: private: bool m_active; + QString m_beforeStatus; + QString m_afterStatus; }; From f0b1d49f6bb526f0ca240cd0599eb674fef7eec3 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Mon, 6 Jun 2011 21:23:55 -0700 Subject: [PATCH 42/53] Add tomahawk link to currently playing song, to Adium now-playing status. --- src/libtomahawk/audio/audioengine.cpp | 4 +++ .../infosystem/infoplugins/adiumplugin.cpp | 3 +- src/libtomahawk/infosystem/infosystem.cpp | 30 +++++++++++++++++++ src/libtomahawk/infosystem/infosystem.h | 3 ++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index d8b28857c..5ca56a721 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -27,6 +27,8 @@ #include "infosystem/infosystem.h" #include "network/servent.h" +#include "album.h" + AudioEngine* AudioEngine::s_instance = 0; static QString s_aeInfoIdentifier = QString( "AUDIOENGINE" ); @@ -98,6 +100,7 @@ AudioEngine::play() trackInfo["title"] = m_currentTrack->track(); trackInfo["artist"] = m_currentTrack->artist()->name(); + trackInfo["album"] = m_currentTrack->album()->name(); Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowResumed, QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) ); @@ -252,6 +255,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) trackInfo["title"] = m_currentTrack->track(); trackInfo["artist"] = m_currentTrack->artist()->name(); + trackInfo["album"] = m_currentTrack->album()->name(); Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowPlaying, QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) ); diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index b684b454e..4ea87c920 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -124,7 +124,6 @@ AdiumPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoTyp /** Audio state slots */ void AdiumPlugin::audioStarted( const QVariant &input ) -//void AdiumPlugin::audioStarted( const Tomahawk::result_ptr& track ) { qDebug() << Q_FUNC_INFO; @@ -139,6 +138,8 @@ AdiumPlugin::audioStarted( const QVariant &input ) nowPlaying.append( hash["title"] ); nowPlaying.append(" - "); nowPlaying.append( hash["artist"] ); + nowPlaying.append( " " ); + nowPlaying.append( openLinkFromHash( hash ).toString() ); setStatus( nowPlaying ); } diff --git a/src/libtomahawk/infosystem/infosystem.cpp b/src/libtomahawk/infosystem/infosystem.cpp index 62c18380d..751b4a263 100644 --- a/src/libtomahawk/infosystem/infosystem.cpp +++ b/src/libtomahawk/infosystem/infosystem.cpp @@ -44,6 +44,36 @@ InfoPlugin::~InfoPlugin() qDebug() << Q_FUNC_INFO; } +QUrl +InfoPlugin::openLinkFromHash( const InfoCriteriaHash& hash ) const +{ + QUrl link( "tomahawk://open/track/" ); + QString title, artist, album; + + if( !hash.isEmpty() && hash.contains( "title" ) && hash.contains( "artist" ) ) + { + title = hash["title"]; + artist = hash["artist"]; + if( hash.contains( "album" ) ) + qDebug() << "Album is: " << album; + album = hash["album"]; + } + + if( !title.isEmpty() ) + link.addEncodedQueryItem( "title", QUrl::toPercentEncoding( title ) ); + if( !artist.isEmpty() ) + link.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artist ) ); + if( !album.isEmpty() ) + link.addEncodedQueryItem( "album", QUrl::toPercentEncoding( album ) ); + + // Add encoding for spaces, since QUrl does not + QUrl encodedLink( link.toString().replace(" ", "%20"), QUrl::StrictMode ); + + qDebug() << "encodedLink " << encodedLink.toString(); + + return encodedLink; +} + InfoSystem* InfoSystem::s_instance = 0; InfoSystem* diff --git a/src/libtomahawk/infosystem/infosystem.h b/src/libtomahawk/infosystem/infosystem.h index c7ed842a6..e1728d798 100644 --- a/src/libtomahawk/infosystem/infosystem.h +++ b/src/libtomahawk/infosystem/infosystem.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -133,6 +134,8 @@ protected slots: virtual void namChangedSlot( QNetworkAccessManager *nam ) = 0; protected: + QUrl openLinkFromHash( const InfoCriteriaHash& hash ) const; + InfoType m_type; QSet< InfoType > m_supportedGetTypes; QSet< InfoType > m_supportedPushTypes; From dd78a2097aaf8ebc8fa9d771f8cfb35d772072a4 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Mon, 6 Jun 2011 23:19:53 -0700 Subject: [PATCH 43/53] Decode percent-encoded Tomahawk links. --- src/libtomahawk/globalactionmanager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/globalactionmanager.cpp b/src/libtomahawk/globalactionmanager.cpp index 1dd335571..79ffb7818 100644 --- a/src/libtomahawk/globalactionmanager.cpp +++ b/src/libtomahawk/globalactionmanager.cpp @@ -165,8 +165,9 @@ GlobalActionManager::copyToClipboard( const Tomahawk::query_ptr& query ) const bool GlobalActionManager::parseTomahawkLink( const QString& url ) { - if( url.contains( "tomahawk://" ) ) { - QString cmd = url.mid( 11 ); + QString decodedUrl = QString::fromUtf8( QByteArray::fromPercentEncoding( url.toAscii() ).data() ); + if( decodedUrl.contains( "tomahawk://" ) ) { + QString cmd = decodedUrl.mid( 11 ); qDebug() << "Parsing tomahawk link command" << cmd; QString cmdType = cmd.split( "/" ).first(); From df83239ad36b11e97b6f699e6f5518ede8bf6050 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Mon, 6 Jun 2011 23:22:44 -0700 Subject: [PATCH 44/53] Style fix. --- src/libtomahawk/globalactionmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/globalactionmanager.cpp b/src/libtomahawk/globalactionmanager.cpp index 79ffb7818..5a1807e00 100644 --- a/src/libtomahawk/globalactionmanager.cpp +++ b/src/libtomahawk/globalactionmanager.cpp @@ -165,7 +165,7 @@ GlobalActionManager::copyToClipboard( const Tomahawk::query_ptr& query ) const bool GlobalActionManager::parseTomahawkLink( const QString& url ) { - QString decodedUrl = QString::fromUtf8( QByteArray::fromPercentEncoding( url.toAscii() ).data() ); + QString decodedUrl = QString::fromUtf8( QByteArray::fromPercentEncoding( url.toAscii() ).data() ); if( decodedUrl.contains( "tomahawk://" ) ) { QString cmd = decodedUrl.mid( 11 ); qDebug() << "Parsing tomahawk link command" << cmd; From 3ec930891677c301ed1d3960a7c1c29d101e37a9 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Mon, 6 Jun 2011 23:39:57 -0700 Subject: [PATCH 45/53] debug-- --- src/libtomahawk/infosystem/infosystem.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libtomahawk/infosystem/infosystem.cpp b/src/libtomahawk/infosystem/infosystem.cpp index 751b4a263..0a163c9bb 100644 --- a/src/libtomahawk/infosystem/infosystem.cpp +++ b/src/libtomahawk/infosystem/infosystem.cpp @@ -69,8 +69,6 @@ InfoPlugin::openLinkFromHash( const InfoCriteriaHash& hash ) const // Add encoding for spaces, since QUrl does not QUrl encodedLink( link.toString().replace(" ", "%20"), QUrl::StrictMode ); - qDebug() << "encodedLink " << encodedLink.toString(); - return encodedLink; } From bee2a7165a25da12a7a89878261d56c956047bdf Mon Sep 17 00:00:00 2001 From: Frank Osterfeld Date: Tue, 7 Jun 2011 19:54:29 +0200 Subject: [PATCH 46/53] Fix sorting by file size (Don't sort the formatted strings, but the actual file size). Also, use TrackModel::Column enum instead of int constants. --- .../playlist/collectionproxymodel.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/playlist/collectionproxymodel.cpp b/src/libtomahawk/playlist/collectionproxymodel.cpp index 4f602e5db..46972c6c8 100644 --- a/src/libtomahawk/playlist/collectionproxymodel.cpp +++ b/src/libtomahawk/playlist/collectionproxymodel.cpp @@ -55,6 +55,7 @@ CollectionProxyModel::lessThan( const QModelIndex& left, const QModelIndex& righ unsigned int bitrate1 = 0, bitrate2 = 0; unsigned int mtime1 = 0, mtime2 = 0; unsigned int id1 = 0, id2 = 0; + unsigned int size1 = 0, size2 = 0; if ( q1->numResults() ) { @@ -66,6 +67,7 @@ CollectionProxyModel::lessThan( const QModelIndex& left, const QModelIndex& righ bitrate1 = r->bitrate(); mtime1 = r->modificationTime(); id1 = r->dbid(); + size1 = r->size(); } if ( q2->numResults() ) { @@ -77,9 +79,10 @@ CollectionProxyModel::lessThan( const QModelIndex& left, const QModelIndex& righ bitrate2 = r->bitrate(); mtime2 = r->modificationTime(); id2 = r->dbid(); + size2 = r->size(); } - if ( left.column() == 0 ) // sort by artist + if ( left.column() == TrackModel::Artist ) // sort by artist { if ( artist1 == artist2 ) { @@ -96,7 +99,7 @@ CollectionProxyModel::lessThan( const QModelIndex& left, const QModelIndex& righ return QString::localeAwareCompare( artist1, artist2 ) < 0; } - else if ( left.column() == 2 ) // sort by album + else if ( left.column() == TrackModel::Album ) // sort by album { if ( album1 == album2 ) { @@ -108,21 +111,27 @@ CollectionProxyModel::lessThan( const QModelIndex& left, const QModelIndex& righ return QString::localeAwareCompare( album1, album2 ) < 0; } - else if ( left.column() == 4 ) // sort by bitrate + else if ( left.column() == TrackModel::Bitrate ) // sort by bitrate { if ( bitrate1 == bitrate2 ) return id1 < id2; return bitrate1 < bitrate2; } - else if ( left.column() == 5 ) // sort by mtime + else if ( left.column() == TrackModel::Age ) // sort by mtime { if ( mtime1 == mtime2 ) return id1 < id2; return mtime1 < mtime2; } + else if ( left.column() == TrackModel::Filesize ) // sort by file size + { + if ( size1 == size2 ) + return id1 < id2; + return size1 < size2; + } return QString::localeAwareCompare( sourceModel()->data( left ).toString(), sourceModel()->data( right ).toString() ) < 0; } From 24502d885608deac2a5de23eea94c237ac0fc536 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sun, 5 Jun 2011 15:44:30 -0400 Subject: [PATCH 47/53] Update tomahawk volume when phonon volume is updated externally, lessen deafness --- src/libtomahawk/audio/audioengine.cpp | 3 ++- src/libtomahawk/audio/audioengine.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 5ca56a721..04fc7fcfc 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -62,6 +62,8 @@ AudioEngine::AudioEngine() connect( m_mediaObject, SIGNAL( stateChanged( Phonon::State, Phonon::State ) ), SLOT( onStateChanged( Phonon::State, Phonon::State ) ) ); connect( m_mediaObject, SIGNAL( tick( qint64 ) ), SLOT( timerTriggered( qint64 ) ) ); connect( m_mediaObject, SIGNAL( aboutToFinish() ), SLOT( onAboutToFinish() ) ); + + connect( m_audioOutput, SIGNAL( volumeChanged( qreal ) ), this, SLOT( onVolumeChanged( qreal ) ) ); } @@ -173,7 +175,6 @@ AudioEngine::setVolume( int percentage ) emit volumeChanged( percentage ); } - void AudioEngine::mute() { diff --git a/src/libtomahawk/audio/audioengine.h b/src/libtomahawk/audio/audioengine.h index 05b3b1bd5..d423c7321 100644 --- a/src/libtomahawk/audio/audioengine.h +++ b/src/libtomahawk/audio/audioengine.h @@ -68,7 +68,7 @@ public slots: void setVolume( int percentage ); void lowerVolume() { setVolume( volume() - AUDIO_VOLUME_STEP ); } void raiseVolume() { setVolume( volume() + AUDIO_VOLUME_STEP ); } - void onVolumeChanged( float volume ) { emit volumeChanged( volume * 100 ); } + void onVolumeChanged( qreal volume ) { emit volumeChanged( volume * 100 ); } void mute(); void playItem( PlaylistInterface* playlist, const Tomahawk::result_ptr& result ); From 21479dbe0be8a90c6465f94d8c34c00985eb0827 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Mon, 6 Jun 2011 08:53:41 -0400 Subject: [PATCH 48/53] set volume on startup too, from phonon --- src/libtomahawk/audio/audioengine.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 04fc7fcfc..2ae3c1bb9 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -64,6 +64,8 @@ AudioEngine::AudioEngine() connect( m_mediaObject, SIGNAL( aboutToFinish() ), SLOT( onAboutToFinish() ) ); connect( m_audioOutput, SIGNAL( volumeChanged( qreal ) ), this, SLOT( onVolumeChanged( qreal ) ) ); + + onVolumeChanged( m_audioOutput->volume() ); } From 1ff142616ea6067cb8d162bf2b5bc3fcfb4f8116 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Mon, 6 Jun 2011 16:28:11 -0400 Subject: [PATCH 49/53] remove old settings dialog.ui, just caused confusion --- src/CMakeLists.txt | 1 - src/settingsdialog.ui | 740 ------------------------------------------ thirdparty/jreen | 2 +- 3 files changed, 1 insertion(+), 742 deletions(-) delete mode 100644 src/settingsdialog.ui diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b19d127d2..a7d4dc7d1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -118,7 +118,6 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui} SET( tomahawkUI ${tomahawkUI} tomahawkwindow.ui - settingsdialog.ui diagnosticsdialog.ui stackedsettingsdialog.ui proxydialog.ui diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui deleted file mode 100644 index 3ccf7d55e..000000000 --- a/src/settingsdialog.ui +++ /dev/null @@ -1,740 +0,0 @@ - - - SettingsDialog - - - - 0 - 0 - 621 - 434 - - - - - 0 - 353 - - - - Music Player Settings - - - - - - 0 - - - - Accounts - - - - - - 0 - - - false - - - false - - - true - - - true - - - false - - - - - - - - Jabber - - - - 16 - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - Jabber ID: - - - jabberUsername - - - - - - - - 0 - 0 - - - - e.g. user@example.com - - - - - - - - 0 - 0 - - - - Password: - - - jabberPassword - - - - - - - - 0 - 0 - - - - - - - QLineEdit::Password - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 8 - - - - - - - - true - - - - 0 - 0 - - - - Advanced Jabber Settings - - - - - - - - - 0 - 0 - - - - - 50 - 0 - - - - Server: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - jabberServer - - - - - - - - 0 - 0 - - - - - - - - Port: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 90 - 0 - - - - - 90 - 16777215 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 65535 - - - 5222 - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - Network - - - - - - - 0 - 0 - - - - Advanced Network Settings - - - - - - - - - - - - 0 - 0 - - - - If you're having difficulty connecting to peers, try setting this to your external IP address/host name and a port number (default 50210). Make sure to forward that port to this machine! - - - true - - - - - - - - - - 0 - 0 - - - - Static Host Name: - - - - - - - - - - - 0 - 0 - - - - Static Port: - - - - - - - 65535 - - - 50210 - - - - - - - - - Qt::RightToLeft - - - Always use static host name/port? (Overrides UPnP discovery/port forwarding) - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Proxy Settings... - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::RightToLeft - - - Playdar HTTP API - - - true - - - - - - - Qt::RightToLeft - - - Connect automatically when Tomahawk starts - - - true - - - - - - - Qt::RightToLeft - - - Use UPnP to establish port forward - - - true - - - - - - - - - - - Local Music - - - - 16 - - - - - - - Path to scan for music files: - - - - - - - - - - - - ... - - - - - - - - - - 0 - 0 - - - - Watch for changes - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Last.fm - - - - 16 - - - - - Scrobble tracks to Last.fm - - - - - - - Last.fm Login - - - - - - - - Username: - - - - - - - - - - Password: - - - - - - - QLineEdit::Password - - - - - - - - - Test Login - - - - - - - Qt::Vertical - - - - 20 - 221 - - - - - - - - - - - - Script Resolvers - - - - - - Loaded script resolvers: - - - - - - - - - true - - - QAbstractItemView::SingleSelection - - - false - - - true - - - false - - - true - - - true - - - - - - - - - - - - - :/data/images/list-add.png:/data/images/list-add.png - - - - - - - - - - - :/data/images/list-remove.png:/data/images/list-remove.png - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - SettingsDialog - accept() - - - 402 - 348 - - - 157 - 274 - - - - - buttonBox - rejected() - SettingsDialog - reject() - - - 470 - 348 - - - 286 - 274 - - - - - diff --git a/thirdparty/jreen b/thirdparty/jreen index 2957d0ff0..8f995f246 160000 --- a/thirdparty/jreen +++ b/thirdparty/jreen @@ -1 +1 @@ -Subproject commit 2957d0ff03d9561af8afc4bd3a45947392868875 +Subproject commit 8f995f246637f533feb7124744e113034a32b505 From b392151c56679ed46363556cb103e72efb867d15 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Tue, 7 Jun 2011 18:12:38 -0700 Subject: [PATCH 50/53] Make Tomahawk link handling cleaner and less hackish (lfranchi++). Move openLinkFromHash to GlobalActionManager, to keep Tomahawk link handling simple. --- src/libtomahawk/globalactionmanager.cpp | 32 ++++++++++++++++--- src/libtomahawk/globalactionmanager.h | 4 +++ .../infosystem/infoplugins/adiumplugin.cpp | 3 +- src/libtomahawk/infosystem/infosystem.cpp | 28 ---------------- src/libtomahawk/infosystem/infosystem.h | 2 -- 5 files changed, 33 insertions(+), 36 deletions(-) diff --git a/src/libtomahawk/globalactionmanager.cpp b/src/libtomahawk/globalactionmanager.cpp index 5a1807e00..d49dad75b 100644 --- a/src/libtomahawk/globalactionmanager.cpp +++ b/src/libtomahawk/globalactionmanager.cpp @@ -60,7 +60,6 @@ GlobalActionManager::~GlobalActionManager() QUrl GlobalActionManager::openLinkFromQuery( const Tomahawk::query_ptr& query ) const { - QUrl link( "tomahawk://open/track/" ); QString title, artist, album; if( !query->results().isEmpty() && !query->results().first().isNull() ) @@ -75,6 +74,30 @@ GlobalActionManager::openLinkFromQuery( const Tomahawk::query_ptr& query ) const album = query->album(); } + return openLink( title, artist, album ); +} + +QUrl +GlobalActionManager::openLinkFromHash( const Tomahawk::InfoSystem::InfoCriteriaHash& hash ) const +{ + QString title, artist, album; + + if( !hash.isEmpty() && hash.contains( "title" ) && hash.contains( "artist" ) ) + { + title = hash["title"]; + artist = hash["artist"]; + if( hash.contains( "album" ) ) + album = hash["album"]; + } + + return openLink( title, artist, album ); +} + +QUrl +GlobalActionManager::openLink( const QString& title, const QString& artist, const QString& album ) const +{ + QUrl link( "tomahawk://open/track/" ); + if( !title.isEmpty() ) link.addQueryItem( "title", title ); if( !artist.isEmpty() ) @@ -165,13 +188,12 @@ GlobalActionManager::copyToClipboard( const Tomahawk::query_ptr& query ) const bool GlobalActionManager::parseTomahawkLink( const QString& url ) { - QString decodedUrl = QString::fromUtf8( QByteArray::fromPercentEncoding( url.toAscii() ).data() ); - if( decodedUrl.contains( "tomahawk://" ) ) { - QString cmd = decodedUrl.mid( 11 ); + if( url.contains( "tomahawk://" ) ) { + QString cmd = url.mid( 11 ); qDebug() << "Parsing tomahawk link command" << cmd; QString cmdType = cmd.split( "/" ).first(); - QUrl u( cmd ); + QUrl u = QUrl::fromEncoded( cmd.toUtf8() ); // for backwards compatibility if( cmdType == "load" ) { diff --git a/src/libtomahawk/globalactionmanager.h b/src/libtomahawk/globalactionmanager.h index c7b9d71dc..4d1f1313c 100644 --- a/src/libtomahawk/globalactionmanager.h +++ b/src/libtomahawk/globalactionmanager.h @@ -23,6 +23,7 @@ #include "playlist.h" #include "query.h" #include "playlist/dynamic/DynamicPlaylist.h" +#include "infosystem/infosystem.h" #include "dllmacro.h" #include @@ -36,6 +37,7 @@ public: virtual ~GlobalActionManager(); QUrl openLinkFromQuery( const Tomahawk::query_ptr& query ) const; + QUrl openLinkFromHash( const Tomahawk::InfoSystem::InfoCriteriaHash& hash ) const; void copyToClipboard( const Tomahawk::query_ptr& query ) const; QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist ); @@ -68,6 +70,8 @@ private: bool doQueueAdd( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems ); + QUrl openLink( const QString& title, const QString& artist, const QString& album ) const; + Tomahawk::playlist_ptr m_toShow; Tomahawk::query_ptr m_waitingToBookmark; Tomahawk::query_ptr m_waitingToPlay; diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index 4ea87c920..6bb93587d 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -22,6 +22,7 @@ #include "artist.h" #include "result.h" #include "tomahawksettings.h" +#include "globalactionmanager.h" #include "adiumplugin.h" #include "adium.h" @@ -139,7 +140,7 @@ AdiumPlugin::audioStarted( const QVariant &input ) nowPlaying.append(" - "); nowPlaying.append( hash["artist"] ); nowPlaying.append( " " ); - nowPlaying.append( openLinkFromHash( hash ).toString() ); + nowPlaying.append( GlobalActionManager::instance()->openLinkFromHash( hash ).toEncoded() ); setStatus( nowPlaying ); } diff --git a/src/libtomahawk/infosystem/infosystem.cpp b/src/libtomahawk/infosystem/infosystem.cpp index 0a163c9bb..62c18380d 100644 --- a/src/libtomahawk/infosystem/infosystem.cpp +++ b/src/libtomahawk/infosystem/infosystem.cpp @@ -44,34 +44,6 @@ InfoPlugin::~InfoPlugin() qDebug() << Q_FUNC_INFO; } -QUrl -InfoPlugin::openLinkFromHash( const InfoCriteriaHash& hash ) const -{ - QUrl link( "tomahawk://open/track/" ); - QString title, artist, album; - - if( !hash.isEmpty() && hash.contains( "title" ) && hash.contains( "artist" ) ) - { - title = hash["title"]; - artist = hash["artist"]; - if( hash.contains( "album" ) ) - qDebug() << "Album is: " << album; - album = hash["album"]; - } - - if( !title.isEmpty() ) - link.addEncodedQueryItem( "title", QUrl::toPercentEncoding( title ) ); - if( !artist.isEmpty() ) - link.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artist ) ); - if( !album.isEmpty() ) - link.addEncodedQueryItem( "album", QUrl::toPercentEncoding( album ) ); - - // Add encoding for spaces, since QUrl does not - QUrl encodedLink( link.toString().replace(" ", "%20"), QUrl::StrictMode ); - - return encodedLink; -} - InfoSystem* InfoSystem::s_instance = 0; InfoSystem* diff --git a/src/libtomahawk/infosystem/infosystem.h b/src/libtomahawk/infosystem/infosystem.h index e1728d798..d96657d1f 100644 --- a/src/libtomahawk/infosystem/infosystem.h +++ b/src/libtomahawk/infosystem/infosystem.h @@ -134,8 +134,6 @@ protected slots: virtual void namChangedSlot( QNetworkAccessManager *nam ) = 0; protected: - QUrl openLinkFromHash( const InfoCriteriaHash& hash ) const; - InfoType m_type; QSet< InfoType > m_supportedGetTypes; QSet< InfoType > m_supportedPushTypes; From 8ca84e9ba2553de237eda9533d68c0edebadb6c8 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Tue, 7 Jun 2011 18:50:27 -0700 Subject: [PATCH 51/53] Use just openLink in GAM to avoid including InfoSystem, and deal with the InfoCriteriaHash in the plguin. --- src/libtomahawk/globalactionmanager.cpp | 16 ---------------- src/libtomahawk/globalactionmanager.h | 5 +---- .../infosystem/infoplugins/adiumplugin.cpp | 18 +++++++++++++++++- .../infosystem/infoplugins/adiumplugin.h | 8 +++++--- thirdparty/jreen | 2 +- 5 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/libtomahawk/globalactionmanager.cpp b/src/libtomahawk/globalactionmanager.cpp index d49dad75b..e98702b24 100644 --- a/src/libtomahawk/globalactionmanager.cpp +++ b/src/libtomahawk/globalactionmanager.cpp @@ -77,22 +77,6 @@ GlobalActionManager::openLinkFromQuery( const Tomahawk::query_ptr& query ) const return openLink( title, artist, album ); } -QUrl -GlobalActionManager::openLinkFromHash( const Tomahawk::InfoSystem::InfoCriteriaHash& hash ) const -{ - QString title, artist, album; - - if( !hash.isEmpty() && hash.contains( "title" ) && hash.contains( "artist" ) ) - { - title = hash["title"]; - artist = hash["artist"]; - if( hash.contains( "album" ) ) - album = hash["album"]; - } - - return openLink( title, artist, album ); -} - QUrl GlobalActionManager::openLink( const QString& title, const QString& artist, const QString& album ) const { diff --git a/src/libtomahawk/globalactionmanager.h b/src/libtomahawk/globalactionmanager.h index 4d1f1313c..5e5e11928 100644 --- a/src/libtomahawk/globalactionmanager.h +++ b/src/libtomahawk/globalactionmanager.h @@ -23,7 +23,6 @@ #include "playlist.h" #include "query.h" #include "playlist/dynamic/DynamicPlaylist.h" -#include "infosystem/infosystem.h" #include "dllmacro.h" #include @@ -37,7 +36,7 @@ public: virtual ~GlobalActionManager(); QUrl openLinkFromQuery( const Tomahawk::query_ptr& query ) const; - QUrl openLinkFromHash( const Tomahawk::InfoSystem::InfoCriteriaHash& hash ) const; + QUrl openLink( const QString& title, const QString& artist, const QString& album ) const; void copyToClipboard( const Tomahawk::query_ptr& query ) const; QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist ); @@ -70,8 +69,6 @@ private: bool doQueueAdd( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems ); - QUrl openLink( const QString& title, const QString& artist, const QString& album ) const; - Tomahawk::playlist_ptr m_toShow; Tomahawk::query_ptr m_waitingToBookmark; Tomahawk::query_ptr m_waitingToPlay; diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index 6bb93587d..ecfcb90aa 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -140,10 +140,26 @@ AdiumPlugin::audioStarted( const QVariant &input ) nowPlaying.append(" - "); nowPlaying.append( hash["artist"] ); nowPlaying.append( " " ); - nowPlaying.append( GlobalActionManager::instance()->openLinkFromHash( hash ).toEncoded() ); + nowPlaying.append( openLinkFromHash( hash ).toEncoded() ); setStatus( nowPlaying ); } +QUrl +AdiumPlugin::openLinkFromHash( const Tomahawk::InfoSystem::InfoCriteriaHash& hash ) const +{ + QString title, artist, album; + + if( !hash.isEmpty() && hash.contains( "title" ) && hash.contains( "artist" ) ) + { + title = hash["title"]; + artist = hash["artist"]; + if( hash.contains( "album" ) ) + album = hash["album"]; + } + + return GlobalActionManager::instance()->openLink( title, artist, album ); +} + void AdiumPlugin::audioFinished( const QVariant &input ) { diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.h b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h index 776f62585..724c97ca3 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.h +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.h @@ -41,6 +41,10 @@ protected slots: void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input ); public slots: + void namChangedSlot( QNetworkAccessManager *nam ) {} // unused + void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ) {} // unused + +private: void settingsChanged(); void audioStarted( const QVariant &input ); @@ -49,10 +53,8 @@ public slots: void audioPaused(); void audioResumed( const QVariant &input ); - void namChangedSlot( QNetworkAccessManager *nam ) {} // unused - void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ) {} // unused + QUrl openLinkFromHash( const InfoCriteriaHash& hash ) const; -private: bool m_active; QString m_beforeStatus; QString m_afterStatus; diff --git a/thirdparty/jreen b/thirdparty/jreen index 8f995f246..2957d0ff0 160000 --- a/thirdparty/jreen +++ b/thirdparty/jreen @@ -1 +1 @@ -Subproject commit 8f995f246637f533feb7124744e113034a32b505 +Subproject commit 2957d0ff03d9561af8afc4bd3a45947392868875 From 3277ad7802f926f72f6ca5e262d984135f2917b2 Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Wed, 8 Jun 2011 01:37:52 -0700 Subject: [PATCH 52/53] Parse the "+" of a Tomahawk link as a space. Adium plugin defaults to using toma.hk links now. --- src/libtomahawk/globalactionmanager.cpp | 7 ++++--- src/libtomahawk/globalactionmanager.h | 2 +- src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/globalactionmanager.cpp b/src/libtomahawk/globalactionmanager.cpp index e98702b24..bf60833f6 100644 --- a/src/libtomahawk/globalactionmanager.cpp +++ b/src/libtomahawk/globalactionmanager.cpp @@ -78,9 +78,9 @@ GlobalActionManager::openLinkFromQuery( const Tomahawk::query_ptr& query ) const } QUrl -GlobalActionManager::openLink( const QString& title, const QString& artist, const QString& album ) const +GlobalActionManager::openLink( const QString& title, const QString& artist, const QString& album, bool tomahk ) const { - QUrl link( "tomahawk://open/track/" ); + QUrl link( tomahk ? "http://toma.hk/open/track/" : "tomahawk://open/track/" ); if( !title.isEmpty() ) link.addQueryItem( "title", title ); @@ -172,8 +172,9 @@ GlobalActionManager::copyToClipboard( const Tomahawk::query_ptr& query ) const bool GlobalActionManager::parseTomahawkLink( const QString& url ) { - if( url.contains( "tomahawk://" ) ) { + if( url.contains( "tomahawk://" ) ) { QString cmd = url.mid( 11 ); + cmd.replace( "%2B", "%20" ); qDebug() << "Parsing tomahawk link command" << cmd; QString cmdType = cmd.split( "/" ).first(); diff --git a/src/libtomahawk/globalactionmanager.h b/src/libtomahawk/globalactionmanager.h index 5e5e11928..d8186559a 100644 --- a/src/libtomahawk/globalactionmanager.h +++ b/src/libtomahawk/globalactionmanager.h @@ -36,7 +36,7 @@ public: virtual ~GlobalActionManager(); QUrl openLinkFromQuery( const Tomahawk::query_ptr& query ) const; - QUrl openLink( const QString& title, const QString& artist, const QString& album ) const; + QUrl openLink( const QString& title, const QString& artist, const QString& album, bool tomahk=false ) const; void copyToClipboard( const Tomahawk::query_ptr& query ) const; QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist ); diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index ecfcb90aa..137d22d3e 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -157,7 +157,7 @@ AdiumPlugin::openLinkFromHash( const Tomahawk::InfoSystem::InfoCriteriaHash& has album = hash["album"]; } - return GlobalActionManager::instance()->openLink( title, artist, album ); + return GlobalActionManager::instance()->openLink( title, artist, album, true ); } void From 3da78d7ceeca420ca48541e1c27df4d9fdbed99f Mon Sep 17 00:00:00 2001 From: Alejandro Wainzinger Date: Wed, 8 Jun 2011 17:56:14 -0700 Subject: [PATCH 53/53] Adium plugin now does nothing on pause, and clears status on stop. --- .../infosystem/infoplugins/adiumplugin.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp index 137d22d3e..44bdaeb10 100644 --- a/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp @@ -107,9 +107,9 @@ AdiumPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoTyp case InfoNowPlaying: audioStarted( input ); break; - case InfoNowPaused: - audioPaused(); - break; + // case InfoNowPaused: + // audioPaused(); + // break; case InfoNowResumed: audioResumed( input ); break; @@ -170,16 +170,15 @@ void AdiumPlugin::audioStopped() { qDebug() << Q_FUNC_INFO; - // TODO: audio stopped, so push update status to Adium that says "stopped" - setStatus( "Stopped" ); + setStatus( "" ); } void AdiumPlugin::audioPaused() { qDebug() << Q_FUNC_INFO; - // TODO: audio paused, so push update status to Adium that says "paused" - setStatus( "Paused" ); + + //setStatus( "Paused" ); } void