1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-21 21:25:52 +02:00

Merge branch 'master' of github.com:tomahawk-player/tomahawk

Conflicts:
	src/libtomahawk/tomahawksettings.cpp
	src/libtomahawk/tomahawksettings.h
	src/sip/jreen/jabber.cpp
	src/sip/jreen/jabber.h
	src/tomahawkapp.cpp
	src/tomahawkwindow.h
	thirdparty/jreen
This commit is contained in:
Leo Franchi
2011-05-03 15:56:08 -04:00
58 changed files with 2102 additions and 1186 deletions

View File

@@ -39,6 +39,11 @@ INCLUDE( MacroLogFeature )
set(LIBLASTFM_FOUND true)
find_package(Phonon REQUIRED)
if(PHONON_VERSION STRLESS "4.5.0")
message(FATAL_ERROR "Phonon version 4.5.0 or higher is required, you have version ${PHONON_VERSION}")
else()
message(STATUS "Phonon found; ensure that phonon-vlc is at least 0.4")
endif()
macro_optional_find_package(LibEchonest 1.1.1)
macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest is needed for dynamic playlists and the infosystem")

View File

@@ -31,11 +31,11 @@ else(PHONON_FOUND)
endif(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)
# As discussed on kde-buildsystem: first look at CMAKE_PREFIX_PATH, then at the suggested PATHS (kde4 install dir)
find_library(PHONON_LIBRARY NAMES phonon phonon4 PATHS ${KDE4_LIB_INSTALL_DIR} ${QT_LIBRARY_DIR} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH)
find_library(PHONON_LIBRARY NAMES phonon phonon4 PATHS ${KDE4_LIB_INSTALL_DIR} ${QT_LIBRARY_DIR})
# then at the default system locations (CMAKE_SYSTEM_PREFIX_PATH, i.e. /usr etc.)
find_library(PHONON_LIBRARY NAMES phonon phonon4)
find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h PATHS ${KDE4_INCLUDE_INSTALL_DIR} ${QT_INCLUDE_DIR} ${INCLUDE_INSTALL_DIR} ${QT_LIBRARY_DIR} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH)
find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h PATHS ${KDE4_INCLUDE_INSTALL_DIR} ${QT_INCLUDE_DIR} ${INCLUDE_INSTALL_DIR} ${QT_LIBRARY_DIR})
find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h)
if(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)

View File

@@ -39,6 +39,7 @@ SET( tomahawkSources ${tomahawkSources}
musicscanner.cpp
shortcuthandler.cpp
globalactionmanager.cpp
scanmanager.cpp
tomahawkapp.cpp
main.cpp
@@ -83,6 +84,7 @@ SET( tomahawkHeaders ${tomahawkHeaders}
musicscanner.h
scanmanager.h
shortcuthandler.h
globalactionmanager.h
)
IF(LIBLASTFM_FOUND)

360
src/globalactionmanager.cpp Normal file
View File

@@ -0,0 +1,360 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
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 2 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "globalactionmanager.h"
#include "audio/audioengine.h"
#include "utils/xspfloader.h"
#include "sourcelist.h"
#include "playlist/dynamic/GeneratorInterface.h"
#include "viewmanager.h"
#include "playlist/topbar/topbar.h"
#include "pipeline.h"
#include "database/localcollection.h"
#include "playlist/playlistview.h"
#include "echonest/Playlist.h"
#include <QUrl>
#include <Playlist.h>
GlobalActionManager* GlobalActionManager::s_instance = 0;
GlobalActionManager*
GlobalActionManager::instance()
{
if( !s_instance )
s_instance = new GlobalActionManager;
return s_instance;
}
GlobalActionManager::GlobalActionManager( QObject* parent )
: QObject( parent )
{
}
GlobalActionManager::~GlobalActionManager()
{}
bool
GlobalActionManager::parseTomahawkLink( const QString& url )
{
if( url.contains( "tomahawk://" ) ) {
QString cmd = url.mid( 11 );
qDebug() << "Parsing tomahawk link command" << cmd;
QString cmdType = cmd.split( "/" ).first();
QUrl u( cmd );
// for backwards compatibility
if( cmdType == "load" ) {
if( u.hasQueryItem( "xspf" ) ) {
QUrl xspf = QUrl::fromUserInput( u.queryItemValue( "xspf" ) );
XSPFLoader* l = new XSPFLoader( true, this );
qDebug() << "Loading spiff:" << xspf.toString();
l->load( xspf );
connect( l, SIGNAL( ok( Tomahawk::playlist_ptr ) ), ViewManager::instance(), SLOT( show( Tomahawk::playlist_ptr ) ) );
return true;
}
}
if( cmdType == "playlist" ) {
return handlePlaylistCommand( u );
} else if( cmdType == "collection" ) {
return handleCollectionCommand( u );
} else if( cmdType == "queue" ) {
return handleQueueCommand( u );
} else if( cmdType == "station" ) {
return handleStationCommand( u );
} else if( cmdType == "search" ) {
return handleSearchCommand( u );
} else if( cmdType == "play" ) {
return handlePlayCommand( u );
} else {
qDebug() << "Tomahawk link not supported, command not known!" << cmdType << u.path();
return false;
}
} else {
qDebug() << "Not a tomahawk:// link!";
return false;
}
}
bool
GlobalActionManager::handlePlaylistCommand( const QUrl& url )
{
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
if( parts.isEmpty() ) {
qDebug() << "No specific playlist command:" << url.toString();
return false;
}
if( parts[ 0 ] == "import" ) {
if( !url.hasQueryItem( "xspf" ) ) {
qDebug() << "No xspf to load..";
return false;
}
QUrl xspf = QUrl( url.queryItemValue( "xspf" ) );
QString title = url.hasQueryItem( "title" ) ? url.queryItemValue( "title" ) : QString();
XSPFLoader* l= new XSPFLoader( true, this );
l->setOverrideTitle( title );
l->load( xspf );
connect( l, SIGNAL( ok( Tomahawk::playlist_ptr ) ), ViewManager::instance(), SLOT( show( Tomahawk::playlist_ptr ) ) );
} else if( parts [ 0 ] == "new" ) {
if( !url.hasQueryItem( "title" ) ) {
qDebug() << "New playlist command needs a title...";
return false;
}
Tomahawk::playlist_ptr pl = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), uuid(), url.queryItemValue( "title" ), QString(), QString(), false );
pl->createNewRevision( uuid(), pl->currentrevision(), QList< Tomahawk::plentry_ptr >() );
ViewManager::instance()->show( pl );
} else if( parts[ 0 ] == "add" ) {
if( !url.hasQueryItem( "playlistid" ) || !url.hasQueryItem( "track" ) || !url.hasQueryItem( "artist" ) ) {
qDebug() << "Add to playlist command needs playlistid, track, and artist..." << url.toString();
return false;
}
// TODO implement. Let the user select what playlist to add to
return false;
}
return false;
}
bool
GlobalActionManager::handleCollectionCommand( const QUrl& url )
{
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
if( parts.isEmpty() ) {
qDebug() << "No specific collection command:" << url.toString();
return false;
}
if( parts[ 0 ] == "add" ) {
// TODO implement
}
return false;
}
bool
GlobalActionManager::handleQueueCommand( const QUrl& url )
{
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
if( parts.isEmpty() ) {
qDebug() << "No specific queue command:" << url.toString();
return false;
}
if( parts[ 0 ] == "add" ) {
if( parts.size() > 1 && parts[ 1 ] == "track" ) {
QPair< QString, QString > pair;
foreach( pair, url.queryItems() ) {
if( pair.first != "url" )
continue;
QUrl track = QUrl::fromUserInput( pair.second );
//FIXME: isLocalFile is Qt 4.8
if( track.toString().startsWith( "file://" ) ) { // it's local, so we see if it's in the DB and load it if so
// TODO
} else { // give it a web result hint
// TODO actually read the tags
QFileInfo info( track.path() );
Tomahawk::query_ptr q = Tomahawk::Query::get( QString(), info.baseName(), QString() );
q->setResultHint( track.toString() );
Tomahawk::Pipeline::instance()->resolve( q, true );
ViewManager::instance()->queue()->model()->append( q );
ViewManager::instance()->showQueue();
}
return true;
}
} else {
qDebug() << "Only queue/add/track is support at the moment, got:" << parts;
return false;
}
}
return false;
}
bool
GlobalActionManager::handleSearchCommand( const QUrl& url )
{
// open the super collection and set this as the search filter
QStringList query;
if( url.hasQueryItem( "artist" ) )
query << url.queryItemValue( "artist" );
if( url.hasQueryItem( "album" ) )
query << url.queryItemValue( "album" );
if( url.hasQueryItem( "track" ) )
query << url.queryItemValue( "track" );
QString queryStr = query.join( " " );
if( queryStr.isEmpty() )
return false;
ViewManager::instance()->showSuperCollection();
ViewManager::instance()->topbar()->setFilter( queryStr );
return true;
}
bool
GlobalActionManager::handleStationCommand( const QUrl& url )
{
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;
}
if( parts[ 0 ] == "create" ) {
if( !url.hasQueryItem( "title" ) || !url.hasQueryItem( "type" ) ) {
qDebug() << "Station create command needs title and type..." << url.toString();
return false;
}
QString title = url.queryItemValue( "title" );
QString type = url.queryItemValue( "type" );
Tomahawk::dynplaylist_ptr pl = Tomahawk::DynamicPlaylist::create( SourceList::instance()->getLocal(), uuid(), title, QString(), QString(), Tomahawk::OnDemand, false, type );
QList< Tomahawk::dyncontrol_ptr > controls;
QPair< QString, QString > param;
foreach( param, url.queryItems() ) {
if( param.first == "artist" ) {
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Artist" );
c->setInput( param.second );
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistRadioType ) );
controls << c;
} /*else if( param.first == "hotttnesss" ) { TODO
Tomahawk::dyncontrol_ptr c = pl->generator()->createControl( "Artist" );
c->setInput( param.second );
c->setMatch( 0 );
controls << c;
} */
}
pl->createNewRevision( uuid(), pl->currentrevision(), type, controls );
return true;
}
return false;
}
bool
GlobalActionManager::handlePlayCommand( const QUrl& url )
{
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
if( parts.isEmpty() ) {
qDebug() << "No specific play command:" << url.toString();
return false;
}
if( parts[ 0 ] == "track" ) {
QPair< QString, QString > pair;
QString title, artist, album, urlStr;
foreach( pair, url.queryItems() ) {
if( pair.first == "track" )
title = pair.second;
else if( pair.first == "artist" )
artist = pair.second;
else if( pair.first == "album" )
album = pair.second;
else if( pair.first == "url" )
urlStr = pair.second;
}
Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album );
if( !urlStr.isEmpty() )
q->setResultHint( urlStr );
Tomahawk::Pipeline::instance()->resolve( q, true );
// now we add it to the special "bookmarks" playlist, creating it if it doesn't exist. if nothing is playing, start playing the track
QSharedPointer< LocalCollection > col = SourceList::instance()->getLocal()->collection().dynamicCast< LocalCollection >();
Tomahawk::playlist_ptr bookmarkpl = col->bookmarksPlaylist();
if( bookmarkpl.isNull() ) { // create it and do the deed then
m_waitingToBookmark = q;
col->createBookmarksPlaylist();
connect( col.data(), SIGNAL( bookmarkPlaylistCreated( Tomahawk::playlist_ptr ) ), this, SLOT( bookmarkPlaylistCreated( Tomahawk::playlist_ptr ) ), Qt::UniqueConnection );
} else {
doBookmark( bookmarkpl, q );
}
return true;
}
return false;
}
void
GlobalActionManager::bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl )
{
Q_ASSERT( !m_waitingToBookmark.isNull() );
doBookmark( pl, m_waitingToBookmark );
}
void
GlobalActionManager::doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahawk::query_ptr& q )
{
Tomahawk::plentry_ptr e( new Tomahawk::PlaylistEntry );
e->setGuid( uuid() );
if ( q->results().count() )
e->setDuration( q->results().at( 0 )->duration() );
else
e->setDuration( 0 );
e->setLastmodified( 0 );
e->setAnnotation( "" ); // FIXME
e->setQuery( q );
pl->createNewRevision( uuid(), pl->currentrevision(), QList< Tomahawk::plentry_ptr >( pl->entries() ) << e );
connect( pl.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( showPlaylist() ) );
m_toShow = pl;
// if nothing is playing, lets start this
// TODO
if( !AudioEngine::instance()->isPlaying() ) {
connect( q.data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( waitingForResolved( bool ) ) );
m_waitingToPlay = q;
}
m_waitingToBookmark.clear();
}
void
GlobalActionManager::showPlaylist()
{
if( m_toShow.isNull() )
return;
ViewManager::instance()->show( m_toShow );
m_toShow.clear();
}
void
GlobalActionManager::waitingForResolved( bool success )
{
if( success && !m_waitingToPlay.isNull() && !m_waitingToPlay->results().isEmpty() ) { // play it!
AudioEngine::instance()->playItem( AudioEngine::instance()->playlist(), m_waitingToPlay->results().first() );
}
m_waitingToPlay.clear();
}

61
src/globalactionmanager.h Normal file
View File

@@ -0,0 +1,61 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
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 2 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef GLOBALACTIONMANAGER_H
#define GLOBALACTIONMANAGER_H
#include "playlist.h"
#include <QObject>
#include <QUrl>
class GlobalActionManager : public QObject
{
Q_OBJECT
public:
static GlobalActionManager* instance();
virtual ~GlobalActionManager();
public slots:
bool parseTomahawkLink( const QString& link );
void waitingForResolved( bool );
private slots:
void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl );
void showPlaylist();
private:
explicit GlobalActionManager( QObject* parent = 0 );
void doBookmark( const Tomahawk::playlist_ptr& pl, const Tomahawk::query_ptr& q );
bool handlePlaylistCommand( const QUrl& url );
bool handleCollectionCommand(const QUrl& url );
bool handleQueueCommand(const QUrl& url );
bool handleStationCommand(const QUrl& url );
bool handleSearchCommand(const QUrl& url );
bool handlePlayCommand(const QUrl& url );
Tomahawk::playlist_ptr m_toShow;
Tomahawk::query_ptr m_waitingToBookmark;
Tomahawk::query_ptr m_waitingToPlay;
static GlobalActionManager* s_instance;
};
#endif // GLOBALACTIONMANAGER_H

View File

@@ -21,6 +21,7 @@ set( libSources
artist.cpp
album.cpp
collection.cpp
webcollection.cpp
playlist.cpp
resolver.cpp
query.cpp
@@ -38,6 +39,7 @@ set( libSources
database/database.cpp
database/fuzzyindex.cpp
database/databasecollection.cpp
database/localcollection.cpp
database/databaseworker.cpp
database/databaseimpl.cpp
database/databaseresolver.cpp
@@ -66,7 +68,6 @@ set( libSources
database/databasecommand_renameplaylist.cpp
database/databasecommand_loadops.cpp
database/databasecommand_updatesearchindex.cpp
database/databasecollection.cpp
database/databasecommand_setdynamicplaylistrevision.cpp
database/databasecommand_createdynamicplaylist.cpp
database/databasecommand_loaddynamicplaylist.cpp
@@ -79,6 +80,7 @@ set( libSources
infosystem/infosystemcache.cpp
infosystem/infosystem.cpp
infosystem/infosystemworker.cpp
infosystem/infoplugins/echonestplugin.cpp
infosystem/infoplugins/lastfmplugin.cpp
infosystem/infoplugins/musixmatchplugin.cpp
@@ -174,6 +176,7 @@ set( libHeaders
aclsystem.h
collection.h
webcollection.h
query.h
resolver.h
result.h
@@ -223,6 +226,7 @@ set( libHeaders
database/databasecommand_loadops.h
database/databasecommand_updatesearchindex.h
database/databasecollection.h
database/localcollection.h
database/databasecommand_setdynamicplaylistrevision.h
database/databasecommand_createdynamicplaylist.h
database/databasecommand_loaddynamicplaylist.h
@@ -233,6 +237,7 @@ set( libHeaders
database/databasecommand_clientauthvalid.h
infosystem/infosystem.h
infosystem/infosystemworker.h
infosystem/infosystemcache.h
infosystem/infoplugins/echonestplugin.h
infosystem/infoplugins/lastfmplugin.h

View File

@@ -113,12 +113,6 @@ AudioEngine::stop()
m_expectStop = true;
m_mediaObject->stop();
if ( !m_input.isNull() )
{
m_input->close();
m_input.clear();
}
setCurrentTrack( Tomahawk::result_ptr() );
emit stopped();
}
@@ -198,8 +192,6 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
m_expectStop = true;
}
m_input = io;
if ( !m_currentTrack->url().startsWith( "http://" ) )
{
m_mediaObject->setCurrentSource( io.data() );
@@ -215,6 +207,9 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
}
m_mediaObject->setCurrentSource( furl );
}
m_input = io;
m_mediaObject->currentSource().setAutoDelete( true );
m_mediaObject->play();

View File

@@ -41,7 +41,7 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
{
qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint();
Tomahawk::result_ptr result = lib->result( m_query->resultHint() );
Tomahawk::result_ptr result = lib->resultFromHint( m_query );
if ( !result.isNull() && result->collection()->source()->isOnline() )
{
res << result;
@@ -119,7 +119,7 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
s = SourceList::instance()->get( files_query.value( 13 ).toUInt() );
if( s.isNull() )
{
Q_ASSERT( false );
qDebug() << "WTF: Could not find source" << files_query.value( 13 ).toUInt();
continue;
}

View File

@@ -149,6 +149,8 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib )
QString resultHint;
if ( !e->query()->results().isEmpty() )
resultHint = e->query()->results().first()->url();
else if ( !e->query()->resultHint().isEmpty() )
resultHint = e->query()->resultHint();
adde.bindValue( 0, e->guid() );
adde.bindValue( 1, m_playlistguid );

View File

@@ -528,8 +528,9 @@ DatabaseImpl::album( int id )
Tomahawk::result_ptr
DatabaseImpl::result( const QString& url )
DatabaseImpl::resultFromHint( const Tomahawk::query_ptr& origquery )
{
QString url = origquery->resultHint();
TomahawkSqlQuery query = newquery();
Tomahawk::source_ptr s;
Tomahawk::result_ptr res;
@@ -552,7 +553,18 @@ DatabaseImpl::result( const QString& url )
else
{
// Q_ASSERT( false );
qDebug() << "We don't support non-servent / non-file result-hints yet.";
// qDebug() << "We don't support non-servent / non-file result-hints yet.";
res = Tomahawk::result_ptr( new Tomahawk::Result() );
s = SourceList::instance()->webSource();
res->setUrl( url );
res->setCollection( s->collection() );
res->setRID( uuid() );
res->setScore( 1.0 );
res->setArtist( Tomahawk::artist_ptr( new Tomahawk::Artist( 0, origquery->artist() ) ) );
res->setAlbum( Tomahawk::album_ptr( new Tomahawk::Album( 0, origquery->album(), res->artist() ) ) );
res->setTrack( origquery->track() );
res->setDuration( origquery->duration() );
res->setFriendlySource( url );
return res;
}

View File

@@ -64,7 +64,7 @@ public:
QVariantMap album( int id );
QVariantMap track( int id );
Tomahawk::result_ptr file( int fid );
Tomahawk::result_ptr result( const QString& url );
Tomahawk::result_ptr resultFromHint( const Tomahawk::query_ptr& query );
static bool scorepairSorter( const QPair<int,float>& left, const QPair<int,float>& right )
{

View File

@@ -0,0 +1,61 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
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 2 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "localcollection.h"
#include "sourcelist.h"
#include "viewmanager.h"
#include <tomahawksettings.h>
LocalCollection::LocalCollection( const Tomahawk::source_ptr& source, QObject* parent )
: DatabaseCollection( source, parent )
{
}
Tomahawk::playlist_ptr
LocalCollection::bookmarksPlaylist()
{
if( TomahawkSettings::instance()->bookmarkPlaylist().isEmpty() )
return Tomahawk::playlist_ptr();
return playlist( TomahawkSettings::instance()->bookmarkPlaylist() );
}
void
LocalCollection::createBookmarksPlaylist()
{
if( bookmarksPlaylist().isNull() ) {
QString guid = uuid();
Tomahawk::playlist_ptr p = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), guid, tr( "Bookmarks" ), tr( "Saved tracks" ), QString(), false );
ViewManager::instance()->createPageForPlaylist( p );
// connect( p.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( loaded( Tomahawk::PlaylistRevision ) ), Qt::QueuedConnection );
connect( p.data(), SIGNAL( created() ), this, SLOT( created() ) );
TomahawkSettings::instance()->setBookmarkPlaylist( guid );
// p->createNewRevision( uuid(), p->currentrevision(), QList< Tomahawk::plentry_ptr >() );
}
}
void
LocalCollection::created()
{
emit bookmarkPlaylistCreated( bookmarksPlaylist() );
}

View File

@@ -0,0 +1,46 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
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 2 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef LOCALCOLLECTION_H
#define LOCALCOLLECTION_H
#include "databasecollection.h"
#include "dllmacro.h"
#include "playlist.h"
class DLLEXPORT LocalCollection : public DatabaseCollection
{
Q_OBJECT
public:
explicit LocalCollection( const Tomahawk::source_ptr& source, QObject* parent = 0 );
// gets the playlist used for storing stuff from the web, if it already exists. if the returned playlist
// is invalid ask to create and listen to the signal
Tomahawk::playlist_ptr bookmarksPlaylist();
void createBookmarksPlaylist();
signals:
void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& p );
private slots:
void created();
};
#endif // LOCALCOLLECTION_H

View File

@@ -25,13 +25,16 @@ using namespace Echonest;
// for internal neatness
EchoNestPlugin::EchoNestPlugin(QObject *parent)
EchoNestPlugin::EchoNestPlugin(InfoSystemWorker *parent)
: InfoPlugin(parent)
, m_infoSystemWorker( parent )
{
qDebug() << Q_FUNC_INFO;
QSet< InfoType > supportedTypes;
supportedTypes << Tomahawk::InfoSystem::InfoArtistBiography << Tomahawk::InfoSystem::InfoArtistFamiliarity << Tomahawk::InfoSystem::InfoArtistHotttness << Tomahawk::InfoSystem::InfoArtistTerms << Tomahawk::InfoSystem::InfoMiscTopTerms;
qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes);
parent->registerInfoTypes( this, supportedTypes, QSet< InfoType>() );
connect( parent, SIGNAL( namChanged() ), SLOT( namChangedSlot() ) );
}
EchoNestPlugin::~EchoNestPlugin()
@@ -39,6 +42,13 @@ EchoNestPlugin::~EchoNestPlugin()
qDebug() << Q_FUNC_INFO;
}
void
EchoNestPlugin::namChangedSlot()
{
qDebug() << Q_FUNC_INFO;
Echonest::Config::instance()->setNetworkAccessManager( m_infoSystemWorker->nam() );
}
void
EchoNestPlugin::getInfo(const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData)
{

View File

@@ -20,6 +20,7 @@
#define ECHONESTPLUGIN_H
#include "infosystem/infosystem.h"
#include "infosystem/infosystemworker.h"
#include <QObject>
@@ -39,12 +40,31 @@ class EchoNestPlugin : public InfoPlugin
Q_OBJECT
public:
EchoNestPlugin(QObject *parent);
EchoNestPlugin( InfoSystemWorker *parent );
virtual ~EchoNestPlugin();
protected slots:
virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData );
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data )
{
Q_UNUSED( caller );
Q_UNUSED( type );
Q_UNUSED( data );
}
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData )
{
Q_UNUSED( criteria );
Q_UNUSED( caller );
Q_UNUSED( type );
Q_UNUSED( input );
Q_UNUSED( customData );
}
public slots:
void namChangedSlot();
private:
void getSongProfile( const QString &caller, const QVariant &input, const InfoCustomData &customData, const QString &item = QString() );
void getArtistBiography ( const QString &caller, const QVariant &input, const InfoCustomData &customData );
@@ -67,6 +87,7 @@ private slots:
private:
QHash< QNetworkReply*, InfoCustomData > m_replyMap;
QHash< QNetworkReply*, QString > m_callerMap;
InfoSystemWorker* m_infoSystemWorker;
};
}

View File

@@ -41,14 +41,18 @@ md5( const QByteArray& src )
}
LastFmPlugin::LastFmPlugin( QObject* parent )
LastFmPlugin::LastFmPlugin( InfoSystemWorker* parent )
: InfoPlugin(parent)
, m_scrobbler( 0 )
, m_authJob( 0 )
, m_infoSystemWorker( parent )
{
QSet< InfoType > supportedTypes;
supportedTypes << InfoMiscSubmitScrobble << InfoMiscSubmitNowPlaying << InfoAlbumCoverArt << InfoArtistImages;
qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes);
QSet< InfoType > supportedGetTypes, supportedPushTypes;
supportedGetTypes << InfoAlbumCoverArt << InfoArtistImages;
supportedPushTypes << InfoSubmitScrobble << InfoSubmitNowPlaying;
parent->registerInfoTypes( this, supportedGetTypes, supportedPushTypes );
connect( parent, SIGNAL( namChanged() ), SLOT( namChangedSlot() ) );
/*
Your API Key is 7194b85b6d1f424fe1668173a78c0c4a
@@ -94,6 +98,14 @@ LastFmPlugin::~LastFmPlugin()
}
void
LastFmPlugin::namChangedSlot()
{
qDebug() << Q_FUNC_INFO;
lastfm::setNetworkAccessManager( m_infoSystemWorker->nam() );
}
void
LastFmPlugin::dataError( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData )
{
@@ -109,14 +121,6 @@ LastFmPlugin::getInfo( const QString caller, const Tomahawk::InfoSystem::InfoTyp
switch ( type )
{
case InfoMiscSubmitNowPlaying:
nowPlaying( caller, type, input, customData );
break;
case InfoMiscSubmitScrobble:
scrobble( caller, type, input, customData );
break;
case InfoArtistImages:
fetchArtistImages( caller, type, input, customData );
break;
@@ -132,19 +136,34 @@ LastFmPlugin::getInfo( const QString caller, const Tomahawk::InfoSystem::InfoTyp
void
LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData )
LastFmPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input )
{
qDebug() << Q_FUNC_INFO;
switch ( type )
{
case InfoSubmitNowPlaying:
nowPlaying( caller, type, input );
break;
case InfoSubmitScrobble:
scrobble( caller, type, input );
break;
default:
return;
}
}
void
LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVariant &input )
{
if ( !input.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() || !m_scrobbler )
{
dataError( caller, type, input, customData );
return;
}
InfoCriteriaHash hash = input.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
if ( !hash.contains( "title" ) || !hash.contains( "artist" ) || !hash.contains( "album" ) || !hash.contains( "duration" ) )
{
dataError( caller, type, input, customData );
return;
}
m_track = lastfm::MutableTrack();
m_track.stamp();
@@ -157,26 +176,20 @@ LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVar
m_track.setSource( lastfm::Track::Player );
m_scrobbler->nowPlaying( m_track );
emit info( caller, type, input, QVariant(), customData );
}
void
LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData )
LastFmPlugin::scrobble( const QString &caller, const InfoType type, const QVariant &input )
{
Q_ASSERT( QThread::currentThread() == thread() );
if ( !m_scrobbler || m_track.isNull() )
{
dataError( caller, type, input, customData );
return;
}
qDebug() << Q_FUNC_INFO << m_track.toString();
m_scrobbler->cache( m_track );
m_scrobbler->submit();
emit info( caller, type, input, QVariant(), customData );
}
@@ -241,7 +254,7 @@ LastFmPlugin::notInCacheSlot( const QHash<QString, QString> criteria, const QStr
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=album.imageredirect&artist=%1&album=%2&autocorrect=1&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b";
QNetworkRequest req( imgurl.arg( artistName ).arg( albumName ) );
QNetworkReply* reply = TomahawkUtils::nam()->get( req );
QNetworkReply* reply = m_infoSystemWorker->nam()->get( req );
reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) );
reply->setProperty( "origData", input );
reply->setProperty( "caller", caller );
@@ -257,7 +270,7 @@ LastFmPlugin::notInCacheSlot( const QHash<QString, QString> criteria, const QStr
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=artist.imageredirect&artist=%1&autocorrect=1&size=medium&api_key=7a90f6672a04b809ee309af169f34b8b";
QNetworkRequest req( imgurl.arg( artistName ) );
QNetworkReply* reply = TomahawkUtils::nam()->get( req );
QNetworkReply* reply = m_infoSystemWorker->nam()->get( req );
reply->setProperty( "customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>( customData ) );
reply->setProperty( "origData", input );
reply->setProperty( "caller", caller );
@@ -312,7 +325,7 @@ LastFmPlugin::coverArtReturned()
{
// Follow HTTP redirect
QNetworkRequest req( redir );
QNetworkReply* newReply = TomahawkUtils::nam()->get( req );
QNetworkReply* newReply = m_infoSystemWorker->nam()->get( req );
newReply->setProperty( "origData", reply->property( "origData" ) );
newReply->setProperty( "customData", reply->property( "customData" ) );
newReply->setProperty( "caller", reply->property( "caller" ) );
@@ -362,7 +375,7 @@ LastFmPlugin::artistImagesReturned()
{
// Follow HTTP redirect
QNetworkRequest req( redir );
QNetworkReply* newReply = TomahawkUtils::nam()->get( req );
QNetworkReply* newReply = m_infoSystemWorker->nam()->get( req );
newReply->setProperty( "origData", reply->property( "origData" ) );
newReply->setProperty( "customData", reply->property( "customData" ) );
newReply->setProperty( "caller", reply->property( "caller" ) );

View File

@@ -19,6 +19,7 @@
#ifndef LASTFMPLUGIN_H
#define LASTFMPLUGIN_H
#include "infosystem/infosystem.h"
#include "infosystem/infosystemworker.h"
#include "result.h"
#include <lastfm/Track>
@@ -40,7 +41,7 @@ class LastFmPlugin : public InfoPlugin
Q_OBJECT
public:
LastFmPlugin( QObject *parent );
LastFmPlugin( InfoSystemWorker *parent );
virtual ~LastFmPlugin();
public slots:
@@ -50,17 +51,21 @@ public slots:
void coverArtReturned();
void artistImagesReturned();
void namChangedSlot();
protected slots:
virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData );
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData );
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data );
private:
void fetchCoverArt( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
void fetchArtistImages( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
void createScrobbler();
void scrobble( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
void nowPlaying( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
void scrobble( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input );
void nowPlaying( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input );
void dataError( const QString &caller, const Tomahawk::InfoSystem::InfoType type, const QVariant &input, const Tomahawk::InfoSystem::InfoCustomData &customData );
@@ -71,6 +76,8 @@ private:
QList< QUrl > m_badUrls;
QNetworkReply* m_authJob;
InfoSystemWorker* m_infoSystemWorker;
};
}

View File

@@ -27,14 +27,15 @@ using namespace Tomahawk::InfoSystem;
// for internal neatness
MusixMatchPlugin::MusixMatchPlugin(QObject *parent)
MusixMatchPlugin::MusixMatchPlugin(InfoSystemWorker *parent)
: InfoPlugin(parent)
, m_apiKey("61be4ea5aea7dd942d52b2f1311dd9fe")
, m_infoSystemWorker( parent )
{
qDebug() << Q_FUNC_INFO;
QSet< InfoType > supportedTypes;
supportedTypes << Tomahawk::InfoSystem::InfoTrackLyrics;
qobject_cast< InfoSystem* >(parent)->registerInfoTypes(this, supportedTypes);
parent->registerInfoTypes( this, supportedTypes, QSet< InfoType>() );
}
MusixMatchPlugin::~MusixMatchPlugin()
@@ -62,7 +63,7 @@ MusixMatchPlugin::getInfo( const QString caller, const Tomahawk::InfoSystem::Inf
url.addQueryItem("apikey", m_apiKey);
url.addQueryItem("q_artist", artist);
url.addQueryItem("q_track", track);
QNetworkReply* reply = TomahawkUtils::nam()->get(QNetworkRequest(url));
QNetworkReply* reply = m_infoSystemWorker->nam()->get(QNetworkRequest(url));
reply->setProperty("customData", QVariant::fromValue<Tomahawk::InfoSystem::InfoCustomData>(customData));
reply->setProperty("origData", input);
reply->setProperty("caller", caller);
@@ -120,7 +121,7 @@ MusixMatchPlugin::trackSearchSlot()
QUrl url(requestString);
url.addQueryItem("apikey", m_apiKey);
url.addQueryItem("track_id", track_id);
QNetworkReply* newReply = TomahawkUtils::nam()->get(QNetworkRequest(url));
QNetworkReply* newReply = m_infoSystemWorker->nam()->get(QNetworkRequest(url));
newReply->setProperty("origData", oldReply->property("origData"));
newReply->setProperty("customData", oldReply->property("customData"));
newReply->setProperty("caller", oldReply->property("caller"));

View File

@@ -20,6 +20,7 @@
#define MUSIXMATCHPLUGIN_H
#include "infosystem/infosystem.h"
#include "infosystem/infosystemworker.h"
class QNetworkReply;
@@ -34,7 +35,7 @@ class MusixMatchPlugin : public InfoPlugin
Q_OBJECT
public:
MusixMatchPlugin( QObject *parent );
MusixMatchPlugin( InfoSystemWorker *parent );
virtual ~MusixMatchPlugin();
public slots:
@@ -44,10 +45,28 @@ public slots:
protected slots:
virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData );
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data )
{
Q_UNUSED( caller );
Q_UNUSED( type );
Q_UNUSED( data );
}
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData )
{
Q_UNUSED( criteria );
Q_UNUSED( caller );
Q_UNUSED( type );
Q_UNUSED( input );
Q_UNUSED( customData );
}
private:
bool isValidTrackData( const QString &caller, const QVariant &input, const InfoCustomData &customData );
QString m_apiKey;
InfoSystemWorker* m_infoSystemWorker;
};
}

View File

@@ -19,6 +19,7 @@
#include <QCoreApplication>
#include "infosystem.h"
#include "tomahawksettings.h"
#include "utils/tomahawkutils.h"
#include "infosystemcache.h"
#include "infoplugins/echonestplugin.h"
@@ -31,7 +32,7 @@ namespace Tomahawk
namespace InfoSystem
{
InfoPlugin::InfoPlugin(QObject *parent)
InfoPlugin::InfoPlugin( InfoSystemWorker *parent )
:QObject( parent )
{
qDebug() << Q_FUNC_INFO;
@@ -59,59 +60,33 @@ InfoSystem::InfoSystem(QObject *parent)
m_cache->moveToThread( m_infoSystemCacheThreadController );
m_infoSystemCacheThreadController->start( QThread::IdlePriority );
InfoPluginPtr enptr( new EchoNestPlugin( this ) );
m_plugins.append( enptr );
InfoPluginPtr mmptr( new MusixMatchPlugin( this ) );
m_plugins.append( mmptr );
InfoPluginPtr lfmptr( new LastFmPlugin( this ) );
m_plugins.append( lfmptr );
m_infoSystemWorkerThreadController = new QThread( this );
m_worker = new InfoSystemWorker();
m_worker->moveToThread( m_infoSystemWorkerThreadController );
m_infoSystemWorkerThreadController->start();
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
{
connect(
plugin.data(),
SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
this,
SLOT( infoSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
Qt::UniqueConnection
);
QMetaObject::invokeMethod( m_worker, "init", Qt::QueuedConnection );
connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( newNam() ) );
connect(
plugin.data(),
SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
m_cache,
SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
);
connect(
m_cache,
SIGNAL( notInCache( Tomahawk::InfoSystem::InfoCriteriaHash, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
plugin.data(),
SLOT( notInCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
);
connect(
plugin.data(),
SIGNAL( updateCache( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
m_cache,
SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) )
);
}
connect( m_cache, SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
this, SLOT( infoSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ), Qt::UniqueConnection );
connect( m_worker, SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
this, SLOT( infoSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ), Qt::UniqueConnection );
}
InfoSystem::~InfoSystem()
{
qDebug() << Q_FUNC_INFO;
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
{
if( plugin )
delete plugin.data();
}
if ( m_infoSystemCacheThreadController )
m_infoSystemCacheThreadController->quit();
if ( m_infoSystemWorkerThreadController )
m_infoSystemWorkerThreadController->quit();
if( m_infoSystemCacheThreadController )
{
m_infoSystemCacheThreadController->quit();
while( !m_infoSystemCacheThreadController->isFinished() )
{
QCoreApplication::processEvents( QEventLoop::AllEvents, 200 );
@@ -127,56 +102,73 @@ InfoSystem::~InfoSystem()
delete m_infoSystemCacheThreadController;
m_infoSystemCacheThreadController = 0;
}
if( m_infoSystemWorkerThreadController )
{
while( !m_infoSystemWorkerThreadController->isFinished() )
{
QCoreApplication::processEvents( QEventLoop::AllEvents, 200 );
TomahawkUtils::Sleep::msleep( 100 );
}
void InfoSystem::registerInfoTypes(const InfoPluginPtr &plugin, const QSet< InfoType >& types)
if( m_worker )
{
delete m_worker;
m_worker = 0;
}
delete m_infoSystemWorkerThreadController;
m_infoSystemWorkerThreadController = 0;
}
}
void
InfoSystem::newNam() const
{
qDebug() << Q_FUNC_INFO;
Q_FOREACH(InfoType type, types)
m_infoMap[type].append(plugin);
QMetaObject::invokeMethod( m_worker, "newNam", Qt::QueuedConnection );
}
QLinkedList< InfoPluginPtr > InfoSystem::determineOrderedMatches(const InfoType type) const
{
//Dummy function for now that returns the various items in the QSet; at some point this will
//probably need to support ordering based on the data source
QLinkedList< InfoPluginPtr > providers;
Q_FOREACH(InfoPluginPtr ptr, m_infoMap[type])
providers << ptr;
return providers;
}
void InfoSystem::getInfo(const QString &caller, const InfoType type, const QVariant& input, InfoCustomData customData)
void
InfoSystem::getInfo( const QString &caller, const InfoType type, const QVariant& input, InfoCustomData customData )
{
qDebug() << Q_FUNC_INFO;
QLinkedList< InfoPluginPtr > providers = determineOrderedMatches(type);
if (providers.isEmpty())
{
emit info(caller, InfoNoInfo, QVariant(), QVariant(), customData);
emit finished(caller);
return;
}
InfoPluginPtr ptr = providers.first();
if (!ptr)
{
emit info(caller, InfoNoInfo, QVariant(), QVariant(), customData);
emit finished(caller);
return;
}
m_dataTracker[caller][type] = m_dataTracker[caller][type] + 1;
qDebug() << "current count in dataTracker for type" << type << "is" << m_dataTracker[caller][type];
QMetaObject::invokeMethod( ptr.data(), "getInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ), Q_ARG( Tomahawk::InfoSystem::InfoCustomData, customData ) );
QMetaObject::invokeMethod( m_worker, "getInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ), Q_ARG( Tomahawk::InfoSystem::InfoCustomData, customData ) );
}
void InfoSystem::getInfo(const QString &caller, const InfoMap &input, InfoCustomData customData)
void
InfoSystem::getInfo( const QString &caller, const InfoMap &input, InfoCustomData customData )
{
Q_FOREACH( InfoType type, input.keys() )
getInfo( caller, type, input[type], customData );
}
void InfoSystem::infoSlot(QString target, InfoType type, QVariant input, QVariant output, InfoCustomData customData)
void
InfoSystem::pushInfo( const QString &caller, const InfoType type, const QVariant& input )
{
qDebug() << Q_FUNC_INFO;
QMetaObject::invokeMethod( m_worker, "pushInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ) );
}
void
InfoSystem::pushInfo( const QString &caller, const InfoMap &input )
{
Q_FOREACH( InfoType type, input.keys() )
pushInfo( caller, type, input[type] );
}
void
InfoSystem::infoSlot( QString target, InfoType type, QVariant input, QVariant output, InfoCustomData customData )
{
qDebug() << Q_FUNC_INFO;
qDebug() << "current count in dataTracker is " << m_dataTracker[target][type];

View File

@@ -36,62 +36,63 @@ namespace Tomahawk {
namespace InfoSystem {
class InfoSystemCache;
class InfoSystemWorker;
enum InfoType {
enum InfoType { // as items are saved in cache, mark them here to not change them
InfoTrackID = 0,
InfoTrackArtist,
InfoTrackAlbum,
InfoTrackGenre,
InfoTrackComposer,
InfoTrackDate,
InfoTrackNumber,
InfoTrackDiscNumber,
InfoTrackBitRate,
InfoTrackLength,
InfoTrackSampleRate,
InfoTrackFileSize,
InfoTrackBPM,
InfoTrackReplayGain,
InfoTrackReplayPeakGain,
InfoTrackLyrics,
InfoTrackLocation,
InfoTrackProfile,
InfoTrackEnergy,
InfoTrackDanceability,
InfoTrackTempo,
InfoTrackLoudness,
InfoTrackArtist = 1,
InfoTrackAlbum = 2,
InfoTrackGenre = 3,
InfoTrackComposer = 4,
InfoTrackDate = 5,
InfoTrackNumber = 6,
InfoTrackDiscNumber = 7,
InfoTrackBitRate = 8,
InfoTrackLength = 9,
InfoTrackSampleRate = 10,
InfoTrackFileSize = 11,
InfoTrackBPM = 12,
InfoTrackReplayGain = 13,
InfoTrackReplayPeakGain = 14,
InfoTrackLyrics = 15,
InfoTrackLocation = 16,
InfoTrackProfile = 17,
InfoTrackEnergy = 18,
InfoTrackDanceability = 19,
InfoTrackTempo = 20,
InfoTrackLoudness = 21,
InfoArtistID,
InfoArtistName,
InfoArtistBiography,
InfoArtistBlog,
InfoArtistFamiliarity,
InfoArtistHotttness,
InfoArtistImages,
InfoArtistNews,
InfoArtistProfile,
InfoArtistReviews,
InfoArtistSongs,
InfoArtistSimilars,
InfoArtistTerms,
InfoArtistLinks,
InfoArtistVideos,
InfoArtistID = 22,
InfoArtistName = 23,
InfoArtistBiography = 24,
InfoArtistBlog = 25,
InfoArtistFamiliarity = 26,
InfoArtistHotttness = 27,
InfoArtistImages = 28,
InfoArtistNews = 29,
InfoArtistProfile = 30,
InfoArtistReviews = 31,
InfoArtistSongs = 32,
InfoArtistSimilars = 33,
InfoArtistTerms = 34,
InfoArtistLinks = 35,
InfoArtistVideos = 36,
InfoAlbumID,
InfoAlbumName,
InfoAlbumArtist,
InfoAlbumDate,
InfoAlbumGenre,
InfoAlbumComposer,
InfoAlbumCoverArt,
InfoAlbumID = 37,
InfoAlbumName = 38,
InfoAlbumArtist = 39,
InfoAlbumDate = 40,
InfoAlbumGenre = 41,
InfoAlbumComposer = 42,
InfoAlbumCoverArt = 43, //cached -- do not change
InfoMiscTopHotttness,
InfoMiscTopTerms,
InfoMiscTopHotttness = 44,
InfoMiscTopTerms = 45,
InfoMiscSubmitNowPlaying,
InfoMiscSubmitScrobble,
InfoSubmitNowPlaying = 46,
InfoSubmitScrobble = 47,
InfoNoInfo
InfoNoInfo = 48
};
typedef QMap< InfoType, QVariant > InfoMap;
@@ -104,12 +105,9 @@ class DLLEXPORT InfoPlugin : public QObject
Q_OBJECT
public:
InfoPlugin( QObject *parent );
InfoPlugin( InfoSystemWorker *parent );
virtual ~InfoPlugin()
{
qDebug() << Q_FUNC_INFO;
}
virtual ~InfoPlugin() {}
signals:
void getCachedInfo( Tomahawk::InfoSystem::InfoCriteriaHash criteria, qint64 newMaxAge, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
@@ -119,16 +117,8 @@ signals:
protected slots:
virtual void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data, const Tomahawk::InfoSystem::InfoCustomData customData ) = 0;
//FIXME: Make pure virtual when everything supports it
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData )
{
Q_UNUSED( criteria );
Q_UNUSED( caller );
Q_UNUSED( type );
Q_UNUSED( input );
Q_UNUSED( customData );
}
virtual void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant data ) = 0;
virtual void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ) = 0;
protected:
InfoType m_type;
@@ -139,13 +129,6 @@ private:
typedef QWeakPointer< InfoPlugin > InfoPluginPtr;
class DLLEXPORT InfoSystemWorker : public QObject
{
Q_OBJECT
InfoSystemWorker() {};
~InfoSystemWorker() {};
};
class DLLEXPORT InfoSystem : public QObject
{
Q_OBJECT
@@ -156,12 +139,12 @@ public:
InfoSystem( QObject *parent );
~InfoSystem();
void registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType > &types );
void getInfo( const QString &caller, const InfoType type, const QVariant &input, InfoCustomData customData );
void getInfo( const QString &caller, const InfoMap &input, InfoCustomData customData );
void pushInfo( const QString &caller, const InfoType type, const QVariant &input );
void pushInfo( const QString &caller, const InfoMap &input );
InfoSystemCache* getCache() { return m_cache; }
InfoSystemCache* getCache() const { return m_cache; }
signals:
void info( QString caller, Tomahawk::InfoSystem::InfoType, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
@@ -170,14 +153,9 @@ signals:
public slots:
void infoSlot( const QString target, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const QVariant output, const Tomahawk::InfoSystem::InfoCustomData customData );
void newNam() const;
private:
QLinkedList< InfoPluginPtr > determineOrderedMatches( const InfoType type ) const;
QMap< InfoType, QLinkedList< InfoPluginPtr > > m_infoMap;
// For now, statically instantiate plugins; this is just somewhere to keep them
QLinkedList< InfoPluginPtr > m_plugins;
QHash< QString, QHash< InfoType, int > > m_dataTracker;
InfoSystemCache* m_cache;

View File

@@ -0,0 +1,190 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <QCoreApplication>
#include <QNetworkConfiguration>
#include <QNetworkProxy>
#include "infosystemworker.h"
#include "utils/tomahawkutils.h"
#include "infosystemcache.h"
#include "infoplugins/echonestplugin.h"
#include "infoplugins/musixmatchplugin.h"
#include "infoplugins/lastfmplugin.h"
namespace Tomahawk
{
namespace InfoSystem
{
InfoSystemWorker::InfoSystemWorker()
: m_nam( 0 )
{
qDebug() << Q_FUNC_INFO;
}
InfoSystemWorker::~InfoSystemWorker()
{
qDebug() << Q_FUNC_INFO;
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
{
if( plugin )
delete plugin.data();
}
}
void InfoSystemWorker::init()
{
InfoPluginPtr enptr( new EchoNestPlugin( this ) );
m_plugins.append( enptr );
InfoPluginPtr mmptr( new MusixMatchPlugin( this ) );
m_plugins.append( mmptr );
InfoPluginPtr lfmptr( new LastFmPlugin( this ) );
m_plugins.append( lfmptr );
InfoSystemCache *cache = InfoSystem::instance()->getCache();
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
{
connect(
plugin.data(),
SIGNAL( info( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
InfoSystem::instance(),
SLOT( infoSlot( QString, Tomahawk::InfoSystem::InfoType, QVariant, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
Qt::UniqueConnection
);
connect(
plugin.data(),
SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
cache,
SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
);
connect(
cache,
SIGNAL( notInCache( Tomahawk::InfoSystem::InfoCriteriaHash, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
plugin.data(),
SLOT( notInCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
);
connect(
plugin.data(),
SIGNAL( updateCache( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
cache,
SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) )
);
}
QMetaObject::invokeMethod( this, "newNam" );
}
void
InfoSystemWorker::registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType >& getTypes, const QSet< InfoType >& pushTypes )
{
qDebug() << Q_FUNC_INFO;
Q_FOREACH( InfoType type, getTypes )
m_infoGetMap[type].append( plugin );
Q_FOREACH( InfoType type, pushTypes )
m_infoPushMap[type].append( plugin );
}
QLinkedList< InfoPluginPtr >
InfoSystemWorker::determineOrderedMatches( const InfoType type ) const
{
//Dummy function for now that returns the various items in the QSet; at some point this will
//probably need to support ordering based on the data source
QLinkedList< InfoPluginPtr > providers;
Q_FOREACH( InfoPluginPtr ptr, m_infoGetMap[type] )
providers << ptr;
return providers;
}
void
InfoSystemWorker::getInfo( QString caller, InfoType type, QVariant input, InfoCustomData customData )
{
qDebug() << Q_FUNC_INFO;
QLinkedList< InfoPluginPtr > providers = determineOrderedMatches(type);
if ( providers.isEmpty() )
{
emit info( caller, type, QVariant(), QVariant(), customData );
return;
}
InfoPluginPtr ptr = providers.first();
if ( !ptr )
{
emit info( caller, type, QVariant(), QVariant(), customData );
return;
}
QMetaObject::invokeMethod( ptr.data(), "getInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ), Q_ARG( Tomahawk::InfoSystem::InfoCustomData, customData ) );
}
void
InfoSystemWorker::pushInfo( const QString caller, const InfoType type, const QVariant input )
{
qDebug() << Q_FUNC_INFO;
Q_FOREACH( InfoPluginPtr ptr, m_infoPushMap[type] )
{
if( ptr )
QMetaObject::invokeMethod( ptr.data(), "pushInfo", Qt::QueuedConnection, Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QVariant, input ) );
}
}
QNetworkAccessManager*
InfoSystemWorker::nam() const
{
return m_nam;
}
void
InfoSystemWorker::newNam()
{
qDebug() << Q_FUNC_INFO;
QNetworkAccessManager *newNam = new QNetworkAccessManager();
if ( m_nam )
{
delete m_nam;
}
QNetworkAccessManager *oldNam = TomahawkUtils::nam();
if ( !oldNam )
{
m_nam = newNam;
return;
}
newNam->setConfiguration( oldNam->configuration() );
newNam->setNetworkAccessible( oldNam->networkAccessible() );
newNam->setProxy( oldNam->proxy() );
m_nam = newNam;
emit namChanged();
}
} //namespace InfoSystem
} //namespace Tomahawk

View File

@@ -0,0 +1,76 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TOMAHAWK_INFOSYSTEMWORKER_H
#define TOMAHAWK_INFOSYSTEMWORKER_H
#include "infosystem/infosystem.h"
#include <QNetworkAccessManager>
#include <QtCore/QObject>
#include <QtCore/QtDebug>
#include <QtCore/QMap>
#include <QtCore/QWeakPointer>
#include <QtCore/QSet>
#include <QtCore/QLinkedList>
#include <QtCore/QVariant>
#include "dllmacro.h"
namespace Tomahawk {
namespace InfoSystem {
class DLLEXPORT InfoSystemWorker : public QObject
{
Q_OBJECT
public:
InfoSystemWorker();
~InfoSystemWorker();
void registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType > &getTypes, const QSet< InfoType > &pushTypes );
QNetworkAccessManager* nam() const;
signals:
void info( QString target, Tomahawk::InfoSystem::InfoType, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
void namChanged();
public slots:
void init();
void getInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData );
void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input );
void newNam();
private:
QLinkedList< InfoPluginPtr > determineOrderedMatches( const InfoType type ) const;
// For now, statically instantiate plugins; this is just somewhere to keep them
QLinkedList< InfoPluginPtr > m_plugins;
QMap< InfoType, QLinkedList< InfoPluginPtr > > m_infoGetMap;
QMap< InfoType, QLinkedList< InfoPluginPtr > > m_infoPushMap;
QNetworkAccessManager *m_nam;
};
}
}
#endif // TOMAHAWK_INFOSYSTEMWORKER_H

View File

@@ -496,13 +496,13 @@ Servent::connectToPeer( const QString& ha, int port, const QString &key, const Q
void
Servent::connectToPeer( const QString& ha, int port, const QString &key, Connection* conn )
{
qDebug() << "Servent::connectToPeer:" << ha << ":" << port
<< thread() << QThread::currentThread();
Q_ASSERT( port > 0 );
Q_ASSERT( conn );
// Q_ASSERT( this->thread() == QThread::currentThread() );
qDebug() << "Servent::connectToPeer:" << ha << ":" << port
<< thread() << QThread::currentThread();
if ( ( ha == m_externalAddress.toString() || ha == m_externalHostname ) &&
( port == m_externalPort ) )
{

View File

@@ -118,10 +118,10 @@ DynamicPlaylist::create( const Tomahawk::source_ptr& author,
const QString& info,
const QString& creator,
GeneratorMode mode,
bool shared )
bool shared,
const QString& type
)
{
// default generator
QString type = "";
dynplaylist_ptr dynplaylist = dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared ) );
DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist );

View File

@@ -82,7 +82,8 @@ public:
const QString& info,
const QString& creator,
GeneratorMode mode,
bool shared
bool shared,
const QString& type = QString()
);
static bool remove( const dynplaylist_ptr& playlist );

View File

@@ -55,6 +55,18 @@ SourceList::getLocal()
return m_local;
}
void
SourceList::setWebSource( const source_ptr& websrc )
{
m_dummy = websrc;
}
const
source_ptr SourceList::webSource() const
{
return m_dummy;
}
void
SourceList::loadSources()

View File

@@ -40,6 +40,9 @@ public:
const Tomahawk::source_ptr& getLocal();
void setLocal( const Tomahawk::source_ptr& localSrc );
void setWebSource( const Tomahawk::source_ptr& websrc );
const Tomahawk::source_ptr webSource() const;
void removeAllRemote();
QList<Tomahawk::source_ptr> sources( bool onlyOnline = false ) const;
@@ -66,6 +69,7 @@ private:
QMap< int, QString > m_sources_id2name;
Tomahawk::source_ptr m_local;
Tomahawk::source_ptr m_dummy;
mutable QMutex m_mut; // mutable so const methods can use a lock
static SourceList* s_instance;

View File

@@ -377,6 +377,18 @@ TomahawkSettings::appendRecentlyPlayedPlaylist( const Tomahawk::playlist_ptr& pl
setValue( "playlists/recentlyPlayed", playlist_guids );
}
QString
TomahawkSettings::bookmarkPlaylist() const
{
return value( "playlists/bookmark", QString() ).toString();
}
void
TomahawkSettings::setBookmarkPlaylist( const QString& guid )
{
setValue( "playlists/bookmark", guid );
}
QStringList
TomahawkSettings::sipPlugins() const
{

View File

@@ -73,6 +73,9 @@ public:
void setSipPlugins( const QStringList& plugins );
QStringList sipPlugins() const;
void setBookmarkPlaylist( const QString& guid );
QString bookmarkPlaylist() const;
// just the enabled sip plugins.
void setEnabledSipPlugins( const QStringList& list );
QStringList enabledSipPlugins() const;

View File

@@ -29,6 +29,12 @@
using namespace Tomahawk;
void
XSPFLoader::setOverrideTitle( const QString& newTitle )
{
m_overrideTitle = newTitle;
}
void
XSPFLoader::load( const QUrl& url )
@@ -116,13 +122,15 @@ XSPFLoader::gotBody()
m_title = origTitle;
if ( m_title.isEmpty() )
m_title = tr( "New Playlist" );
if( !m_overrideTitle.isEmpty() )
m_title = m_overrideTitle;
bool shownError = false;
for ( unsigned int i = 0; i < tracklist.length(); i++ )
{
QDomNode e = tracklist.at( i );
QString artist, album, track, duration, annotation;
QString artist, album, track, duration, annotation, url;
QDomElement n = e.firstChildElement();
for ( ; !n.isNull(); n = n.nextSiblingElement() ) {
if (n.namespaceURI() == m_NS && n.localName() == "duration") {
@@ -135,6 +143,8 @@ XSPFLoader::gotBody()
album = n.text();
} else if (n.namespaceURI() == m_NS && n.localName() == "title") {
track = n.text();
} else if (n.namespaceURI() == m_NS && n.localName() == "url") {
url = n.text();
}
}
@@ -154,6 +164,8 @@ XSPFLoader::gotBody()
p->setQuery( Tomahawk::Query::get( artist, track, album, uuid() ) );
p->query()->setDuration( duration.toInt() / 1000 );
if( !url.isEmpty() )
p->query()->setResultHint( url );
m_entries << p;
}

View File

@@ -53,6 +53,7 @@ public:
QList< Tomahawk::plentry_ptr > entries() const { return m_entries; }
void setOverrideTitle( const QString& newTitle );
signals:
void failed();
void ok( const Tomahawk::playlist_ptr& );
@@ -70,7 +71,7 @@ private:
void gotBody();
bool m_autoCreate;
QString m_NS;
QString m_NS,m_overrideTitle;
QList< Tomahawk::plentry_ptr > m_entries;
QString m_title, m_info, m_creator;

View File

@@ -149,6 +149,22 @@ ViewManager::queue() const
return m_queueView->queue();
}
PlaylistView*
ViewManager::createPageForPlaylist( const playlist_ptr& pl )
{
PlaylistView* view = new PlaylistView();
PlaylistModel* model = new PlaylistModel();
view->setPlaylistModel( model );
view->setFrameShape( QFrame::NoFrame );
view->setAttribute( Qt::WA_MacShowFocusRect, 0 );
model->loadPlaylist( pl );
pl->resolve();
m_playlistViews.insert( pl, view );
return view;
}
Tomahawk::ViewPage*
ViewManager::show( const Tomahawk::playlist_ptr& playlist )
@@ -156,15 +172,7 @@ ViewManager::show( const Tomahawk::playlist_ptr& playlist )
PlaylistView* view;
if ( !m_playlistViews.contains( playlist ) )
{
view = new PlaylistView();
PlaylistModel* model = new PlaylistModel();
view->setPlaylistModel( model );
view->setFrameShape( QFrame::NoFrame );
view->setAttribute( Qt::WA_MacShowFocusRect, 0 );
model->loadPlaylist( playlist );
playlist->resolve();
m_playlistViews.insert( playlist, view );
view = createPageForPlaylist( playlist );
}
else
{

View File

@@ -67,6 +67,7 @@ public:
QWidget* widget() const { return m_widget; }
PlaylistView* queue() const;
TopBar* topbar() const { return m_topbar; }
bool isSuperCollectionVisible() const;
bool isNewPlaylistPageVisible() const;
@@ -76,14 +77,6 @@ public:
Tomahawk::ViewPage* pageForInterface( PlaylistInterface* interface ) const;
int positionInHistory( Tomahawk::ViewPage* page ) const;
// Returns the shown viewpage
Tomahawk::ViewPage* show( const Tomahawk::playlist_ptr& playlist );
Tomahawk::ViewPage* show( const Tomahawk::dynplaylist_ptr& playlist );
Tomahawk::ViewPage* show( const Tomahawk::artist_ptr& artist );
Tomahawk::ViewPage* show( const Tomahawk::album_ptr& album );
Tomahawk::ViewPage* show( const Tomahawk::collection_ptr& collection );
Tomahawk::ViewPage* show( const Tomahawk::source_ptr& source );
Tomahawk::ViewPage* show( Tomahawk::ViewPage* page );
Tomahawk::ViewPage* welcomeWidget() const { return m_welcomeWidget; }
@@ -94,6 +87,9 @@ public:
Tomahawk::ViewPage* pageForDynPlaylist( const Tomahawk::dynplaylist_ptr& pl ) const;
Tomahawk::ViewPage* pageForCollection( const Tomahawk::collection_ptr& pl ) const;
// only use this is you need to create a playlist and show it directly and want it to be
// linked to the sidebar. call it right after creating the playlist
PlaylistView* createPageForPlaylist( const Tomahawk::playlist_ptr& pl );
signals:
void numSourcesChanged( unsigned int sources );
void numTracksChanged( unsigned int tracks );
@@ -127,6 +123,14 @@ public slots:
Tomahawk::ViewPage* showWelcomePage();
void showCurrentTrack();
// Returns the shown viewpage
Tomahawk::ViewPage* show( const Tomahawk::playlist_ptr& playlist );
Tomahawk::ViewPage* show( const Tomahawk::dynplaylist_ptr& playlist );
Tomahawk::ViewPage* show( const Tomahawk::artist_ptr& artist );
Tomahawk::ViewPage* show( const Tomahawk::album_ptr& album );
Tomahawk::ViewPage* show( const Tomahawk::collection_ptr& collection );
Tomahawk::ViewPage* show( const Tomahawk::source_ptr& source );
void historyBack();
void historyForward();
void showHistory( int historyPosition );

View File

@@ -0,0 +1,32 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
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 2 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "webcollection.h"
using namespace Tomahawk;
WebCollection::WebCollection( const source_ptr& source, const QString& name, QObject* parent )
: Collection( source, name, parent )
{
}
WebCollection::~WebCollection()
{
}

View File

@@ -0,0 +1,43 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
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 2 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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef WEBCOLLECTION_H
#define WEBCOLLECTION_H
#include "collection.h"
#include "dllmacro.h"
namespace Tomahawk
{
class DLLEXPORT WebCollection : public Collection
{
Q_OBJECT
public:
WebCollection( const source_ptr& source, const QString& name = QString(), QObject* parent = 0 );
virtual ~WebCollection();
virtual void removeTracks( const QDir& ) {}
virtual void addTracks( const QList< QVariant >& ) {}
};
}
#endif // WEBCOLLECTION_H

View File

@@ -80,9 +80,9 @@ Scrobbler::trackStarted( const Tomahawk::result_ptr& track )
trackInfo["artist"] = track->artist()->name();
trackInfo["album"] = track->album()->name();
trackInfo["duration"] = QString::number( track->duration() );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo(
s_scInfoIdentifier, Tomahawk::InfoSystem::InfoMiscSubmitNowPlaying,
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
s_scInfoIdentifier, Tomahawk::InfoSystem::InfoSubmitNowPlaying,
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) );
m_scrobblePoint = ScrobblePoint( track->duration() / 2 );
}
@@ -128,9 +128,9 @@ Scrobbler::scrobble()
{
Q_ASSERT( QThread::currentThread() == thread() );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo(
s_scInfoIdentifier, Tomahawk::InfoSystem::InfoMiscSubmitScrobble,
QVariant(), Tomahawk::InfoSystem::InfoCustomData() );
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
s_scInfoIdentifier, Tomahawk::InfoSystem::InfoSubmitScrobble,
QVariant() );
}
@@ -141,13 +141,7 @@ Scrobbler::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type,
Q_UNUSED( output );
Q_UNUSED( customData );
if ( caller == s_scInfoIdentifier )
{
qDebug() << Q_FUNC_INFO;
if ( type == Tomahawk::InfoSystem::InfoMiscSubmitNowPlaying )
qDebug() << "Scrobbler received now playing response from InfoSystem";
else if ( type == Tomahawk::InfoSystem::InfoMiscSubmitScrobble )
qDebug() << "Scrobbler received scrobble response from InfoSystem";
}
}

View File

@@ -8,7 +8,6 @@ add_definitions( -DSIPDLLEXPORT_PRO )
set( jabberSources
jabber.cpp
jabber_p.cpp
tomahawksipmessage.cpp
tomahawksipmessagefactory.cpp
avatarmanager.cpp
@@ -16,7 +15,6 @@ set( jabberSources
set( jabberHeaders
jabber.h
jabber_p.h
tomahawksipmessage.h
tomahawksipmessagefactory.h
avatarmanager.h

View File

@@ -10,7 +10,6 @@ set( googleHeaders
set( googleSources
../jabber.cpp
../jabber_p.cpp
../tomahawksipmessage.cpp
../tomahawksipmessagefactory.cpp
../avatarmanager.cpp

View File

@@ -19,13 +19,27 @@
#include "jabber.h"
#include "config.h"
#include "tomahawksettings.h"
#include "tomahawksipmessage.h"
#include "tomahawksipmessagefactory.h"
#include <jreen/jid.h>
#include <jreen/capabilities.h>
#include <jreen/vcardupdate.h>
#include <jreen/vcard.h>
#include <qjson/parser.h>
#include <qjson/serializer.h>
#include <QtPlugin>
#include <QStringList>
#include <QInputDialog>
#include <QLineEdit>
#include <QMessageBox>
#include <QDateTime>
#include <QTimer>
#include "ui_configwidget.h"
@@ -41,14 +55,16 @@ JabberFactory::icon() const
return QIcon( ":/jabber-icon.png" );
}
JabberPlugin::JabberPlugin( const QString& pluginId )
: SipPlugin( pluginId )
, p( 0 )
, m_menu( 0 )
, m_addFriendAction( 0 )
, m_state( Disconnected )
{
qDebug() << Q_FUNC_INFO;
qsrand(QDateTime::currentDateTime().toTime_t());
m_configWidget = QWeakPointer< QWidget >( new QWidget );
m_ui = new Ui_JabberConfig;
m_ui->setupUi( m_configWidget.data() );
@@ -60,17 +76,56 @@ JabberPlugin::JabberPlugin( const QString& pluginId )
m_ui->jabberServer->setText( readServer() );
m_ui->jabberPort->setValue( readPort() );
// setup JID object
Jreen::JID jid = Jreen::JID( accountName() );
// general client setup
m_client = new Jreen::Client( jid, m_currentPassword );
m_client->registerStanzaExtension(new TomahawkSipMessageFactory);
m_currentResource = QString::fromAscii( "tomahawk%1" ).arg( QString::number( qrand() % 10000 ) );
m_client->setResource( m_currentResource );
// add VCardUpdate extension to own presence
m_client->presence().addExtension( new Jreen::VCardUpdate() );
// initialize the AvatarManager
m_avatarManager = new AvatarManager( m_client );
// setup disco
m_client->disco()->setSoftwareVersion( "Tomahawk Player", TOMAHAWK_VERSION, CMAKE_SYSTEM );
m_client->disco()->addIdentity( Jreen::Disco::Identity( "client", "type", "tomahawk", "en" ) );
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>();
caps->setNode( TOMAHAWK_CAP_NODE_NAME );
//FIXME: caps->setVersion( TOMAHAWK_VERSION );
// print connection parameters
qDebug() << "Our JID set to:" << m_client->jid().full();
qDebug() << "Our Server set to:" << m_client->server();
qDebug() << "Our Port set to" << m_client->port();
// setup slots
connect(m_client->connection(), SIGNAL(error(SocketError)), SLOT(onError(SocketError)));
connect(m_client, SIGNAL(serverFeaturesReceived(QSet<QString>)), 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(newPresence(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence)));
connect(m_client, SIGNAL(newIQ(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
connect(m_avatarManager, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString)));
}
JabberPlugin::~JabberPlugin()
{
delete p;
}
void
JabberPlugin::setProxy( QNetworkProxy* proxy )
{
p->setProxy( proxy );
qDebug() << Q_FUNC_INFO << "Not implemented";
}
@@ -124,32 +179,13 @@ JabberPlugin::connectPlugin( bool startup )
QString password = m_currentPassword = readPassword();
unsigned int port = m_currentPort = readPort();
QStringList splitJid = jid.split( '@', QString::SkipEmptyParts );
if ( splitJid.size() < 2 )
{
qDebug() << "JID did not have an @ in it, could not find a server part";
return false;
}
qDebug() << "Connecting to the XMPP server..." << (m_state == Connected);
qDebug() << m_client->jid().full();
//m_client->setServer( m_client->jid().domain() );
qDebug() << m_client->server() << m_client->port();
if ( port < 1 || port > 65535 || jid.isEmpty() || password.isEmpty() )
{
qDebug() << "Jabber credentials look wrong, not connecting";
return false;
}
delete p;
p = new Jabber_p( jid, password, ( server.isEmpty() ? QString() : server ), port );
QObject::connect( p, SIGNAL( peerOnline( QString ) ), SIGNAL( peerOnline( QString ) ) );
QObject::connect( p, SIGNAL( peerOffline( QString ) ), SIGNAL( peerOffline( QString ) ) );
QObject::connect( p, SIGNAL( msgReceived( QString, QString ) ), SIGNAL( msgReceived( QString, QString ) ) );
QObject::connect( p, SIGNAL( connected() ), SLOT( onConnected() ) );
QObject::connect( p, SIGNAL( disconnected() ), SLOT( onDisconnected() ) );
QObject::connect( p, SIGNAL( authError( int, QString ) ), SLOT( onAuthError( int, QString ) ) );
QObject::connect( p, SIGNAL( avatarReceived( QString, QPixmap ) ), SIGNAL( avatarReceived( QString, QPixmap ) ) );
QObject::connect( p, SIGNAL( avatarReceived( QPixmap ) ), SIGNAL( avatarReceived( QPixmap) ) );
QTimer::singleShot(1000, m_client, SLOT( connectToServer() ) );
//m_client->connectToServer();
m_state = Connecting;
emit stateChanged( m_state );
@@ -159,58 +195,131 @@ JabberPlugin::connectPlugin( bool startup )
void
JabberPlugin::disconnectPlugin()
{
onDisconnected();
qDebug() << Q_FUNC_INFO << (m_state == Connected);
if ( p )
p->disconnect();
if( m_state == Disconnected )
return;
delete p;
p = 0;
foreach(const Jreen::JID &peer, m_peers.keys())
{
handlePeerStatus(peer, Jreen::Presence::Unavailable);
}
//m_roster->deleteLater();
//m_roster = 0;
//m_room->deleteLater();
//m_room = 0;
m_peers.clear();
m_legacy_peers.clear();
m_client->disconnectFromServer(true);
}
void
JabberPlugin::onConnected()
JabberPlugin::onConnect()
{
if( !m_menu ) {
m_menu = new QMenu( QString( "JREEN (" ).append( accountName() ).append(")" ) );
m_addFriendAction = m_menu->addAction( "Add Friend..." );
QAction *connectAction = m_menu->addAction( "Connect" );
qDebug() << Q_FUNC_INFO;
connect( m_addFriendAction, SIGNAL(triggered() ),
this, SLOT( showAddFriendDialog() ) );
connect( connectAction, SIGNAL( triggered() ), SLOT( connectPlugin() ) );
emit addMenu( m_menu );
// update jid resource, servers like gtalk use resource binding and may
// have changed our requested /resource
if ( m_client->jid().resource() != m_currentResource )
{
m_currentResource = m_client->jid().resource();
emit jidChanged( m_client->jid().full() );
}
qDebug() << "Connected as:" << m_client->jid().full();
// set presence to least valid value
m_client->setPresence(Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127);
// set ping timeout to 15 secs (TODO: verify if this works)
m_client->setPingInterval(1000);
// load roster
m_roster = new Jreen::SimpleRoster( m_client );
m_roster->load();
//FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P
// join MUC with bare jid as nickname
//TODO: make the room a list of rooms and make that configurable
QString mucNickname = QString( "tomahawk@conference.qutim.org/" ).append( QString( m_client->jid().bare() ).replace( "@", "-" ) );
//m_room = new Jreen::MUCRoom(m_client, Jreen::JID( mucNickname ) );
//m_room->setHistorySeconds(0);
//m_room->join();
// treat muc participiants like contacts
//connect( m_room, SIGNAL( messageReceived( Jreen::Message, bool ) ), this, SLOT( onNewMessage( Jreen::Message ) ) );
//connect( m_room, SIGNAL( presenceReceived( Jreen::Presence, const Jreen::MUCRoom::Participant* ) ), this, SLOT( onNewPresence( Jreen::Presence ) ) );
m_state = Connected;
emit stateChanged( m_state );
addMenuHelper();
}
void
JabberPlugin::onDisconnected()
JabberPlugin::onDisconnect( Jreen::Client::DisconnectReason reason )
{
if( m_menu && m_addFriendAction ) {
emit removeMenu( m_menu );
qDebug() << Q_FUNC_INFO;
delete m_menu;
m_menu = 0;
m_addFriendAction = 0; // deleted by menu
}
QString errorMessage;
bool reconnect = false;
int reconnectInSeconds = 0;
m_state = Disconnected;
emit stateChanged( m_state );
}
void
JabberPlugin::onAuthError( int code, const QString& msg )
{
switch( code )
switch( reason )
{
case Jreen::Client::User:
errorMessage = "User Interaction";
break;
case Jreen::Client::HostUnknown:
errorMessage = "Host is unknown";
break;
case Jreen::Client::ItemNotFound:
errorMessage = "Item not found";
break;
case Jreen::Client::AuthorizationError:
emit error( SipPlugin::AuthError, msg );
errorMessage = "Authorization Error";
break;
case Jreen::Client::RemoteStreamError:
errorMessage = "Remote Stream Error";
reconnect = true;
break;
case Jreen::Client::RemoteConnectionFailed:
errorMessage = "Remote Connection failed";
break;
case Jreen::Client::InternalServerError:
errorMessage = "Internal Server Error";
reconnect = true;
break;
case Jreen::Client::SystemShutdown:
errorMessage = "System shutdown";
reconnect = true;
reconnectInSeconds = 60;
break;
case Jreen::Client::Conflict:
errorMessage = "Conflict";
break;
case Jreen::Client::Unknown:
errorMessage = "Unknown";
break;
default:
qDebug() << "Not all Client::DisconnectReasons checked";
Q_ASSERT(false);
break;
}
switch( reason )
{
case Jreen::Client::User:
break;
case Jreen::Client::AuthorizationError:
emit error( SipPlugin::AuthError, errorMessage );
break;
case Jreen::Client::HostUnknown:
@@ -221,7 +330,7 @@ JabberPlugin::onAuthError( int code, const QString& msg )
case Jreen::Client::SystemShutdown:
case Jreen::Client::Conflict:
case Jreen::Client::Unknown:
emit error( SipPlugin::ConnectionError, msg );
emit error( SipPlugin::ConnectionError, errorMessage );
break;
default:
@@ -230,29 +339,97 @@ JabberPlugin::onAuthError( int code, const QString& msg )
break;
}
m_state = Disconnected;
emit stateChanged( m_state );
removeMenuHelper();
if(reconnect)
QTimer::singleShot(reconnectInSeconds*1000, this, SLOT(connectPlugin()));
}
void
JabberPlugin::onAuthError( int code, const QString& msg )
{
}
void
JabberPlugin::sendMsg(const QString& to, const QString& msg)
{
if ( p )
p->sendMsg( to, msg );
qDebug() << Q_FUNC_INFO << to << msg;
if ( !m_client ) {
return;
}
if( m_legacy_peers.contains( to ) )
{
qDebug() << Q_FUNC_INFO << to << "Send legacy message" << msg;
Jreen::Message m( Jreen::Message::Chat, Jreen::JID(to), msg);
m_client->send( m );
return;
}
/*******************************************************
* Obsolete this by a SipMessage class
*/
QJson::Parser parser;
bool ok;
QVariant v = parser.parse( msg.toAscii(), &ok );
if ( !ok || v.type() != QVariant::Map )
{
qDebug() << "Invalid JSON in XMPP msg";
return;
}
QVariantMap m = v.toMap();
/*******************************************************/
TomahawkSipMessage *sipMessage;
if(m["visible"].toBool())
{
sipMessage = new TomahawkSipMessage(m["ip"].toString(),
m["port"].toInt(),
m["uniqname"].toString(),
m["key"].toString(),
m["visible"].toBool()
);
}
else
{
sipMessage = new TomahawkSipMessage();
}
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 );
}
void
JabberPlugin::broadcastMsg(const QString& msg)
{
if ( p )
p->broadcastMsg( msg );
qDebug() << Q_FUNC_INFO;
if ( !m_client )
return;
foreach( const Jreen::JID& jid, m_peers.keys() )
{
sendMsg( jid.full(), msg );
}
}
void
JabberPlugin::addContact(const QString& jid, const QString& msg)
{
if ( p )
p->addContact( jid, msg );
// Add contact to the Tomahawk group on the roster
m_roster->subscribe( jid, msg, jid, QStringList() << "Tomahawk" );
return;
}
void
@@ -287,13 +464,299 @@ JabberPlugin::checkSettings()
m_currentServer = readServer();
m_currentPort = readPort();
if ( reconnect && ( p || readAutoConnect() ) )
if ( reconnect )
{
qDebug() << Q_FUNC_INFO << "Reconnecting jreen plugin...";
disconnectPlugin();
m_currentUsername = accountName();
m_currentPassword = readPassword();
m_currentServer = readServer();
m_currentPort = readPort();
Jreen::JID jid = Jreen::JID( accountName() );
m_client->setJID( jid );
m_client->setPassword( m_currentPassword );
m_client->setServer( m_currentServer );
m_client->setPort( m_currentPort );
qDebug() << Q_FUNC_INFO << "Updated settings";
connectPlugin( false );
}
}
void JabberPlugin::addMenuHelper()
{
if( !m_menu )
{
m_menu = new QMenu( QString( "JREEN (" ).append( accountName() ).append(")" ) );
m_addFriendAction = m_menu->addAction( "Add Friend..." );
connect( m_addFriendAction, SIGNAL( triggered() ), this, SLOT( showAddFriendDialog() ) );
emit addMenu( m_menu );
}
}
void JabberPlugin::removeMenuHelper()
{
if( m_menu && m_addFriendAction )
{
emit removeMenu( m_menu );
delete m_menu;
m_menu = 0;
m_addFriendAction = 0; // deleted by menu
}
}
void JabberPlugin::onNewMessage(const Jreen::Message& message)
{
QString from = message.from().full();
QString msg = message.body();
if ( msg.isEmpty() )
return;
QJson::Parser parser;
bool ok;
QVariant v = parser.parse( msg.toAscii(), &ok );
if ( !ok || v.type() != QVariant::Map )
{
QString to = from;
QString response = QString( tr("I'm sorry -- I'm just an automatic presence used by Tomahawk Player"
" (http://gettomahawk.com). If you are getting this message, the person you"
" are trying to reach is probably not signed on, so please try again later!") );
// this is not a sip message, so we send it directly through the client
m_client->send( Jreen::Message ( Jreen::Message::Chat, Jreen::JID(to), response) );
return;
}
qDebug() << Q_FUNC_INFO << "From:" << message.from().full() << ":" << message.body();
emit msgReceived( from, msg );
}
void JabberPlugin::onNewPresence( const Jreen::Presence& presence)
{
Jreen::JID jid = presence.from();
QString fulljid( jid.full() );
qDebug() << Q_FUNC_INFO << "* New presence: " << fulljid << presence.subtype();
if( jid == m_client->jid() )
return;
if ( presence.error() ) {
//qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: no" << "presence error";
return;
}
// ignore anyone not Running tomahawk:
Jreen::Capabilities::Ptr caps = presence.findExtension<Jreen::Capabilities>();
if ( caps && ( caps->node() == TOMAHAWK_CAP_NODE_NAME ) )
{
// must be a jreen resource, implementation in gloox was broken
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: yes" << "caps " << caps->node();
handlePeerStatus( jid, presence.subtype() );
}
else if( caps )
{
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: maybe" << "caps " << caps->node()
<< "requesting disco..";
// request disco features
QString node = caps->node() + '#' + caps->ver();
Jreen::IQ iq( Jreen::IQ::Get, jid );
iq.addExtension( new Jreen::Disco::Info( node ) );
m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), RequestDisco );
}
else if( !caps )
{
qDebug() << Q_FUNC_INFO << "Running tomahawk: no" << "no caps";
}
}
void JabberPlugin::onNewIq(const Jreen::IQ& iq, int context)
{
if( context == RequestDisco )
{
qDebug() << Q_FUNC_INFO << "Received disco IQ...";
Jreen::Disco::Info *discoInfo = iq.findExtension<Jreen::Disco::Info>().data();
if(!discoInfo)
return;
iq.accept();
Jreen::JID jid = iq.from();
Jreen::DataForm::Ptr form = discoInfo->form();
if(discoInfo->features().contains( TOMAHAWK_FEATURE ))
{
qDebug() << Q_FUNC_INFO << jid.full() << "Running tomahawk/feature enabled: yes";
// the actual presence doesn't matter, it just needs to be "online"
handlePeerStatus( jid, Jreen::Presence::Available );
}
else
{
qDebug() << Q_FUNC_INFO << jid.full() << "Running tomahawk/feature enabled: no";
//LEGACY: accept resources starting with tomahawk too
if( jid.resource().startsWith("tomahawk") )
{
qDebug() << Q_FUNC_INFO << jid.full() << "Detected legacy tomahawk..";
// add to legacy peers, so we can send text messages instead of iqs
m_legacy_peers.append( jid );
handlePeerStatus( jid, Jreen::Presence::Available );
}
}
}
else if(context == RequestedDisco)
{
qDebug() << "Sent IQ(Set), what should be happening here?";
}
else if(context == SipMessageSent )
{
qDebug() << "Sent SipMessage... what now?!";
}
/*else if(context == RequestedVCard )
{
qDebug() << "Requested VCard... what now?!";
}*/
else
{
TomahawkSipMessage *sipMessage = iq.findExtension<TomahawkSipMessage>().data();
if(sipMessage)
{
iq.accept();
qDebug() << Q_FUNC_INFO << "Got SipMessage ...";
qDebug() << "ip" << sipMessage->ip();
qDebug() << "port" << sipMessage->port();
qDebug() << "uniqname" << sipMessage->uniqname();
qDebug() << "key" << sipMessage->key();
qDebug() << "visible" << sipMessage->visible();
QVariantMap m;
if( sipMessage->visible() )
{
m["visible"] = true;
m["ip"] = sipMessage->ip();
m["port"] = sipMessage->port();
m["key"] = sipMessage->key();
m["uniqname"] = sipMessage->uniqname();
}
else
{
m["visible"] = false;
}
QJson::Serializer ser;
QByteArray ba = ser.serialize( m );
QString msg = QString::fromAscii( ba );
QString from = iq.from().full();
qDebug() << Q_FUNC_INFO << "From:" << from << ":" << msg;
emit msgReceived( from, msg );
}
}
}
bool JabberPlugin::presenceMeansOnline(Jreen::Presence::Type p)
{
switch(p)
{
case Jreen::Presence::Invalid:
case Jreen::Presence::Unavailable:
case Jreen::Presence::Error:
return false;
break;
default:
return true;
}
}
void JabberPlugin::handlePeerStatus(const Jreen::JID& jid, Jreen::Presence::Type presenceType)
{
QString fulljid = jid.full();
// "going offline" event
if ( !presenceMeansOnline( presenceType ) &&
( !m_peers.contains( jid ) ||
presenceMeansOnline( m_peers.value( jid ) )
)
)
{
m_peers[ jid ] = presenceType;
qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid;
// remove peer from legacy peers
if( m_legacy_peers.contains( jid ) )
{
m_legacy_peers.removeAll( jid );
}
emit peerOffline( fulljid );
return;
}
// "coming online" event
if( presenceMeansOnline( presenceType ) &&
( !m_peers.contains( jid ) ||
!presenceMeansOnline( m_peers.value( jid ) )
)
)
{
m_peers[ jid ] = presenceType;
qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid;
emit peerOnline( fulljid );
if(!m_avatarManager->avatar(jid.bare()).isNull())
onNewAvatar( jid.bare() );
return;
}
//qDebug() << "Updating presence data for" << fulljid;
m_peers[ jid ] = presenceType;
}
void JabberPlugin::onNewAvatar(const QString& jid)
{
qDebug() << Q_FUNC_INFO << jid;
Q_ASSERT(!m_avatarManager->avatar( jid ).isNull());
// find peers for the jid
QList<Jreen::JID> peers = m_peers.keys();
foreach(const Jreen::JID &peer, peers)
{
if( peer.bare() == jid )
{
emit avatarReceived ( peer.full(), m_avatarManager->avatar( jid ) );
}
}
if( jid == m_client->jid().bare() )
// own avatar
emit avatarReceived ( m_avatarManager->avatar( jid ) );
else
// someone else's avatar
emit avatarReceived ( jid, m_avatarManager->avatar( jid ) );
}
QString
JabberPlugin::readPassword()
{

View File

@@ -21,11 +21,29 @@
#define JABBER_H
#include "sip/SipPlugin.h"
#include "jabber_p.h"
#include "../sipdllmacro.h"
#include "avatarmanager.h"
#include <jreen/client.h>
#include <jreen/disco.h>
#include <jreen/message.h>
#include <jreen/messagesession.h>
#include <jreen/stanza.h>
#include <jreen/jreen.h>
#include <jreen/error.h>
#include <jreen/presence.h>
#include <jreen/vcard.h>
#include <jreen/abstractroster.h>
#include <jreen/connection.h>
#include <jreen/mucroom.h>
#include <QNetworkProxy>
#define MYNAME "SIPJREEN"
#define TOMAHAWK_FEATURE QLatin1String( "tomahawk:sip:v1" )
#define TOMAHAWK_CAP_NODE_NAME QLatin1String( "http://tomahawk-player.org/" )
#include "../sipdllmacro.h"
class Ui_JabberConfig;
@@ -64,6 +82,8 @@ public:
virtual void saveConfig();
void setProxy( QNetworkProxy* proxy );
signals:
void jidChanged( const QString& );
public slots:
virtual bool connectPlugin( bool startup );
@@ -78,17 +98,31 @@ protected:
private slots:
void showAddFriendDialog();
void onConnected();
void onDisconnected();
void onConnect();
void onDisconnect(Jreen::Client::DisconnectReason reason);
void onAuthError(int code, const QString &msg);
void onNewPresence( const Jreen::Presence& presence );
void onNewMessage( const Jreen::Message& message );
void onError( const Jreen::Connection::SocketError& e )
{
qDebug() << e;
}
void onNewIq( const Jreen::IQ &iq, int context = NoContext );
void onNewAvatar( const QString &jid );
private:
QString readPassword();
QString readServer();
bool readAutoConnect();
int readPort();
Jabber_p* p;
void addMenuHelper();
void removeMenuHelper();
bool presenceMeansOnline( Jreen::Presence::Type p );
void handlePeerStatus( const Jreen::JID &jid, Jreen::Presence::Type presenceType );
QMenu* m_menu;
QAction* m_addFriendAction;
@@ -99,6 +133,18 @@ private:
ConnectionState m_state;
QWeakPointer< QWidget > m_configWidget;
QString m_currentResource;
// sort out
Jreen::Client *m_client;
Jreen::MUCRoom *m_room;
Jreen::SimpleRoster *m_roster;
QHash<Jreen::JID, Jreen::Presence::Type> m_peers;
enum IqContext { NoContext, RequestDisco, RequestedDisco, SipMessageSent, RequestedVCard };
QStringList m_legacy_peers;
AvatarManager *m_avatarManager;
};
#endif

View File

@@ -1,576 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Dominik Schmidt <dev@dominik-schmidt.de>
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "jabber_p.h"
#include "tomahawksipmessage.h"
#include "tomahawksipmessagefactory.h"
#include "config.h"
#include "utils/tomahawkutils.h"
#include <jreen/capabilities.h>
#include <jreen/tcpconnection.h>
#include <jreen/vcardupdate.h>
#include <jreen/vcard.h>
#include <qjson/parser.h>
#include <qjson/serializer.h>
#include <QDebug>
#include <QTime>
#include <QTimer>
#include <QString>
#include <QRegExp>
#include <QThread>
#include <QVariant>
#include <QMap>
#include <QCryptographicHash>
#include <QDir>
#include <QFile>
#include <QPixmap>
//remove
#include <QLabel>
#include <QtGui/QLabel>
#define TOMAHAWK_FEATURE QLatin1String( "tomahawk:sip:v1" )
#define TOMAHAWK_CAP_NODE_NAME QLatin1String( "http://tomahawk-player.org/" )
Jabber_p::Jabber_p( const QString& jid, const QString& password, const QString& server, const int port )
: QObject()
, m_server()
{
qDebug() << Q_FUNC_INFO;
qsrand(QDateTime::currentDateTime().toTime_t());
// setup JID object
m_jid = Jreen::JID( jid );
// general client setup
m_client = new Jreen::Client( jid, password );
if ( !server.isEmpty() )
{
m_client->setServer( server );
m_client->setPort( port );
}
m_client->registerStanzaExtension(new TomahawkSipMessageFactory);
m_client->setResource( QString( "tomahawk%1" ).arg( QString::number( qrand() % 10000 ) ) );
// add VCardUpdate extension to own presence
m_client->presence().addExtension( new Jreen::VCardUpdate() );
// initialize the AvatarManager
m_avatarManager = new AvatarManager(m_client);
// setup disco
m_client->disco()->setSoftwareVersion( "Tomahawk Player", TOMAHAWK_VERSION, CMAKE_SYSTEM );
m_client->disco()->addIdentity( Jreen::Disco::Identity( "client", "type", "tomahawk", "en" ) );
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>();
caps->setNode( TOMAHAWK_CAP_NODE_NAME );
// print connection parameters
qDebug() << "Our JID set to:" << m_client->jid().full();
qDebug() << "Our Server set to:" << m_client->server();
qDebug() << "Our Port set to" << m_client->port();
m_client->setConnectionImpl( new Jreen::TcpConnection( m_client->server(), m_client->port() ) );
// setup slots
connect(qobject_cast<Jreen::Connection*>(m_client->connection()), SIGNAL(error(const Jreen::Connection::SocketError&)), SLOT(onError(const Jreen::Connection::SocketError&)));
connect(m_client, SIGNAL(serverFeaturesReceived(QSet<QString>)), SLOT(onConnect()));
connect(m_client, SIGNAL(disconnected(Jreen::Client::DisconnectReason)), SLOT(onDisconnect(Jreen::Client::DisconnectReason)));
connect(m_client, SIGNAL(destroyed(QObject*)), this, SLOT(onDestroy(QObject*)));
connect(m_client, SIGNAL(newMessage(Jreen::Message)), SLOT(onNewMessage(Jreen::Message)));
connect(m_client, SIGNAL(newPresence(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence)));
connect(m_client, SIGNAL(newIQ(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
connect(m_avatarManager, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString)));
// connect
qDebug() << "Connecting to the XMPP server...";
m_client->connectToServer();
}
Jabber_p::~Jabber_p()
{
delete m_client;
}
void
Jabber_p::setProxy( QNetworkProxy* proxy )
{
qDebug() << Q_FUNC_INFO << "NOT IMPLEMENTED";
}
void
Jabber_p::disconnect()
{
if ( m_client )
{
m_client->disconnect();
}
}
void
Jabber_p::sendMsg( const QString& to, const QString& msg )
{
qDebug() << Q_FUNC_INFO << to << msg;
if ( !m_client ) {
return;
}
if( m_legacy_peers.contains( to ) )
{
qDebug() << Q_FUNC_INFO << to << "Send legacy message" << msg;
Jreen::Message m( Jreen::Message::Chat, Jreen::JID(to), msg);
m_client->send( m );
return;
}
/*******************************************************
* Obsolete this by a SipMessage class
*/
QJson::Parser parser;
bool ok;
QVariant v = parser.parse( msg.toAscii(), &ok );
if ( !ok || v.type() != QVariant::Map )
{
qDebug() << "Invalid JSON in XMPP msg";
return;
}
QVariantMap m = v.toMap();
/*******************************************************/
TomahawkSipMessage *sipMessage;
if(m["visible"].toBool())
{
sipMessage = new TomahawkSipMessage(m["ip"].toString(),
m["port"].toInt(),
m["uniqname"].toString(),
m["key"].toString(),
m["visible"].toBool()
);
}
else
{
sipMessage = new TomahawkSipMessage();
}
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 );
}
void
Jabber_p::broadcastMsg( const QString &msg )
{
qDebug() << Q_FUNC_INFO;
if ( !m_client )
return;
foreach( const QString& jidstr, m_peers.keys() )
{
sendMsg( jidstr, msg );
}
}
void
Jabber_p::addContact( const QString& jid, const QString& msg )
{
// Add contact to the Tomahawk group on the roster
m_roster->add( jid, jid, QStringList() << "Tomahawk" );
return;
}
void
Jabber_p::onConnect()
{
qDebug() << Q_FUNC_INFO;
// update jid resource, servers like gtalk use resource binding and may
// have changed our requested /resource
if ( m_client->jid().resource() != m_jid.resource() )
{
// TODO: check if this is still neccessary with jreen
m_jid.setResource( m_client->jid().resource() );
QString jidstr( m_jid.full() );
emit jidChanged( jidstr );
}
emit connected();
qDebug() << "Connected as:" << m_jid.full();
// set presence to least valid value
m_client->setPresence(Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127);
// set ping timeout to 15 secs (TODO: verify if this works)
m_client->setPingInterval(15000);
// load roster
m_roster = new Jreen::SimpleRoster( m_client );
m_roster->load();
//FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P
// join MUC with bare jid as nickname
//TODO: make the room a list of rooms and make that configurable
QString mucNickname = QString( "tomahawk@conference.qutim.org/" ).append( QString( m_jid.bare() ).replace( "@", "-" ) );
m_room = new Jreen::MUCRoom(m_client, Jreen::JID( mucNickname ) );
//m_room->setHistorySeconds(0);
//m_room->join();
// treat muc participiants like contacts
connect( m_room, SIGNAL( messageReceived( Jreen::Message, bool ) ), this, SLOT( onNewMessage( Jreen::Message ) ) );
connect( m_room, SIGNAL( presenceReceived( Jreen::Presence, const Jreen::MUCRoom::Participant* ) ), this, SLOT( onNewPresence( Jreen::Presence ) ) );
}
void
Jabber_p::onDisconnect( Jreen::Client::DisconnectReason reason )
{
QString error;
bool reconnect = false;
int reconnectInSeconds = 0;
switch( reason )
{
case Jreen::Client::User:
error = "User Interaction";
break;
case Jreen::Client::HostUnknown:
error = "Host is unknown";
break;
case Jreen::Client::ItemNotFound:
error = "Item not found";
break;
case Jreen::Client::AuthorizationError:
error = "Authorization Error";
break;
case Jreen::Client::RemoteStreamError:
error = "Remote Stream Error";
reconnect = true;
break;
case Jreen::Client::RemoteConnectionFailed:
error = "Remote Connection failed";
break;
case Jreen::Client::InternalServerError:
error = "Internal Server Error";
reconnect = true;
break;
case Jreen::Client::SystemShutdown:
error = "System shutdown";
reconnect = true;
reconnectInSeconds = 60;
break;
case Jreen::Client::Conflict:
error = "Conflict";
break;
case Jreen::Client::Unknown:
error = "Unknown";
break;
default:
qDebug() << "Not all Client::DisconnectReasons checked";
Q_ASSERT(false);
break;
}
qDebug() << "Disconnected from server:" << error;
if( reason != Jreen::Client::User )
{
emit authError( reason, error );
}
if(reconnect)
QTimer::singleShot(reconnectInSeconds*1000, m_client, SLOT(connectToServer()));
emit disconnected();
}
void
Jabber_p::onNewMessage( const Jreen::Message& m )
{
QString from = m.from().full();
QString msg = m.body();
if ( msg.isEmpty() )
return;
QJson::Parser parser;
bool ok;
QVariant v = parser.parse( msg.toAscii(), &ok );
if ( !ok || v.type() != QVariant::Map )
{
if ( m.from().domain().contains( "googlemail." )
|| m.from().domain().contains( "gmail." )
|| m.from().domain().contains( "gtalk." )
)
return;
QString to = from;
QString response = QString( tr("I'm sorry -- I'm just an automatic presence used by Tomahawk Player"
" (http://gettomahawk.com). If you are getting this message, the person you"
" are trying to reach is probably not signed on, so please try again later!") );
// this is not a sip message, so we send it directly through the client
m_client->send( Jreen::Message ( Jreen::Message::Chat, Jreen::JID(to), response) );
return;
}
qDebug() << Q_FUNC_INFO << "From:" << m.from().full() << ":" << m.body();
emit msgReceived( from, msg );
}
void Jabber_p::onNewPresence( const Jreen::Presence& presence)
{
Jreen::JID jid = presence.from();
QString fulljid( jid.full() );
qDebug() << Q_FUNC_INFO << "* New presence: " << fulljid << presence.subtype();
if( jid == m_jid )
return;
if ( presence.error() ) {
//qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: no" << "presence error";
return;
}
// ignore anyone not Running tomahawk:
Jreen::Capabilities::Ptr caps = presence.findExtension<Jreen::Capabilities>();
if ( caps && ( caps->node() == TOMAHAWK_CAP_NODE_NAME ) )
{
// must be a jreen resource, implementation in gloox was broken
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: yes" << "caps " << caps->node();
handlePeerStatus( fulljid, presence.subtype() );
}
else if( caps )
{
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: maybe" << "caps " << caps->node()
<< "requesting disco..";
// request disco features
QString node = caps->node() + '#' + caps->ver();
Jreen::IQ iq( Jreen::IQ::Get, jid );
iq.addExtension( new Jreen::Disco::Info( node ) );
m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), RequestDisco );
}
else if( !caps )
{
qDebug() << Q_FUNC_INFO << "Running tomahawk: no" << "no caps";
}
}
void
Jabber_p::onNewIq( const Jreen::IQ &iq, int context )
{
if( context == RequestDisco )
{
qDebug() << Q_FUNC_INFO << "Received disco IQ...";
Jreen::Disco::Info *discoInfo = iq.findExtension<Jreen::Disco::Info>().data();
if(!discoInfo)
return;
iq.accept();
QString fulljid = iq.from().full();
Jreen::DataForm::Ptr form = discoInfo->form();
if(discoInfo->features().contains( TOMAHAWK_FEATURE ))
{
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk/feature enabled: yes";
// the actual presence doesn't matter, it just needs to be "online"
handlePeerStatus( fulljid, Jreen::Presence::Available );
}
else
{
qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk/feature enabled: no";
//LEGACY: accept resources starting with tomahawk too
if( iq.from().resource().startsWith("tomahawk") )
{
qDebug() << Q_FUNC_INFO << fulljid << "Detected legacy tomahawk..";
// add to legacy peers, so we can send text messages instead of iqs
m_legacy_peers.append( fulljid );
handlePeerStatus( fulljid, Jreen::Presence::Available );
}
}
}
else if(context == RequestedDisco)
{
qDebug() << "Sent IQ(Set), what should be happening here?";
}
else if(context == SipMessageSent )
{
qDebug() << "Sent SipMessage... what now?!";
}
/*else if(context == RequestedVCard )
{
qDebug() << "Requested VCard... what now?!";
}*/
else
{
TomahawkSipMessage *sipMessage = iq.findExtension<TomahawkSipMessage>().data();
if(sipMessage)
{
iq.accept();
qDebug() << Q_FUNC_INFO << "Got SipMessage ...";
qDebug() << "ip" << sipMessage->ip();
qDebug() << "port" << sipMessage->port();
qDebug() << "uniqname" << sipMessage->uniqname();
qDebug() << "key" << sipMessage->key();
qDebug() << "visible" << sipMessage->visible();
QVariantMap m;
if( sipMessage->visible() )
{
m["visible"] = true;
m["ip"] = sipMessage->ip();
m["port"] = sipMessage->port();
m["key"] = sipMessage->key();
m["uniqname"] = sipMessage->uniqname();
}
else
{
m["visible"] = false;
}
QJson::Serializer ser;
QByteArray ba = ser.serialize( m );
QString msg = QString::fromAscii( ba );
QString from = iq.from().full();
qDebug() << Q_FUNC_INFO << "From:" << from << ":" << msg;
emit msgReceived( from, msg );
}
}
}
bool
Jabber_p::presenceMeansOnline( Jreen::Presence::Type p )
{
switch(p)
{
case Jreen::Presence::Invalid:
case Jreen::Presence::Unavailable:
case Jreen::Presence::Error:
return false;
break;
default:
return true;
}
}
void
Jabber_p::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type presenceType )
{
QString fulljid = jid.full();
// "going offline" event
if ( !presenceMeansOnline( presenceType ) &&
( !m_peers.contains( fulljid ) ||
presenceMeansOnline( m_peers.value( fulljid ) )
)
)
{
m_peers[ fulljid ] = presenceType;
qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid;
// remove peer from legacy peers
if( m_legacy_peers.contains( fulljid ) )
{
m_legacy_peers.removeAll( fulljid );
}
emit peerOffline( fulljid );
return;
}
// "coming online" event
if( presenceMeansOnline( presenceType ) &&
( !m_peers.contains( fulljid ) ||
!presenceMeansOnline( m_peers.value( fulljid ) )
)
)
{
m_peers[ fulljid ] = presenceType;
qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid;
emit peerOnline( fulljid );
if(!m_avatarManager->avatar(jid.bare()).isNull())
onNewAvatar( jid.bare() );
return;
}
//qDebug() << "Updating presence data for" << fulljid;
m_peers[ fulljid ] = presenceType;
}
void Jabber_p::onNewAvatar(const QString& jid)
{
qDebug() << Q_FUNC_INFO << jid;
Q_ASSERT(!m_avatarManager->avatar( jid ).isNull());
// find peers for the jid
QStringList peers = m_peers.keys();
foreach(const QString &peer, peers)
{
if( peer.startsWith(jid) )
{
emit avatarReceived ( peer, m_avatarManager->avatar( jid ) );
}
}
if( jid == m_client->jid().bare() )
// own avatar
emit avatarReceived ( m_avatarManager->avatar( jid ) );
else
// someone else's avatar
emit avatarReceived ( jid, m_avatarManager->avatar( jid ) );
}

View File

@@ -1,114 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Dominik Schmidt <dev@dominik-schmidt.de>
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef JABBER_P_H
#define JABBER_P_H
#include "../sipdllmacro.h"
#include "avatarmanager.h"
#include <jreen/client.h>
#include <jreen/disco.h>
#include <jreen/message.h>
#include <jreen/messagesession.h>
#include <jreen/stanza.h>
#include <jreen/jreen.h>
#include <jreen/error.h>
#include <jreen/presence.h>
#include <jreen/vcard.h>
#include <jreen/abstractroster.h>
#include <jreen/connection.h>
#include <jreen/mucroom.h>
#include <QObject>
#include <QSharedPointer>
#include <QMap>
#include <QNetworkProxy>
#if defined( WIN32 ) || defined( _WIN32 )
#include <windows.h>
#endif
class SIPDLLEXPORT Jabber_p :
public QObject
{
Q_OBJECT
public:
explicit Jabber_p( const QString& jid, const QString& password, const QString& server = "", const int port = -1 );
virtual ~Jabber_p();
void setProxy( QNetworkProxy* proxy );
signals:
void msgReceived( const QString&, const QString& ); //from, msg
void peerOnline( const QString& );
void peerOffline( const QString& );
void connected();
void disconnected();
void jidChanged( const QString& );
void avatarReceived( const QPixmap& avatar );
void avatarReceived( const QString&, const QPixmap& avatar );
void authError( int, const QString& );
public slots:
void sendMsg( const QString& to, const QString& msg );
void broadcastMsg( const QString& msg );
void addContact( const QString& jid, const QString& msg = QString() );
void disconnect();
void onDisconnect(Jreen::Client::DisconnectReason reason);
void onConnect();
private slots:
virtual void onNewPresence( const Jreen::Presence& presence );
virtual void onNewMessage( const Jreen::Message& msg );
virtual void onError( const Jreen::Connection::SocketError& e )
{
qDebug() << e;
}
virtual void onDestroy( QObject */*object*/ )
{
qDebug() << Q_FUNC_INFO;
}
virtual void onNewIq( const Jreen::IQ &iq, int context = NoContext );
virtual void onNewAvatar( const QString &jid );
private:
bool presenceMeansOnline( Jreen::Presence::Type p );
void handlePeerStatus( const Jreen::JID &jid, Jreen::Presence::Type presenceType );
Jreen::Client *m_client;
Jreen::MUCRoom *m_room;
Jreen::SimpleRoster *m_roster;
Jreen::JID m_jid;
QMap<Jreen::Presence::Type, QString> m_presences;
QMap<QString, Jreen::Presence::Type> m_peers;
QString m_server;
enum IqContext { NoContext, RequestDisco, RequestedDisco, SipMessageSent, RequestedVCard };
QStringList m_legacy_peers;
AvatarManager *m_avatarManager;
};
#endif // JABBER_H

View File

@@ -48,6 +48,9 @@
#include "shortcuthandler.h"
#include "scanmanager.h"
#include "tomahawksettings.h"
#include "globalactionmanager.h"
#include "webcollection.h"
#include "database/localcollection.h"
#include "audio/audioengine.h"
#include "utils/xspfloader.h"
@@ -223,7 +226,7 @@ TomahawkApp::init()
#else
qDebug() << "Setting NAM.";
TomahawkUtils::setNam( new QNetworkAccessManager );
TomahawkUtils::setNam( new QNetworkAccessManager() );
#endif
// Set up proxy
@@ -241,7 +244,6 @@ TomahawkApp::init()
else
TomahawkUtils::setProxy( new QNetworkProxy( QNetworkProxy::NoProxy ) );
Echonest::Config::instance()->setAPIKey( "JRIHWEP6GPOER2QQ6" );
Echonest::Config::instance()->setNetworkAccessManager( TomahawkUtils::nam() );
@@ -249,7 +251,6 @@ TomahawkApp::init()
qDebug() << "Init SIP system.";
#ifndef TOMAHAWK_HEADLESS
if ( !m_headless )
{
@@ -462,12 +463,19 @@ void
TomahawkApp::initLocalCollection()
{
source_ptr src( new Source( 0, "My Collection" ) );
collection_ptr coll( new DatabaseCollection( src ) );
collection_ptr coll( new LocalCollection( src ) );
src->addCollection( coll );
SourceList::instance()->setLocal( src );
// src->collection()->tracks();
// dummy source/collection for web-based result-hints.
source_ptr dummy( new Source( -1, "" ) );
dummy->setOnline();
collection_ptr dummycol( new WebCollection( dummy ) );
dummy->addCollection( dummycol );
SourceList::instance()->setWebSource( dummy );
// to make the stats signal be emitted by our local source
// this will update the sidebar, etc.
DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( src );
@@ -503,7 +511,9 @@ TomahawkApp::setupSIP()
qDebug() << "Connecting SIP classes";
SipHandler::instance()->loadFromConfig( true );
// SipHandler::instance()->setProxy( *TomahawkUtils::proxy() );
// m_sipHandler->setProxy( *TomahawkUtils::proxy() );
}
}
@@ -520,29 +530,23 @@ TomahawkApp::activate()
bool
TomahawkApp::loadUrl( const QString& url )
{
if( url.contains( "tomahawk://" ) ) {
QString cmd = url.mid( 11 );
qDebug() << "tomahawk!s" << cmd;
if( cmd.startsWith( "load/?" ) ) {
cmd = cmd.mid( 6 );
qDebug() << "loading.." << cmd;
if( cmd.startsWith( "xspf=" ) ) {
XSPFLoader* l = new XSPFLoader( true, this );
qDebug() << "Loading spiff:" << cmd.mid( 5 );
l->load( QUrl( cmd.mid( 5 ) ) );
}
}
} else {
if( url.startsWith( "tomahawk://" ) )
return GlobalActionManager::instance()->parseTomahawkLink( url );
else
{
QFile f( url );
QFileInfo info( f );
if( f.exists() && info.suffix() == "xspf" ) {
XSPFLoader* l = new XSPFLoader( true, this );
qDebug() << "Loading spiff:" << url;
l->load( QUrl::fromUserInput( url ) );
}
}
return true;
}
}
return false;
}
void
@@ -555,6 +559,7 @@ TomahawkApp::instanceStarted( KDSingleApplicationGuard::Instance instance )
return;
}
loadUrl( instance.arguments.at( 1 ) );
QString arg1 = instance.arguments[ 1 ];
loadUrl( arg1 );
}

View File

@@ -21,6 +21,8 @@
#include <QAction>
#include <QCloseEvent>
#include <QShowEvent>
#include <QHideEvent>
#include <QInputDialog>
#include <QPixmap>
#include <QPropertyAnimation>
@@ -161,7 +163,7 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
qtsparkle::Updater* updater = new qtsparkle::Updater( updaterUrl, this );
updater->SetNetworkAccessManager( TomahawkUtils::nam() );
updater->SetVersion( VERSION );
updater->SetVersion( TOMAHAWK_VERSION );
ui->menu_Help->addSeparator();
QAction* checkForUpdates = ui->menu_Help->addAction( tr( "Check For Updates...") );
@@ -267,6 +269,13 @@ TomahawkWindow::setupSignals()
connect( ui->actionCreate_New_Station, SIGNAL( triggered() ), SLOT( createStation() ));
connect( ui->actionAboutTomahawk, SIGNAL( triggered() ), SLOT( showAboutTomahawk() ) );
connect( ui->actionExit, SIGNAL( triggered() ), APP, SLOT( quit() ) );
#if defined( Q_OS_DARWIN )
connect( ui->actionMinimize, SIGNAL( triggered() ), SLOT( minimize() ) );
connect( ui->actionZoom, SIGNAL( triggered() ), SLOT( maximize() ) );
#else
ui->menuWindow->clear();
ui->menuWindow->menuAction()->setVisible( false );
#endif
// <SipHandler>
connect( APP->sipHandler(), SIGNAL( connected() ), SLOT( onSipConnected() ) );
@@ -294,7 +303,6 @@ TomahawkWindow::changeEvent( QEvent* e )
}
}
void
TomahawkWindow::closeEvent( QCloseEvent* e )
{
@@ -310,6 +318,27 @@ TomahawkWindow::closeEvent( QCloseEvent* e )
e->accept();
}
void
TomahawkWindow::showEvent( QShowEvent* e )
{
QMainWindow::showEvent( e );
#if defined( Q_OS_DARWIN )
ui->actionMinimize->setDisabled( false );
ui->actionZoom->setDisabled( false );
#endif
}
void
TomahawkWindow::hideEvent( QHideEvent* e )
{
QMainWindow::hideEvent( e );
#if defined( Q_OS_DARWIN )
ui->actionMinimize->setDisabled( true );
ui->actionZoom->setDisabled( true );
#endif
}
void
TomahawkWindow::showSettingsDialog()
@@ -530,3 +559,25 @@ TomahawkWindow::checkForUpdates()
Tomahawk::checkForUpdates();
#endif
}
void
TomahawkWindow::minimize()
{
if ( isMinimized() )
{
showNormal();
} else {
showMinimized();
}
}
void
TomahawkWindow::maximize()
{
if ( isMaximized() )
{
showNormal();
} else {
showMaximized();
}
}

View File

@@ -57,6 +57,8 @@ public:
protected:
void changeEvent( QEvent* e );
void closeEvent( QCloseEvent* e );
void showEvent( QShowEvent* e );
void hideEvent( QHideEvent* e );
public slots:
void createAutomaticPlaylist();
@@ -84,6 +86,10 @@ private slots:
void onSipPluginAdded( SipPlugin* p );
void onSipPluginRemoved( SipPlugin* p );
void minimize();
void maximize();
private:
void loadSettings();
void saveSettings();

View File

@@ -72,6 +72,13 @@
<addaction name="actionToggleConnect"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menuWindow">
<property name="title">
<string>&amp;Window</string>
</property>
<addaction name="actionMinimize"/>
<addaction name="actionZoom"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
<string>&amp;Help</string>
@@ -82,6 +89,7 @@
<addaction name="menuPlaylist"/>
<addaction name="menuNetwork"/>
<addaction name="menuSettings"/>
<addaction name="menuWindow"/>
<addaction name="menu_Help"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
@@ -157,6 +165,22 @@
<string>Hide Offline Sources</string>
</property>
</action>
<action name="actionMinimize">
<property name="text">
<string>Minimize</string>
</property>
<property name="shortcut">
<string>Ctrl+M</string>
</property>
</action>
<action name="actionZoom">
<property name="text">
<string>Zoom</string>
</property>
<property name="shortcut">
<string>Meta+Ctrl+Z</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>

View File

@@ -78,7 +78,7 @@ if(UNIX)
endif(APPLE)
endif(UNIX)
if(WIN32)
set(SOURCES ${SOURCES} ws/win/WNetworkConnectionMonitor_win.cpp)
set(SOURCES ${SOURCES} ws/win/WNetworkConnectionMonitor_win.cpp ws/win/Pac.cpp ws/win/NdisEvents.cpp )
set(MOC_HEADERS ${MOC_HEADERS} ws/win/WNetworkConnectionMonitor.h)
endif(WIN32)
@@ -100,6 +100,7 @@ ENDIF()
target_link_libraries(tomahawk_lastfm2
${QT_LIBRARIES}
${QT_QTDBUS_LIBRARY}
)
set_target_properties(tomahawk_lastfm2 PROPERTIES COMPILE_FLAGS "-DLASTFM_OHAI_QMAKE" )

View File

@@ -50,7 +50,7 @@ static struct NetworkAccessManagerInit
// at two seconds, so that hangs startup
if (!s.fAutoDetect && s.lpszProxy)
{
QUrl url( QString::fromUtf16(s.lpszProxy) );
QUrl url( QString::fromUtf16((const unsigned short*)s.lpszProxy) );
QNetworkProxy proxy( QNetworkProxy::HttpProxy );
proxy.setHostName( url.host() );
proxy.setPort( url.port() );

View File

@@ -23,9 +23,10 @@
#endif
#include <objbase.h>
#include <atlbase.h>
#include <atlcom.h>
//#include <boost/range/atl.hpp>
//#include <atlbase.h>
//#include <atlcom.h>
#include <winable.h>
/** @brief WsConnectionMonitor needs Com to work as early as possible so we do this
* @author <doug@last.fm>
@@ -37,7 +38,7 @@ public:
{
HRESULT hr = CoInitialize(0);
m_bComInitialised = SUCCEEDED(hr);
_ASSERT(m_bComInitialised);
//_ASSERT(m_bComInitialised);
if (m_bComInitialised) {
setupSecurity();
}
@@ -45,10 +46,10 @@ public:
void setupSecurity()
{
CSecurityDescriptor sd;
sd.InitializeFromThreadToken();
HRESULT hr = CoInitializeSecurity(sd, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
_ASSERT(SUCCEEDED(hr));
//CSecurityDescriptor sd;
//sd.InitializeFromThreadToken();
//HRESULT hr = CoInitializeSecurity(sd, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
//_ASSERT(SUCCEEDED(hr));
}
~ComSetup()

View File

@@ -26,6 +26,7 @@
*/
struct IeSettings : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
{
#ifndef WIN32
IeSettings()
{
if (!WinHttpGetIEProxyConfigForCurrentUser(this)) {
@@ -33,6 +34,7 @@ struct IeSettings : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
lpszAutoConfigUrl = lpszProxy = lpszProxyBypass = 0;
}
}
#endif
~IeSettings()
{

View File

@@ -32,22 +32,24 @@ NdisEvents::NdisEvents()
NdisEvents::~NdisEvents()
{
#ifndef WIN32
if (m_pSink)
m_pSink->disconnect();
if (m_pServices && m_pSink)
m_pServices->CancelAsyncCall(m_pSink);
#endif
//if (m_pServices && m_pSink)
//m_pServices->CancelAsyncCall(m_pSink);
// and reference counting will take care of the WmiSink object
}
HRESULT
NdisEvents::registerForNdisEvents()
{
HRESULT hr = m_pLocator.CoCreateInstance(CLSID_WbemLocator);
HRESULT hr = 0; //m_pLocator.CoCreateInstance(CLSID_WbemLocator);
if (FAILED(hr))
return hr;
// Connect to the root\wmi namespace with the current user.
hr = m_pLocator->ConnectServer(CComBSTR("ROOT\\WMI"), // strNetworkResource
hr = 0; /*m_pLocator->ConnectServer(CComBSTR("ROOT\\WMI"), // strNetworkResource
NULL, // strUser
NULL, // strPassword
NULL, // strLocale
@@ -55,12 +57,12 @@ NdisEvents::registerForNdisEvents()
CComBSTR(""), // strAuthority
NULL, // pCtx
&m_pServices
);
);*/
if (FAILED(hr))
return hr;
#ifndef WIN32
m_pSink = new WmiSink(this);
#endif
//////////////////////////
// other notifications we're not interested in right now include...
@@ -75,12 +77,12 @@ NdisEvents::registerForNdisEvents()
// MSNdis_StatusProtocolUnbind
// MSNdis_StatusMediaSpecificIndication
CComBSTR wql("WQL");
/*CComBSTR wql("WQL");
CComBSTR query("SELECT * FROM MSNdis_StatusMediaDisconnect");
hr = m_pServices->ExecNotificationQueryAsync(wql, query, 0, 0, m_pSink);
query = "SELECT * FROM MSNdis_StatusMediaConnect";
hr = m_pServices->ExecNotificationQueryAsync(wql, query, 0, 0, m_pSink);
hr = m_pServices->ExecNotificationQueryAsync(wql, query, 0, 0, m_pSink);*/
return S_OK;
}

View File

@@ -21,8 +21,8 @@
#define NDIS_EVENTS_H
#include <windows.h>
#include <atlbase.h>
#include <WbemCli.h>
//#include <atlbase.h>
//#include <WbemCli.h>
class NdisEvents
{
@@ -35,8 +35,8 @@ public:
virtual void onConnectionDown(BSTR name) = 0;
private:
CComPtr<IWbemLocator> m_pLocator;
CComPtr<IWbemServices> m_pServices;
//CComPtr<IWbemLocator> m_pLocator;
//CComPtr<IWbemServices> m_pServices;
class WmiSink *m_pSink;
};

View File

@@ -21,8 +21,9 @@
#include <QNetworkRequest>
#include <QStringList>
#include <QUrl>
#include <atlbase.h>
#include <atlconv.h>
//#include <atlbase.h>
//#include <atlconv.h>
#include <winhttp.h>
static bool
@@ -73,8 +74,10 @@ lastfm::Pac::Pac()
lastfm::Pac::~Pac()
{
#ifndef WIN32
if (m_hSession)
WinHttpCloseHandle(m_hSession);
#endif
}
QNetworkProxy
@@ -86,7 +89,7 @@ lastfm::Pac::resolve(const QNetworkRequest &request, const wchar_t* pacUrl)
if (!m_hSession)
{
QByteArray user_agent = request.rawHeader("user-agent");
m_hSession = WinHttpOpen(CA2W(user_agent), WINHTTP_ACCESS_TYPE_NO_PROXY, 0, 0, WINHTTP_FLAG_ASYNC);
//m_hSession = WinHttpOpen(CA2W(user_agent), WINHTTP_ACCESS_TYPE_NO_PROXY, 0, 0, WINHTTP_FLAG_ASYNC);
}
if (m_hSession)
{
@@ -95,33 +98,36 @@ lastfm::Pac::resolve(const QNetworkRequest &request, const wchar_t* pacUrl)
memset(&opts, 0, sizeof(opts));
if (pacUrl)
{
opts.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
opts.lpszAutoConfigUrl = pacUrl;
//opts.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
//opts.lpszAutoConfigUrl = pacUrl;
}
else
{
opts.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
opts.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
//opts.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
//opts.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
}
opts.fAutoLogonIfChallenged = TRUE;
if (WinHttpGetProxyForUrl(m_hSession, request.url().toString().utf16(), &opts, &info)) {
#ifndef WIN32
if (WinHttpGetProxyForUrl(m_hSession, (const WCHAR*)(request.url().toString().utf16()), &opts, &info)) {
if (info.lpszProxy)
{
QList<QNetworkProxy> proxies = parsePacResult(QString::fromUtf16(info.lpszProxy));
QList<QNetworkProxy> proxies = parsePacResult(QString::fromUtf16((const ushort*)info.lpszProxy));
if (!proxies.empty())
{
out = proxies.at(0);
}
GlobalFree(info.lpszProxy);
// pay attention! casting away constness
GlobalFree((void*)info.lpszProxy);
}
if (info.lpszProxyBypass)
{
GlobalFree(info.lpszProxyBypass);
// pay attention! casting away constness
GlobalFree((void*)info.lpszProxyBypass);
}
} else {
m_bFailed = true;
}
#endif
}
return out;

View File

@@ -20,7 +20,7 @@
#ifndef WMISINK_WIN_H
#define WMISINK_WIN_H
#include "WbemCli.h"
#include "wbemcli.h"
// Sink object for WMI NDIS notifications
class WmiSink : public IWbemObjectSink

View File

@@ -25,9 +25,13 @@
#include <QDomElement>
#include <QLocale>
#include <QStringList>
#include <QThread>
#include <QMutex>
#include <QUrl>
static QNetworkAccessManager* nam = 0;
static QMap< QThread*, QNetworkAccessManager* > threadNamHash;
static QMap< QThread*, bool > ourNamHash;
static QMutex namAccessMutex;
QString
lastfm::ws::host()
@@ -192,17 +196,33 @@ lastfm::ws::parse( QNetworkReply* reply ) throw( ParseError )
QNetworkAccessManager*
lastfm::nam()
{
if (!::nam) ::nam = new NetworkAccessManager( qApp );
return ::nam;
QMutexLocker l( &namAccessMutex );
QThread* thread = QThread::currentThread();
if ( !threadNamHash.contains( thread ) )
{
NetworkAccessManager* newNam = new NetworkAccessManager();
threadNamHash[thread] = newNam;
ourNamHash[thread] = true;
return newNam;
}
return threadNamHash[thread];
}
void
lastfm::setNetworkAccessManager( QNetworkAccessManager* nam )
{
delete ::nam;
::nam = nam;
nam->setParent( qApp ); // ensure it isn't deleted out from under us
if ( !nam )
return;
QMutexLocker l( &namAccessMutex );
QThread* thread = QThread::currentThread();
if ( threadNamHash.contains( thread ) && ourNamHash.contains( thread ) && ourNamHash[thread] )
delete threadNamHash[thread];
threadNamHash[thread] = nam;
ourNamHash[thread] = false;
}