1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-03-25 10:19:41 +01:00

Merge branch 'master' into spotifyplaylists

Conflicts:
	src/accounts/lastfm/lastfmplugin.h
	src/libtomahawk/playlist.h
	src/libtomahawk/resolvers/scriptresolver.cpp
	src/main.cpp
	src/tomahawkapp.h
This commit is contained in:
Leo Franchi 2012-03-31 11:44:39 -04:00
commit 059d0374c6
79 changed files with 4766 additions and 154 deletions

View File

@ -26,8 +26,21 @@ add_definitions( "-fvisibility=hidden" )
# build options
option(BUILD_GUI "Build Tomahawk with GUI" ON)
option(BUILD_RELEASE "Generate TOMAHAWK_VERSION without GIT info" OFF)
option(WITH_BREAKPAD "Build with breakpad integration" ON)
option(WITH_CRASHREPORTER "Build with CrashReporter" ON)
option(LEGACY_KDE_INTEGRATION "Install tomahawk.protocol file, deprecated since 4.6.0" OFF)
IF( CMAKE_SYSTEM_PROCESSOR MATCHES "arm" )
message(STATUS "Build of breakpad library disabled on this platform.")
SET(WITH_BREAKPAD OFF)
SET(WITH_CRASHREPORTER OFF)
ENDIF()
# add definitions based on build options
IF(WITH_BREAKPAD)
message(STATUS "Build with support for breakpad.")
ENDIF()
# generate version string
# base string used in release and unstable builds
@ -200,9 +213,3 @@ ADD_SUBDIRECTORY( src/libtomahawk )
SET( TOMAHAWK_LIBRARIES tomahawklib )
ADD_SUBDIRECTORY( src )
ADD_SUBDIRECTORY( admin )
IF( BUILD_GUI )
IF( NOT DISABLE_CRASHREPORTER )
ADD_SUBDIRECTORY( src/breakpad/CrashReporter )
ENDIF()
ENDIF()

3505
lang/tomahawk_bg.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,8 @@
<file>tomahawk_de.qm</file>
<file>tomahawk_sv.qm</file>
<file>tomahawk_es.qm</file>
<file>tomahawk_bg.qm</file>
<file>tomahawk_pl.qm</file>
<file>tomahawk_pt_BR.qm</file>
</qresource>
</RCC>

View File

@ -42,6 +42,7 @@ public:
};
explicit AccountFactoryWrapper( Tomahawk::Accounts::AccountFactory* factory, QWidget* parent = 0 );
virtual ~AccountFactoryWrapper() {}
public slots:
void openAccountConfig( Tomahawk::Accounts::Account* );

View File

@ -68,8 +68,6 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
sourcetree/items/groupitem.cpp
sourcetree/items/historyitem.cpp
breakpad/BreakPad.cpp
utils/guihelpers.cpp
accounts/lastfm/LastFmAccount.cpp
@ -93,6 +91,10 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
AccountFactoryWrapperDelegate.cpp
)
IF( WITH_BREAKPAD )
LIST(APPEND tomahawkSourcesGui breakpad/BreakPad.cpp)
ENDIF()
SET( tomahawkUI ${tomahawkUI}
tomahawkwindow.ui
diagnosticsdialog.ui
@ -174,6 +176,10 @@ SET( final_src ${final_src} ${tomahawkMoc} ${tomahawkSources} ${trans_outfile})
IF( BUILD_GUI )
LIST(APPEND tomahawkSources ${tomahawkSourcesGui})
qt4_wrap_ui( tomahawkUI_H ${tomahawkUI} )
IF( WITH_CRASHREPORTER )
ADD_SUBDIRECTORY( breakpad/CrashReporter )
ENDIF()
ENDIF()
kde4_add_app_icon( tomahawkSources "${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon-*.png" )
@ -206,9 +212,11 @@ ENDIF(GLOOX_FOUND)
IF(QCA2_FOUND)
SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} )
ENDIF(QCA2_FOUND)
IF(WITH_BREAKPAD)
SET(LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_breakpad)
ENDIF()
TARGET_LINK_LIBRARIES( tomahawk
tomahawk_breakpad
${LINK_LIBRARIES}
${TOMAHAWK_LIBRARIES}
${PHONON_LIBS}

View File

@ -270,6 +270,7 @@ LastFmAccount::hookupResolver()
const Attica::Content res = AtticaManager::instance()->resolverForId( "lastfm" );
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
Q_ASSERT( state == AtticaManager::Installed );
Q_UNUSED( state );
const AtticaManager::Resolver data = AtticaManager::instance()->resolverData( res.id() );

View File

@ -585,6 +585,8 @@ LastFmPlugin::topTracksReturned()
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
QStringList topTracks = lastfm::Artist::getTopTracks( reply );
topTracks.removeDuplicates();
QVariantMap returnedData;
returnedData["tracks"] = topTracks;

View File

@ -14,6 +14,7 @@ set( xmppAccountSources
sip/tomahawkxmppmessagefactory.cpp
sip/avatarmanager.cpp
sip/xmlconsole.cpp
XmppInfoPlugin.cpp
)
set( xmppAccountHeaders
@ -22,6 +23,7 @@ set( xmppAccountHeaders
sip/xmppsip.h
sip/avatarmanager.h
sip/xmlconsole.h
XmppInfoPlugin.h
)
set( xmppAccountUI

View File

@ -0,0 +1,143 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012, Dominik Schmidt <domme@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 "XmppInfoPlugin.h"
#include "globalactionmanager.h"
#include "sip/xmppsip.h"
#include "utils/logger.h"
#include <jreen/tune.h>
#include <jreen/pubsubmanager.h>
#include <jreen/jid.h>
#include <jreen/client.h>
// remove now playing status after PAUSE_TIMEOUT seconds
static const int PAUSE_TIMEOUT = 60;
Tomahawk::InfoSystem::XmppInfoPlugin::XmppInfoPlugin(XmppSipPlugin* sipPlugin)
: m_sipPlugin( sipPlugin )
, m_pubSubManager( 0 )
, m_pauseTimer( this )
{
Q_ASSERT( sipPlugin->m_client );
m_supportedPushTypes << InfoNowPlaying << InfoNowPaused << InfoNowResumed << InfoNowStopped;
m_pubSubManager = new Jreen::PubSub::Manager( sipPlugin->m_client );
m_pubSubManager->addEntityType< Jreen::Tune >();
m_pauseTimer.setSingleShot( true );
connect( &m_pauseTimer, SIGNAL( timeout() ),
this, SLOT( audioStopped() ) );
}
Tomahawk::InfoSystem::XmppInfoPlugin::~XmppInfoPlugin()
{
delete m_pubSubManager;
}
void
Tomahawk::InfoSystem::XmppInfoPlugin::pushInfo(QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input)
{
tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full();
if( m_sipPlugin->m_account->configuration().value("publishtracks").toBool() == false )
{
tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full() << "Not publishing now playing info (disabled in account config)";
return;
}
switch ( type )
{
case InfoNowPlaying:
case InfoNowResumed:
m_pauseTimer.stop();
if ( input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
audioStarted( input.value< Tomahawk::InfoSystem::InfoStringHash >() );
break;
case InfoNowPaused:
m_pauseTimer.start( PAUSE_TIMEOUT * 1000 );
audioPaused();
break;
case InfoNowStopped:
m_pauseTimer.stop();
audioStopped();
break;
default:
return;
}
}
void
Tomahawk::InfoSystem::XmppInfoPlugin::audioStarted(const Tomahawk::InfoSystem::InfoStringHash& info)
{
tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full() << info;
Jreen::Tune::Ptr tune( new Jreen::Tune() );
tune->setTitle( info.value( "title" ) );
tune->setArtist( info.value( "artist" ) );
tune->setLength( info.value("duration").toInt() );
tune->setTrack( info.value("albumpos") );
tune->setUri( GlobalActionManager::instance()->openLink( info.value( "title" ), info.value( "artist" ), info.value( "album" ) ) );
//TODO: provide a rating once available in Tomahawk
tune->setRating( 10 );
//TODO: it would be nice to set Spotify, Dilandau etc here, but not the jabber ids of friends
tune->setSource( "Tomahawk" );
m_pubSubManager->publishItems( QList<Jreen::Payload::Ptr>() << tune, Jreen::JID() );
}
void
Tomahawk::InfoSystem::XmppInfoPlugin::audioPaused()
{
tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full();
}
void
Tomahawk::InfoSystem::XmppInfoPlugin::audioStopped()
{
tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full();
Jreen::Tune::Ptr tune( new Jreen::Tune() );
m_pubSubManager->publishItems(QList<Jreen::Payload::Ptr>() << tune, Jreen::JID());
}
void
Tomahawk::InfoSystem::XmppInfoPlugin::getInfo(Tomahawk::InfoSystem::InfoRequestData requestData)
{
Q_UNUSED( requestData );
}
void
Tomahawk::InfoSystem::XmppInfoPlugin::notInCacheSlot(const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData)
{
Q_UNUSED( criteria );
Q_UNUSED( requestData );
}

View File

@ -0,0 +1,68 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012, Dominik Schmidt <domme@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 XMPPINFOPLUGIN_H
#define XMPPINFOPLUGIN_H
#include "infosystem/infosystem.h"
#include <QTimer>
namespace Jreen {
namespace PubSub {
class Manager;
}
}
class XmppSipPlugin;
namespace Tomahawk {
namespace InfoSystem {
class XmppInfoPlugin : public InfoPlugin
{
Q_OBJECT
public:
XmppInfoPlugin(XmppSipPlugin* parent);
virtual ~XmppInfoPlugin();
public slots:
void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
protected slots:
void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input );
void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
private slots:
void audioStarted( const Tomahawk::InfoSystem::InfoStringHash& info );
void audioStopped();
void audioPaused();
private:
XmppSipPlugin* m_sipPlugin;
Jreen::PubSub::Manager* m_pubSubManager;
QTimer m_pauseTimer;
};
}
}
#endif // XMPPINFOPLUGIN_H

View File

@ -7,6 +7,7 @@ set( googleHeaders
../sip/xmppsip.h
../sip/avatarmanager.h
../sip/xmlconsole.h
../XmppInfoPlugin.h
googlewrapper.h )
set( googleSources
@ -17,6 +18,7 @@ set( googleSources
../sip/tomahawkxmppmessagefactory.cpp
../sip/avatarmanager.cpp
../sip/xmlconsole.cpp
../XmppInfoPlugin.cpp
googlewrapper.cpp )

View File

@ -56,6 +56,7 @@
#include <utils/tomahawkutilsgui.h>
#include "utils/logger.h"
#include "XmppInfoPlugin.h"
using namespace Tomahawk;
using namespace Accounts;
@ -85,6 +86,7 @@ JreenMessageHandler(QtMsgType type, const char *msg)
XmppSipPlugin::XmppSipPlugin( Account *account )
: SipPlugin( account )
, m_infoPlugin( 0 )
, m_state( Account::Disconnected )
#ifndef ENABLE_HEADLESS
, m_menu( 0 )
@ -163,6 +165,7 @@ XmppSipPlugin::XmppSipPlugin( Account *account )
XmppSipPlugin::~XmppSipPlugin()
{
delete m_infoPlugin;
delete m_avatarManager;
delete m_roster;
#ifndef ENABLE_HEADLESS
@ -172,6 +175,13 @@ XmppSipPlugin::~XmppSipPlugin()
}
InfoSystem::InfoPlugin*
XmppSipPlugin::infoPlugin()
{
return m_infoPlugin;
}
#ifndef ENABLE_HEADLESS
QMenu*
XmppSipPlugin::menu()
@ -255,6 +265,13 @@ XmppSipPlugin::onConnect()
// load roster
m_roster->load();
// load XmppInfoPlugin
if( !m_infoPlugin )
{
m_infoPlugin = new Tomahawk::InfoSystem::XmppInfoPlugin( this );
InfoSystem::InfoSystem::instance()->addInfoPlugin( m_infoPlugin );
}
//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

View File

@ -52,10 +52,14 @@
#include "accounts/accountdllmacro.h"
#include "XmppInfoPlugin.h"
class ACCOUNTDLLEXPORT XmppSipPlugin : public SipPlugin
{
Q_OBJECT
friend class Tomahawk::InfoSystem::XmppInfoPlugin;
public:
XmppSipPlugin( Tomahawk::Accounts::Account* account );
virtual ~XmppSipPlugin();
@ -63,6 +67,8 @@ public:
//FIXME: Make this more correct
virtual bool isValid() const { return true; }
Tomahawk::InfoSystem::InfoPlugin* infoPlugin();
#ifndef ENABLE_HEADLESS
virtual QMenu* menu();
#endif
@ -123,10 +129,11 @@ private:
QString m_currentPassword;
QString m_currentServer;
int m_currentPort;
Tomahawk::Accounts::Account::ConnectionState m_state;
QString m_currentResource;
Tomahawk::InfoSystem::InfoPlugin* m_infoPlugin;
Tomahawk::Accounts::Account::ConnectionState m_state;
// sort out
Jreen::Client *m_client;

View File

@ -22,6 +22,7 @@
#include "xmppconfigwidget.h"
#include "sip/SipPlugin.h"
#include "ui_xmppconfigwidget.h"
#include "XmppInfoPlugin.h"
#include <QtCore/QtPlugin>
@ -90,6 +91,16 @@ XmppAccount::saveConfig()
}
InfoSystem::InfoPlugin*
XmppAccount::infoPlugin()
{
if( !m_xmppSipPlugin.isNull() )
return m_xmppSipPlugin.data()->infoPlugin();
return 0;
}
SipPlugin*
XmppAccount::sipPlugin()
{

View File

@ -69,7 +69,8 @@ public:
void deauthenticate();
bool isAuthenticated() const;
Tomahawk::InfoSystem::InfoPlugin* infoPlugin() { return 0; }
Tomahawk::InfoSystem::InfoPlugin* infoPlugin();
SipPlugin* sipPlugin();
QWidget* configurationWidget() { return m_configWidget.data(); }
@ -81,6 +82,7 @@ public:
protected:
QWeakPointer< QWidget > m_configWidget; // so the google wrapper can change the config dialog a bit
QWeakPointer< XmppSipPlugin > m_xmppSipPlugin;
QWeakPointer< Tomahawk::InfoSystem::XmppInfoPlugin > m_xmppInfoPlugin;
};
};

View File

@ -43,6 +43,7 @@ XmppConfigWidget::XmppConfigWidget( XmppAccount* account, QWidget *parent ) :
m_ui->xmppPassword->setText( account->credentials().contains( "password" ) ? account->credentials()[ "password" ].toString() : QString() );
m_ui->xmppServer->setText( account->configuration().contains( "server" ) ? account->configuration()[ "server" ].toString() : QString() );
m_ui->xmppPort->setValue( account->configuration().contains( "port" ) ? account->configuration()[ "port" ].toInt() : 5222 );
m_ui->xmppPublishTracksCheckbox->setChecked( account->configuration().contains( "publishtracks" ) ? account->configuration()[ "publishtracks" ].toBool() : true);
m_ui->jidExistsLabel->hide();
connect( m_ui->xmppUsername, SIGNAL( textChanged( QString ) ), SLOT( onCheckJidExists( QString ) ) );
@ -64,6 +65,7 @@ XmppConfigWidget::saveConfig()
QVariantHash configuration = m_account->configuration();
configuration[ "server" ] = m_ui->xmppServer->text().trimmed();
configuration[ "port" ] = m_ui->xmppPort->text().trimmed();
configuration[ "publishtracks"] = m_ui->xmppPublishTracksCheckbox->checkState() == Qt::Checked;
m_account->setAccountFriendlyName( m_ui->xmppUsername->text() );
m_account->setCredentials( credentials );

View File

@ -209,7 +209,7 @@
<property name="title">
<string>Advanced Xmpp Settings</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
@ -293,6 +293,16 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="xmppPublishTracksCheckbox">
<property name="toolTip">
<string>Lots of servers don't support this (e.g. GTalk, jabber.org)</string>
</property>
<property name="text">
<string>Publish currently playing track</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -278,7 +278,7 @@ void
AudioControls::onSocialActionsLoaded()
{
Query* query = qobject_cast< Query* >( sender() );
if ( !query || !m_currentTrack || query != m_currentTrack->toQuery().data() )
if ( !query || !m_currentTrack || !query->equals( m_currentTrack->toQuery() ) )
return;
setSocialActions();

View File

@ -142,7 +142,7 @@
<number>0</number>
</property>
<item>
<widget class="QLabel" name="coverImage">
<widget class="FadingPixmap" name="coverImage">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -561,6 +561,11 @@
<extends>QLabel</extends>
<header>widgets/querylabel.h</header>
</customwidget>
<customwidget>
<class>FadingPixmap</class>
<extends>QLabel</extends>
<header>widgets/FadingPixmap.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View File

@ -17,6 +17,9 @@
#cmakedefine LEOPARD
#cmakedefine HAVE_SPARKLE
#cmakedefine WITH_BREAKPAD
#cmakedefine WITH_CRASHREPORTER
#cmakedefine LIBLASTFM_FOUND
#cmakedefine GLOOX_FOUND
#cmakedefine QCA2_FOUND

View File

@ -119,6 +119,7 @@ set( libGuiSources
utils/dropjobnotifier.cpp
utils/proxystyle.cpp
utils/tomahawkutilsgui.cpp
utils/closure.cpp
widgets/animatedcounterlabel.cpp
widgets/checkdirtree.cpp
@ -141,6 +142,7 @@ set( libGuiSources
widgets/HeaderWidget.cpp
widgets/combobox.cpp
widgets/ToggleButton.cpp
widgets/FadingPixmap.cpp
widgets/SocialPlaylistWidget.cpp
widgets/infowidgets/sourceinfowidget.cpp
widgets/infowidgets/ArtistInfoWidget.cpp
@ -151,9 +153,6 @@ set( libGuiSources
IF(QCA2_FOUND)
set( libGuiSources ${libGuiSources} utils/groovesharkparser.cpp )
ENDIF(QCA2_FOUND)
IF(QCA2_FOUND)
set( libGuiHeaders ${libGuiHeaders} utils/groovesharkparser.h )
ENDIF(QCA2_FOUND)

View File

@ -46,7 +46,6 @@ accountTypeToString( AccountType type )
Account::Account( const QString& accountId )
: QObject()
, m_enabled( false )
, m_autoConnect( false )
, m_accountId( accountId )
{
connect( this, SIGNAL( error( int, QString ) ), this, SLOT( onError( int,QString ) ) );
@ -126,7 +125,6 @@ Account::syncConfig()
s->beginGroup( "accounts/" + m_accountId );
s->setValue( "accountfriendlyname", m_accountFriendlyName );
s->setValue( "enabled", m_enabled );
s->setValue( "autoconnect", m_autoConnect );
s->setValue( "credentials", m_credentials );
s->setValue( "configuration", m_configuration );
s->setValue( "acl", m_acl );
@ -144,7 +142,6 @@ Account::loadFromConfig( const QString& accountId )
s->beginGroup( "accounts/" + m_accountId );
m_accountFriendlyName = s->value( "accountfriendlyname", QString() ).toString();
m_enabled = s->value( "enabled", false ).toBool();
m_autoConnect = s->value( "autoconnect", false ).toBool();
m_credentials = s->value( "credentials", QVariantHash() ).toHash();
m_configuration = s->value( "configuration", QVariantHash() ).toHash();
m_acl = s->value( "acl", QVariantMap() ).toMap();
@ -160,7 +157,6 @@ Account::removeFromConfig()
s->beginGroup( "accounts/" + m_accountId );
s->remove( "accountfriendlyname" );
s->remove( "enabled" );
s->remove( "autoconnect" );
s->remove( "credentials" );
s->remove( "configuration" );
s->remove( "acl" );

View File

@ -78,7 +78,6 @@ public:
QString accountServiceName() const { QMutexLocker locker( &m_mutex ); return m_accountServiceName; } // e.g. "Twitter", "Last.fm"
QString accountFriendlyName() const { QMutexLocker locker( &m_mutex ); return m_accountFriendlyName; } // e.g. screen name on the service, JID, etc.
bool enabled() const { QMutexLocker locker( &m_mutex ); return m_enabled; }
bool autoConnect() const { QMutexLocker locker( &m_mutex ); return m_autoConnect; }
QString accountId() const { QMutexLocker locker( &m_mutex ); return m_accountId; }
QVariantHash configuration() const { QMutexLocker locker( &m_mutex ); return m_configuration; }
@ -109,7 +108,6 @@ public:
void setAccountServiceName( const QString &serviceName ) { QMutexLocker locker( &m_mutex ); m_accountServiceName = serviceName; }
void setAccountFriendlyName( const QString &friendlyName ) { QMutexLocker locker( &m_mutex ); m_accountFriendlyName = friendlyName; }
void setEnabled( bool enabled ) { QMutexLocker locker( &m_mutex ); m_enabled = enabled; }
void setAutoConnect( bool autoConnect ) { QMutexLocker locker( &m_mutex ); m_autoConnect = autoConnect; }
void setAccountId( const QString &accountId ) { QMutexLocker locker( &m_mutex ); m_accountId = accountId; }
void setCredentials( const QVariantHash &credentialHash ) { QMutexLocker locker( &m_mutex ); m_credentials = credentialHash; }
void setConfiguration( const QVariantHash &configuration ) { QMutexLocker locker( &m_mutex ); m_configuration = configuration; }
@ -148,7 +146,6 @@ private:
QString m_accountFriendlyName;
QString m_cachedError;
bool m_enabled;
bool m_autoConnect;
QString m_accountId;
QVariantHash m_credentials;
QVariantHash m_configuration;

View File

@ -374,7 +374,7 @@ AccountManager::hookupAndEnable( Account* account, bool startup )
if ( p )
SipHandler::instance()->hookUpPlugin( p );
if ( account->enabled() && ( !startup || account->autoConnect() ) )
if ( account->enabled() )
{
account->authenticate();
m_enabledAccounts << account;

View File

@ -82,13 +82,6 @@ Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr&
, m_cover( 0 )
#endif
{
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( finished( QString ) ),
SLOT( infoSystemFinished( QString ) ) );
}
@ -131,6 +124,14 @@ Album::cover( const QSize& size, bool forceLoad ) const
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
requestData.customData = QVariantMap();
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( finished( QString ) ),
SLOT( infoSystemFinished( QString ) ) );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
}
@ -190,6 +191,12 @@ Album::infoSystemFinished( QString target )
if ( target != m_uuid )
return;
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
this, SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ),
this, SLOT( infoSystemFinished( QString ) ) );
m_infoLoaded = true;
emit updated();
}

View File

@ -82,14 +82,6 @@ Artist::Artist( unsigned int id, const QString& name )
#endif
{
m_sortname = DatabaseImpl::sortname( name, true );
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( finished( QString ) ),
SLOT( infoSystemFinished( QString ) ) );
}
@ -122,6 +114,14 @@ Artist::cover( const QSize& size, bool forceLoad ) const
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
requestData.customData = QVariantMap();
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
SIGNAL( finished( QString ) ),
SLOT( infoSystemFinished( QString ) ) );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
}
@ -181,6 +181,12 @@ Artist::infoSystemFinished( QString target )
if ( target != m_uuid )
return;
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
this, SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ),
this, SLOT( infoSystemFinished( QString ) ) );
m_infoLoaded = true;
emit updated();
}

View File

@ -78,7 +78,7 @@ AudioEngine::AudioEngine()
connect( m_audioOutput, SIGNAL( volumeChanged( qreal ) ), SLOT( onVolumeChanged( qreal ) ) );
connect( this, SIGNAL( sendWaitingNotification() ), SLOT( sendWaitingNotificationSlot() ), Qt::QueuedConnection );
onVolumeChanged( m_audioOutput->volume() );
#ifndef Q_WS_X11
@ -134,14 +134,22 @@ AudioEngine::play()
{
m_mediaObject->play();
emit resumed();
Tomahawk::InfoSystem::InfoStringHash trackInfo;
trackInfo["title"] = m_currentTrack->track();
trackInfo["artist"] = m_currentTrack->artist()->name();
trackInfo["album"] = m_currentTrack->album()->name();
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowResumed,
QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ) );
if ( TomahawkSettings::instance()->privateListeningMode() != TomahawkSettings::FullyPrivate )
{
Tomahawk::InfoSystem::InfoStringHash trackInfo;
trackInfo["title"] = m_currentTrack->track();
trackInfo["artist"] = m_currentTrack->artist()->name();
trackInfo["album"] = m_currentTrack->album()->name();
trackInfo["albumpos"] = QString::number( m_currentTrack->albumpos() );
trackInfo["duration"] = QString::number( m_currentTrack->duration() );
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowResumed,
QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ) );
}
}
else
next();
@ -319,7 +327,7 @@ AudioEngine::sendWaitingNotificationSlot() const
//since it's async, after this is triggered our result could come in, so don't show the popup in that case
if ( !m_playlist.isNull() && m_playlist->hasNextItem() )
return;
QVariantMap retryInfo;
retryInfo["message"] = QString( "The current track could not be resolved. Tomahawk will pick back up with the next resolvable track from this source." );
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
@ -460,6 +468,8 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
trackInfo["title"] = m_currentTrack->track();
trackInfo["artist"] = m_currentTrack->artist()->name();
trackInfo["album"] = m_currentTrack->album()->name();
trackInfo["duration"] = QString::number( m_currentTrack->duration() );
trackInfo["albumpos"] = QString::number( m_currentTrack->albumpos() );
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
s_aeInfoIdentifier,
@ -506,6 +516,16 @@ AudioEngine::loadNextTrack()
Tomahawk::result_ptr result;
if ( !m_stopAfterTrack.isNull() )
{
if ( m_stopAfterTrack->equals( m_currentTrack->toQuery() ) )
{
m_stopAfterTrack.clear();
stop();
return;
}
}
if ( m_queue && m_queue->trackCount() )
{
result = m_queue->nextItem();
@ -545,7 +565,9 @@ AudioEngine::playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk:
m_currentTrackPlaylist = playlist;
if ( !result.isNull() )
{
loadTrack( result );
}
else if ( !m_playlist.isNull() && m_playlist.data()->retryMode() == PlaylistInterface::Retry )
{
m_waitingOnNewTrack = true;
@ -668,6 +690,9 @@ AudioEngine::timerTriggered( qint64 time )
void
AudioEngine::setPlaylist( Tomahawk::playlistinterface_ptr playlist )
{
if ( m_playlist == playlist )
return;
if ( !m_playlist.isNull() )
{
if ( m_playlist.data() && m_playlist.data()->retryMode() == PlaylistInterface::Retry )
@ -681,8 +706,9 @@ AudioEngine::setPlaylist( Tomahawk::playlistinterface_ptr playlist )
emit playlistChanged( playlist );
return;
}
m_playlist = playlist;
m_stopAfterTrack.clear();
if ( !m_playlist.isNull() && m_playlist.data() && m_playlist.data()->retryMode() == PlaylistInterface::Retry )
connect( m_playlist.data(), SIGNAL( nextTrackReady() ), SLOT( onPlaylistNextTrackReady() ) );
@ -694,16 +720,16 @@ AudioEngine::setPlaylist( Tomahawk::playlistinterface_ptr playlist )
void
AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result )
{
m_lastTrack = m_currentTrack;
if ( !m_lastTrack.isNull() )
Tomahawk::result_ptr lastTrack = m_currentTrack;
if ( !lastTrack.isNull() )
{
if ( TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::PublicListening )
{
DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( m_lastTrack, DatabaseCommand_LogPlayback::Finished, m_timeElapsed );
DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( lastTrack, DatabaseCommand_LogPlayback::Finished, m_timeElapsed );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
}
emit finished( m_lastTrack );
emit finished( lastTrack );
}
m_currentTrack = result;

View File

@ -64,6 +64,8 @@ public:
Tomahawk::playlistinterface_ptr playlist() const { return m_playlist; }
Tomahawk::result_ptr currentTrack() const { return m_currentTrack; }
Tomahawk::query_ptr stopAfterTrack() const { return m_stopAfterTrack; }
qint64 currentTime() const { return m_mediaObject->currentTime(); }
qint64 currentTrackTotalTime() const { return m_mediaObject->totalTime(); }
@ -91,6 +93,8 @@ public slots:
void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::result_ptr& result );
void setPlaylist( Tomahawk::playlistinterface_ptr playlist );
void setQueue( Tomahawk::playlistinterface_ptr queue ) { m_queue = queue; }
void setStopAfterTrack( const Tomahawk::query_ptr& query ) { m_stopAfterTrack = query; }
signals:
void loading( const Tomahawk::result_ptr& track );
@ -141,8 +145,8 @@ private:
QSharedPointer<QIODevice> m_input;
Tomahawk::query_ptr m_stopAfterTrack;
Tomahawk::result_ptr m_currentTrack;
Tomahawk::result_ptr m_lastTrack;
Tomahawk::playlistinterface_ptr m_playlist;
Tomahawk::playlistinterface_ptr m_currentTrackPlaylist;
Tomahawk::playlistinterface_ptr m_queue;

View File

@ -38,6 +38,8 @@ RelatedArtistsContext::RelatedArtistsContext()
m_relatedModel->setColumnStyle( TreeModel::TrackOnly );
m_relatedView->setTreeModel( m_relatedModel );
m_relatedView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
m_relatedView->setSortingEnabled( false );
m_relatedView->proxyModel()->sort( -1 );
QPalette pal = m_relatedView->palette();
pal.setColor( QPalette::Window, QColor( 0, 0, 0, 0 ) );

View File

@ -1,3 +1,4 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
@ -37,7 +38,7 @@ ContextMenu::ContextMenu( QWidget* parent )
m_sigmap = new QSignalMapper( this );
connect( m_sigmap, SIGNAL( mapped( int ) ), SLOT( onTriggered( int ) ) );
m_supportedActions = ActionPlay | ActionQueue | ActionCopyLink | ActionLove;
m_supportedActions = ActionPlay | ActionQueue | ActionCopyLink | ActionLove | ActionStopAfter;
}
@ -80,6 +81,14 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
if ( m_supportedActions & ActionQueue )
m_sigmap->setMapping( addAction( tr( "Add to &Queue" ) ), ActionQueue );
if ( m_supportedActions & ActionStopAfter && itemCount() == 1 )
{
if ( AudioEngine::instance()->stopAfterTrack() == queries.first() )
m_sigmap->setMapping( addAction( tr( "&Continue playback after this track" ) ), ActionStopAfter );
else
m_sigmap->setMapping( addAction( tr( "&Stop playback after this track" ) ), ActionStopAfter );
}
addSeparator();
if ( m_supportedActions & ActionLove && itemCount() == 1 )
@ -110,7 +119,6 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
void
ContextMenu::setQuery( const Tomahawk::query_ptr& query )
{
QList<query_ptr> queries;
queries << query;
setQueries( queries );
@ -212,6 +220,13 @@ ContextMenu::onTriggered( int action )
m_queries.first()->setLoved( !m_queries.first()->loved() );
break;
case ActionStopAfter:
if ( m_queries.first()->equals( AudioEngine::instance()->stopAfterTrack() ) )
AudioEngine::instance()->setStopAfterTrack( query_ptr() );
else
AudioEngine::instance()->setStopAfterTrack( m_queries.first() );
break;
default:
emit triggered( action );
}

View File

@ -40,7 +40,8 @@ public:
ActionQueue = 2,
ActionDelete = 4,
ActionCopyLink = 8,
ActionLove = 16
ActionLove = 16,
ActionStopAfter = 32
};
explicit ContextMenu( QWidget* parent = 0 );

View File

@ -89,12 +89,13 @@ GlobalActionManager::openLinkFromQuery( const query_ptr& query ) const
{
QString title, artist, album;
if( !query->results().isEmpty() && !query->results().first().isNull() )
if ( !query->results().isEmpty() && !query->results().first().isNull() )
{
title = query->results().first()->track();
artist = query->results().first()->artist().isNull() ? QString() : query->results().first()->artist()->name();
album = query->results().first()->album().isNull() ? QString() : query->results().first()->album()->name();
} else
}
else
{
title = query->track();
artist = query->artist();
@ -110,11 +111,11 @@ GlobalActionManager::openLink( const QString& title, const QString& artist, cons
{
QUrl link( QString( "%1/open/track/" ).arg( hostname() ) );
if( !title.isEmpty() )
link.addQueryItem( "title", title );
if( !artist.isEmpty() )
if ( !artist.isEmpty() )
link.addQueryItem( "artist", artist );
if( !album.isEmpty() )
if ( !title.isEmpty() )
link.addQueryItem( "title", title );
if ( !album.isEmpty() )
link.addQueryItem( "album", album );
return link;

View File

@ -85,7 +85,7 @@ InfoBar::InfoBar( QWidget* parent )
m_autoUpdate->setText( tr( "Automatically update" ) );
m_autoUpdate->setLayoutDirection( Qt::RightToLeft );
m_autoUpdate->setPalette( whitePal );
connect( m_autoUpdate, SIGNAL( stateChanged( int ) ), this, SIGNAL( autoUpdateChanged( int ) ) );
connect( m_autoUpdate, SIGNAL( toggled( bool ) ), this, SIGNAL( autoUpdateChanged( bool ) ) );
ui->horizontalLayout->addWidget( m_autoUpdate );

View File

@ -60,7 +60,7 @@ public slots:
void setAutoUpdateAvailable( bool b );
signals:
void filterTextChanged( const QString& filter );
void autoUpdateChanged( int state );
void autoUpdateChanged( bool checked );
protected:
void changeEvent( QEvent* e );

View File

@ -188,8 +188,7 @@ public:
QList<plentry_ptr> entriesFromQueries( const QList<Tomahawk::query_ptr>& queries, bool clearFirst = false );
void setUpdater( PlaylistUpdaterInterface* interface ) { m_updater = interface; }
void setUpdater( PlaylistUpdaterInterface* pluinterface ) { m_updater = pluinterface; }
PlaylistUpdaterInterface* updater() const { return m_updater; }
Tomahawk::playlistinterface_ptr playlistInterface();

View File

@ -40,10 +40,11 @@
using namespace Tomahawk;
PlaylistLargeItemDelegate::PlaylistLargeItemDelegate( TrackView* parent, TrackProxyModel* proxy )
PlaylistLargeItemDelegate::PlaylistLargeItemDelegate( DisplayMode mode, TrackView* parent, TrackProxyModel* proxy )
: QStyledItemDelegate( (QObject*)parent )
, m_view( parent )
, m_model( proxy )
, m_mode( mode )
{
m_topOption = QTextOption( Qt::AlignTop );
m_topOption.setWrapMode( QTextOption::NoWrap );
@ -149,8 +150,7 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem&
return;
QPixmap pixmap, avatar;
QString artist, track, upperText, lowerText;
source_ptr source = item->query()->playedBy().first;
QString artist, track, lowerText;
unsigned int duration = 0;
if ( item->query()->results().count() )
@ -165,14 +165,11 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem&
track = item->query()->track();
}
lowerText = item->query()->socialActionDescription( "Love", Query::Detailed );
if ( source.isNull() )
QSize avatarSize( 32, 32 );
source_ptr source = item->query()->playedBy().first;
if ( m_mode == RecentlyPlayed && !source.isNull() )
{
}
else
{
upperText = QString( "%1 - %2" ).arg( artist ).arg( track );
avatar = source->avatar( Source::FancyStyle, avatarSize );
QString playtime = TomahawkUtils::ageToString( QDateTime::fromTime_t( item->query()->playedBy().second ), true );
if ( source == SourceList::instance()->getLocal() )
@ -181,6 +178,16 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem&
lowerText = QString( tr( "played %1 by %2" ) ).arg( playtime ).arg( source->friendlyName() );
}
if ( m_mode == LatestAdditions && item->query()->numResults() )
{
QString playtime = TomahawkUtils::ageToString( QDateTime::fromTime_t( item->query()->results().first()->modificationTime() ), true );
lowerText = QString( tr( "added %1" ) ).arg( playtime );
}
if ( m_mode == LovedTracks )
lowerText = item->query()->socialActionDescription( "Love", Query::Detailed );
painter->save();
{
QRect r = opt.rect.adjusted( 3, 6, 0, -6 );
@ -197,14 +204,10 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem&
painter->setPen( opt.palette.text().color() );
QSize avatarSize( 32, 32 );
QRect pixmapRect = r.adjusted( 6, 0, -option.rect.width() + option.rect.height() - 6 + r.left(), 0 );
QRect avatarRect = r.adjusted( option.rect.width() - r.left() - 12 - avatarSize.width(), ( option.rect.height() - avatarSize.height() ) / 2 - 5, 0, 0 );
avatarRect.setSize( avatarSize );
if ( source )
avatar = source->avatar( Source::FancyStyle, avatarRect.size() );
pixmap = item->query()->cover( pixmapRect.size(), false );
if ( !pixmap )
{

View File

@ -35,7 +35,10 @@ class DLLEXPORT PlaylistLargeItemDelegate : public QStyledItemDelegate
Q_OBJECT
public:
PlaylistLargeItemDelegate( TrackView* parent = 0, TrackProxyModel* proxy = 0 );
enum DisplayMode
{ LovedTracks, RecentlyPlayed, LatestAdditions };
PlaylistLargeItemDelegate( DisplayMode mode, TrackView* parent = 0, TrackProxyModel* proxy = 0 );
protected:
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
@ -52,6 +55,7 @@ private:
TrackView* m_view;
TrackProxyModel* m_model;
DisplayMode m_mode;
};
#endif // PLAYLISTLARGEITEMDELEGATE_H

View File

@ -79,8 +79,6 @@ PlaylistUpdaterInterface::PlaylistUpdaterInterface( const playlist_ptr& pl )
connect( m_timer, SIGNAL( timeout() ), this, SLOT( updateNow() ) );
QTimer::singleShot( 0, this, SLOT( doSave() ) );
setAutoUpdate( m_autoUpdate );
}
PlaylistUpdaterInterface::PlaylistUpdaterInterface( const playlist_ptr& pl, int interval, bool autoUpdate )

View File

@ -40,6 +40,8 @@ RecentlyPlayedModel::RecentlyPlayedModel( const source_ptr& source, QObject* par
{
if ( source.isNull() )
{
onSourcesReady();
connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) );
connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) );
}

View File

@ -55,8 +55,15 @@ XspfUpdater::~XspfUpdater()
void
XspfUpdater::updateNow()
{
if ( m_url.isEmpty() )
{
qWarning() << "XspfUpdater not updating because we have an empty url...";
return;
}
XSPFLoader* l = new XSPFLoader( false, false );
l->setAutoResolveTracks( false );
l->setErrorTitle( playlist()->title() );
l->load( m_url );
connect( l, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( playlistLoaded( QList<Tomahawk::query_ptr> ) ) );
}

View File

@ -597,7 +597,9 @@ EchonestGenerator::sentenceSummary()
suffix = ", ";
else
suffix = ".";
} else
} else if ( i < required.size() - 2 ) // An item in the list that is before the second to last one, don't use ", and", we only want that for the last item
suffix += ", ";
else
suffix += ", and ";
}
sentence += center + suffix;

View File

@ -97,10 +97,13 @@ PlaylistItemDelegate::prepareStyleOption( QStyleOptionViewItemV4* option, const
if ( item->isPlaying() )
{
option->palette.setColor( QPalette::Highlight, option->palette.color( QPalette::Mid ) );
option->state |= QStyle::State_Selected;
option->backgroundBrush = option->palette.color( QPalette::Mid );
option->palette.setColor( QPalette::Text, option->palette.color( QPalette::Text ) );
}
if ( option->state & QStyle::State_Selected )
if ( option->state & QStyle::State_Selected && !item->isPlaying() )
{
option->palette.setColor( QPalette::Text, option->palette.color( QPalette::HighlightedText ) );
}
@ -203,7 +206,10 @@ PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem&
QRect ir = r.adjusted( 4, 0, -option.rect.width() + option.rect.height() - 8 + r.left(), 0 );
if ( useAvatars )
pixmap = source->avatar( Source::FancyStyle, ir.size() );
{
if ( !source.isNull() )
pixmap = source->avatar( Source::FancyStyle, ir.size() );
}
else
pixmap = item->query()->cover( ir.size(), false );

View File

@ -82,10 +82,7 @@ TrackModelItem::entry() const
const Tomahawk::query_ptr&
TrackModelItem::query() const
{
if ( !m_entry.isNull() )
return m_entry->query();
else
return m_query;
return m_query;
}

View File

@ -33,6 +33,7 @@
#include "dynamic/widgets/LoadingSpinner.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#include "utils/closure.h"
#include "dropjob.h"
#include "artist.h"
#include "album.h"
@ -205,6 +206,41 @@ TrackView::onScrollTimeout()
}
void
TrackView::startPlayingFromStart()
{
if ( m_proxyModel->rowCount() == 0 )
return;
const QModelIndex index = m_proxyModel->index( 0, 0 );
startAutoPlay( index );
}
void
TrackView::autoPlayResolveFinished( const query_ptr& query, int row )
{
Q_ASSERT( !query.isNull() );
Q_ASSERT( row >= 0 );
if ( query.isNull() || row < 0 || query != m_autoPlaying )
return;
const QModelIndex index = m_proxyModel->index( row, 0 );
if ( query->playable() )
{
onItemActivated( index );
return;
}
// Try the next one..
const QModelIndex sib = index.sibling( index.row() + 1, index.column() );
if ( sib.isValid() )
startAutoPlay( sib );
}
void
TrackView::currentChanged( const QModelIndex& current, const QModelIndex& previous )
{
@ -227,15 +263,48 @@ TrackView::onItemActivated( const QModelIndex& index )
if ( !index.isValid() )
return;
tryToPlayItem( index );
emit itemActivated( index );
}
void
TrackView::startAutoPlay( const QModelIndex& index )
{
if ( tryToPlayItem( index ) )
return;
// item isn't playable but still resolving
TrackModelItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( index ) );
if ( item && !item->query().isNull() && !item->query()->resolvingFinished() )
{
m_autoPlaying = item->query(); // So we can kill it if user starts autoplaying this playlist again
NewClosure( item->query().data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( autoPlayResolveFinished( Tomahawk::query_ptr, int ) ),
item->query(), index.row() );
return;
}
// not playable at all, try next
const QModelIndex sib = index.sibling( index.row() + 1, index.column() );
if ( sib.isValid() )
startAutoPlay( sib );
}
bool
TrackView::tryToPlayItem( const QModelIndex& index )
{
TrackModelItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( index ) );
if ( item && !item->query().isNull() && item->query()->numResults() )
{
tDebug() << "Result activated:" << item->query()->toString() << item->query()->results().first()->url();
m_proxyModel->setCurrentIndex( index );
AudioEngine::instance()->playItem( m_proxyModel->playlistInterface(), item->query()->results().first() );
return true;
}
emit itemActivated( index );
return false;
}
@ -489,7 +558,12 @@ TrackView::onCustomContextMenu( const QPoint& pos )
TrackModelItem* item = proxyModel()->itemFromIndex( proxyModel()->mapToSource( index ) );
if ( item && !item->query().isNull() )
queries << item->query();
{
if ( item->query()->numResults() > 0 )
queries << item->query()->results().first()->toQuery();
else
queries << item->query();
}
}
m_contextMenu->setQueries( queries );

View File

@ -66,6 +66,9 @@ public:
bool updatesContextView() const { return m_updateContextView; }
void setUpdatesContextView( bool b ) { m_updateContextView = b; }
// Starts playing from the beginning if resolved, or waits until a track is playable
void startPlayingFromStart();
public slots:
virtual void onItemActivated( const QModelIndex& index );
@ -103,7 +106,11 @@ private slots:
void onCustomContextMenu( const QPoint& pos );
void autoPlayResolveFinished( const Tomahawk::query_ptr& query, int row );
private:
void startAutoPlay( const QModelIndex& index );
bool tryToPlayItem( const QModelIndex& index );
void updateHoverIndex( const QPoint& pos );
QString m_guid;
@ -122,6 +129,9 @@ private:
QModelIndex m_hoveredIndex;
QModelIndex m_contextMenuIndex;
Tomahawk::query_ptr m_autoPlaying;
Tomahawk::ContextMenu* m_contextMenu;
QTimer m_timer;

View File

@ -2,6 +2,7 @@
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
* Copyright 2012, Leo Franchi <lfranchi@kde.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
@ -623,7 +624,7 @@ TreeModel::addAlbums( const artist_ptr& artist, const QModelIndex& parent, bool
requestData.caller = m_infoId;
requestData.customData["row"] = parent.row();
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
requestData.customData["refetch"] = QVariant( autoRefetch );
requestData.customData["refetch"] = autoRefetch;
requestData.type = Tomahawk::InfoSystem::InfoArtistReleases;
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
}
@ -661,8 +662,8 @@ TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent, bool au
m_receivedInfoData.removeAll( artistInfo );
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = m_infoId;
requestData.customData["rows"] = QVariant( rows );
requestData.customData["refetch"] = QVariant( autoRefetch );
requestData.customData["rows"] = rows;
requestData.customData["refetch"] = autoRefetch;
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
requestData.type = Tomahawk::InfoSystem::InfoAlbumSongs;
requestData.timeoutMillis = 0;
@ -797,7 +798,7 @@ TreeModel::onAlbumsAdded( const QList<Tomahawk::album_ptr>& albums, const QModel
albumitem = new TreeModelItem( album, parentItem );
albumitem->index = createIndex( parentItem->children.count() - 1, 0, albumitem );
connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
getCover( albumitem->index );
}
@ -887,7 +888,7 @@ TreeModel::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QV
QModelIndex idx = index( requestData.customData[ "row" ].toInt(), 0, QModelIndex() );
if ( requestData.customData[ "refetch" ].toInt() > 0 && !al.count() )
if ( requestData.customData[ "refetch" ].toBool() && !al.count() )
{
setMode( DatabaseMode );
@ -941,7 +942,13 @@ TreeModel::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QV
}
else if ( m_receivedInfoData.count() == 2 /* FIXME */ )
{
if ( requestData.customData[ "refetch" ].toInt() > 0 )
// If the second load got no data, but the first load did, don't do anything
QList< QVariant > rows = requestData.customData[ "rows" ].toList();
QModelIndex idx = index( rows.first().toUInt(), 0, index( rows.at( 1 ).toUInt(), 0, QModelIndex() ) );
if ( rowCount( idx ) )
return;
if ( requestData.customData[ "refetch" ].toBool() )
{
setMode( DatabaseMode );

View File

@ -58,7 +58,6 @@ Query::get( const QString& artist, const QString& track, const QString& album, c
query_ptr
Query::get( const QString& query, const QID& qid )
{
query_ptr q = query_ptr( new Query( query, qid ), &QObject::deleteLater );
q->setWeakRef( q.toWeakRef() );
@ -164,6 +163,7 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults )
m_results << newresults;
qStableSort( m_results.begin(), m_results.end(), Query::resultSorter );
query_ptr q = m_ownRef.toStrongRef();
// hook up signals, and check solved status
foreach( const result_ptr& rp, newresults )
@ -412,6 +412,18 @@ Query::checkResults()
}
bool
Query::equals( const Tomahawk::query_ptr& other ) const
{
if ( other.isNull() )
return false;
return ( artist() == other->artist() &&
album() == other->album() &&
track() == other->track() );
}
QVariant
Query::toVariant() const
{
@ -538,7 +550,7 @@ Query::parseSocialActions()
{
Tomahawk::SocialAction socialAction;
socialAction = it.next();
if ( socialAction.timestamp.toUInt() > highestTimestamp && socialAction.source->id() == SourceList::instance()->getLocal()->id() )
if ( socialAction.timestamp.toUInt() > highestTimestamp && socialAction.source->isLocal() )
{
m_currentSocialActions[ socialAction.action.toString() ] = socialAction.value.toBool();
}
@ -568,7 +580,7 @@ Query::setLoved( bool loved )
query_ptr q = m_ownRef.toStrongRef();
if ( q )
{
m_currentSocialActions[ "Loved" ] = loved;
m_currentSocialActions[ "Love" ] = loved;
Tomahawk::InfoSystem::InfoStringHash trackInfo;
trackInfo["title"] = track();
@ -581,6 +593,8 @@ Query::setLoved( bool loved )
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction( q, QString( "Love" ), loved ? QString( "true" ) : QString( "false" ) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
emit socialActionsLoaded();
}
}

View File

@ -91,6 +91,8 @@ public:
void setAlbumPos( unsigned int albumpos ) { m_albumpos = albumpos; }
void setDiscNumber( unsigned int discnumber ) { m_discnumber = discnumber; }
bool equals( const Tomahawk::query_ptr& other ) const;
QVariant toVariant() const;
QString toString() const;

View File

@ -42,6 +42,7 @@ ScriptResolver::ScriptResolver( const QString& exe )
, m_ready( false )
, m_stopped( true )
, m_configSent( false )
, m_deleting( false )
, m_error( Tomahawk::ExternalResolver::NoError )
{
tLog() << Q_FUNC_INFO << "Created script resolver:" << exe;
@ -62,15 +63,13 @@ ScriptResolver::ScriptResolver( const QString& exe )
ScriptResolver::~ScriptResolver()
{
disconnect( &m_proc, SIGNAL( finished( int, QProcess::ExitStatus ) ), this, SLOT( cmdExited( int, QProcess::ExitStatus ) ) );
m_deleting = true;
QVariantMap msg;
msg[ "_msgtype" ] = "quit";
sendMessage( msg );
// QEventLoop::processEvents(QEventLoop::ExcludeUserInputEvents);
// m_proc.terminate();
m_proc.waitForFinished( 1000 );
m_proc.waitForFinished( 1000 ); // might call handleMsg
Tomahawk::Pipeline::instance()->removeResolver( this );
@ -221,6 +220,10 @@ ScriptResolver::handleMsg( const QByteArray& msg )
{
// qDebug() << Q_FUNC_INFO << msg.size() << QString::fromAscii( msg );
// Might be called from waitForFinished() in ~ScriptResolver, no database in that case, abort.
if ( m_deleting )
return;
bool ok;
QVariant v = m_parser.parse( msg, &ok );
if ( !ok || v.type() != QVariant::Map )

View File

@ -88,7 +88,7 @@ private:
quint32 m_msgsize;
QByteArray m_msg;
bool m_ready, m_stopped, m_configSent;
bool m_ready, m_stopped, m_configSent, m_deleting;
ExternalResolver::ErrorState m_error;
QJson::Parser m_parser;

View File

@ -0,0 +1,89 @@
/* This file is part of Clementine.
Copyright 2011, David Sansome <me@davidsansome.com>
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "closure.h"
namespace _detail {
Closure::Closure(QObject* sender,
const char* signal,
QObject* receiver,
const char* slot,
const ClosureArgumentWrapper* val0,
const ClosureArgumentWrapper* val1,
const ClosureArgumentWrapper* val2,
const ClosureArgumentWrapper* val3)
: QObject(receiver),
callback_(NULL),
val0_(val0),
val1_(val1),
val2_(val2),
val3_(val3) {
const QMetaObject* meta_receiver = receiver->metaObject();
QByteArray normalised_slot = QMetaObject::normalizedSignature(slot + 1);
const int index = meta_receiver->indexOfSlot(normalised_slot.constData());
Q_ASSERT(index != -1);
slot_ = meta_receiver->method(index);
Connect(sender, signal);
}
Closure::Closure(QObject* sender,
const char* signal,
std::tr1::function<void()> callback)
: callback_(callback) {
Connect(sender, signal);
}
Closure::~Closure() {
}
void Closure::Connect(QObject* sender, const char* signal) {
bool success = connect(sender, signal, SLOT(Invoked()));
Q_ASSERT(success);
success = connect(sender, SIGNAL(destroyed()), SLOT(Cleanup()));
Q_ASSERT(success);
Q_UNUSED(success);
}
void Closure::Invoked() {
if (callback_) {
callback_();
} else {
slot_.invoke(
parent(),
val0_ ? val0_->arg() : QGenericArgument(),
val1_ ? val1_->arg() : QGenericArgument(),
val2_ ? val2_->arg() : QGenericArgument(),
val3_ ? val3_->arg() : QGenericArgument());
}
deleteLater();
}
void Closure::Cleanup() {
disconnect();
deleteLater();
}
} // namespace _detail
_detail::Closure* NewClosure(
QObject* sender, const char* signal,
QObject* receiver, const char* slot) {
return new _detail::Closure(sender, signal, receiver, slot);
}

View File

@ -0,0 +1,225 @@
/* This file is part of Clementine.
Copyright 2011, David Sansome <me@davidsansome.com>
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CLOSURE_H
#define CLOSURE_H
#include <tr1/functional>
#include <QMetaMethod>
#include <QObject>
#include <QSharedPointer>
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
namespace _detail {
class ClosureArgumentWrapper {
public:
virtual ~ClosureArgumentWrapper() {}
virtual QGenericArgument arg() const = 0;
};
template<typename T>
class ClosureArgument : public ClosureArgumentWrapper {
public:
explicit ClosureArgument(const T& data) : data_(data) {}
virtual QGenericArgument arg() const {
return Q_ARG(T, data_);
}
private:
T data_;
};
class Closure : public QObject, boost::noncopyable {
Q_OBJECT
public:
Closure(QObject* sender, const char* signal,
QObject* receiver, const char* slot,
const ClosureArgumentWrapper* val0 = 0,
const ClosureArgumentWrapper* val1 = 0,
const ClosureArgumentWrapper* val2 = 0,
const ClosureArgumentWrapper* val3 = 0);
Closure(QObject* sender, const char* signal,
std::tr1::function<void()> callback);
virtual ~Closure();
private slots:
void Invoked();
void Cleanup();
private:
void Connect(QObject* sender, const char* signal);
QMetaMethod slot_;
std::tr1::function<void()> callback_;
boost::scoped_ptr<const ClosureArgumentWrapper> val0_;
boost::scoped_ptr<const ClosureArgumentWrapper> val1_;
boost::scoped_ptr<const ClosureArgumentWrapper> val2_;
boost::scoped_ptr<const ClosureArgumentWrapper> val3_;
};
class SharedPointerWrapper {
public:
virtual ~SharedPointerWrapper() {}
virtual QObject* data() const = 0;
};
template<typename T>
class SharedPointer : public SharedPointerWrapper {
public:
explicit SharedPointer(QSharedPointer<T> ptr)
: ptr_(ptr) {
}
QObject* data() const {
return ptr_.data();
}
private:
QSharedPointer<T> ptr_;
};
// For use with a QSharedPointer as a sender.
class SharedClosure : public Closure {
Q_OBJECT
public:
SharedClosure(SharedPointerWrapper* sender, const char* signal,
QObject* receiver, const char* slot,
const ClosureArgumentWrapper* val0 = 0,
const ClosureArgumentWrapper* val1 = 0,
const ClosureArgumentWrapper* val2 = 0,
const ClosureArgumentWrapper* val3 = 0)
: Closure(sender->data(), signal,
receiver, slot,
val0, val1, val2, val3),
shared_sender_(sender) {
}
private:
boost::scoped_ptr<SharedPointerWrapper> shared_sender_;
};
} // namespace _detail
#define C_ARG(type, data) new _detail::ClosureArgument<type>(data)
_detail::Closure* NewClosure(
QObject* sender,
const char* signal,
QObject* receiver,
const char* slot);
template <typename T>
_detail::Closure* NewClosure(
QObject* sender,
const char* signal,
QObject* receiver,
const char* slot,
const T& val0) {
return new _detail::Closure(
sender, signal, receiver, slot,
C_ARG(T, val0));
}
template <typename T0, typename T1>
_detail::Closure* NewClosure(
QObject* sender,
const char* signal,
QObject* receiver,
const char* slot,
const T0& val0,
const T1& val1) {
return new _detail::Closure(
sender, signal, receiver, slot,
C_ARG(T0, val0), C_ARG(T1, val1));
}
template <typename T0, typename T1, typename T2>
_detail::Closure* NewClosure(
QObject* sender,
const char* signal,
QObject* receiver,
const char* slot,
const T0& val0,
const T1& val1,
const T2& val2) {
return new _detail::Closure(
sender, signal, receiver, slot,
C_ARG(T0, val0), C_ARG(T1, val1), C_ARG(T2, val2));
}
template <typename T0, typename T1, typename T2, typename T3>
_detail::Closure* NewClosure(
QObject* sender,
const char* signal,
QObject* receiver,
const char* slot,
const T0& val0,
const T1& val1,
const T2& val2,
const T3& val3) {
return new _detail::Closure(
sender, signal, receiver, slot,
C_ARG(T0, val0), C_ARG(T1, val1), C_ARG(T2, val2), C_ARG(T3, val3));
}
template <typename TP>
_detail::Closure* NewClosure(
QSharedPointer<TP> sender,
const char* signal,
QObject* receiver,
const char* slot) {
return new _detail::SharedClosure(
new _detail::SharedPointer<TP>(sender), signal, receiver, slot);
}
template <typename TP, typename T0>
_detail::Closure* NewClosure(
QSharedPointer<TP> sender,
const char* signal,
QObject* receiver,
const char* slot,
const T0& val0) {
return new _detail::SharedClosure(
new _detail::SharedPointer<TP>(sender), signal, receiver, slot,
C_ARG(T0, val0));
}
template <typename TP, typename T0, typename T1>
_detail::Closure* NewClosure(
QSharedPointer<TP> sender,
const char* signal,
QObject* receiver,
const char* slot,
const T0& val0,
const T1& val1) {
return new _detail::SharedClosure(
new _detail::SharedPointer<TP>(sender), signal, receiver, slot,
C_ARG(T0, val0), C_ARG(T1, val1));
}
#endif // CLOSURE_H

View File

@ -316,6 +316,7 @@ QList< QNetworkProxy >
NetworkProxyFactory::queryProxy( const QNetworkProxyQuery& query )
{
//tDebug() << Q_FUNC_INFO << "query hostname is " << query.peerHostName();
QList< QNetworkProxy > proxies;
QString hostname = query.peerHostName();
s_noProxyHostsMutex.lock();

View File

@ -123,7 +123,11 @@ XSPFLoader::reportError()
{
emit error( FetchError );
#ifndef ENABLE_HEADLESS
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( errorToString( FetchError) ) );
const QString errorMsg = errorToString( FetchError);
if ( !m_errorTitle.isEmpty() )
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( QString( "%1: %2" ).arg( m_errorTitle ).arg( errorMsg ) ) );
else
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( errorMsg ) );
#endif
deleteLater();
}

View File

@ -49,6 +49,7 @@ public:
void setOverrideTitle( const QString& newTitle );
void setAutoResolveTracks( bool autoResolve ) { m_autoResolve = autoResolve; }
void setAutoDelete( bool autoDelete ) { m_autoDelete = autoDelete; }
void setErrorTitle( const QString& error ) { m_errorTitle = error; }
static QString errorToString( XSPFErrorCode error );
@ -73,7 +74,7 @@ private:
bool m_autoCreate, m_autoUpdate, m_autoResolve, m_autoDelete;
QString m_NS,m_overrideTitle;
QList< Tomahawk::query_ptr > m_entries;
QString m_title, m_info, m_creator;
QString m_title, m_info, m_creator, m_errorTitle;
QUrl m_url;
QByteArray m_body;

View File

@ -43,6 +43,7 @@
#include "customplaylistview.h"
#include "PlaylistLargeItemDelegate.h"
#include "RecentlyPlayedModel.h"
#include "dynamic/widgets/DynamicWidget.h"
#include "widgets/welcomewidget.h"
@ -75,6 +76,7 @@ ViewManager::ViewManager( QObject* parent )
, m_welcomeWidget( new WelcomeWidget() )
, m_whatsHotWidget( new WhatsHotWidget() )
, m_topLovedWidget( 0 )
, m_recentPlaysWidget( 0 )
, m_currentMode( PlaylistInterface::Tree )
, m_loaded( false )
{
@ -114,7 +116,7 @@ ViewManager::ViewManager( QObject* parent )
connect( &m_filterTimer, SIGNAL( timeout() ), SLOT( applyFilter() ) );
connect( m_infobar, SIGNAL( filterTextChanged( QString ) ), SLOT( setFilter( QString ) ) );
connect( m_infobar, SIGNAL( autoUpdateChanged( int ) ), SLOT( autoUpdateChanged( int ) ) );
connect( m_infobar, SIGNAL( autoUpdateChanged( bool ) ), SLOT( autoUpdateChanged( bool ) ) );
connect( this, SIGNAL( tomahawkLoaded() ), m_whatsHotWidget, SLOT( fetchData() ) );
connect( this, SIGNAL( tomahawkLoaded() ), m_welcomeWidget, SLOT( loadData() ) );
@ -131,6 +133,7 @@ ViewManager::~ViewManager()
delete m_whatsHotWidget;
delete m_welcomeWidget;
delete m_topLovedWidget;
delete m_recentPlaysWidget;
delete m_contextWidget;
delete m_widget;
}
@ -441,7 +444,7 @@ ViewManager::showTopLovedPage()
if ( !m_topLovedWidget )
{
CustomPlaylistView* view = new CustomPlaylistView( CustomPlaylistView::TopLovedTracks, source_ptr(), m_widget );
view->setItemDelegate( new PlaylistLargeItemDelegate( view, view->proxyModel() ) );
view->setItemDelegate( new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::LovedTracks, view, view->proxyModel() ) );
m_topLovedWidget = view;
}
@ -450,6 +453,28 @@ ViewManager::showTopLovedPage()
}
Tomahawk::ViewPage*
ViewManager::showRecentPlaysPage()
{
if ( !m_recentPlaysWidget )
{
PlaylistView* pv = new PlaylistView( m_widget );
pv->setFrameShape( QFrame::NoFrame );
pv->setAttribute( Qt::WA_MacShowFocusRect, 0 );
RecentlyPlayedModel* raModel = new RecentlyPlayedModel( source_ptr(), pv );
raModel->setStyle( TrackModel::Large );
pv->setItemDelegate( new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::RecentlyPlayed, pv, pv->proxyModel() ) );
pv->setPlaylistModel( raModel );
m_recentPlaysWidget = pv;
}
return show( m_recentPlaysWidget );
}
void
ViewManager::setTableMode()
{
@ -544,9 +569,9 @@ ViewManager::applyFilter()
void
ViewManager::autoUpdateChanged( int state )
ViewManager::autoUpdateChanged( bool toggled )
{
currentPage()->setAutoUpdate( state == Qt::Checked );
currentPage()->setAutoUpdate( toggled );
}

View File

@ -85,13 +85,14 @@ public:
Tomahawk::playlistinterface_ptr currentPlaylistInterface() const;
Tomahawk::ViewPage* currentPage() const;
Tomahawk::ViewPage* pageForInterface( Tomahawk::playlistinterface_ptr interface ) const;
Tomahawk::ViewPage* pageForInterface( Tomahawk::playlistinterface_ptr plInterface ) const;
Tomahawk::ViewPage* show( Tomahawk::ViewPage* page );
Tomahawk::ViewPage* welcomeWidget() const { return m_welcomeWidget; }
Tomahawk::ViewPage* whatsHotWidget() const { return m_whatsHotWidget; }
Tomahawk::ViewPage* topLovedWidget() const { return m_topLovedWidget; }
Tomahawk::ViewPage* recentPlaysWidget() const { return m_recentPlaysWidget; }
ArtistView* superCollectionView() const { return m_superCollectionView; }
/// Get the view page for the given item. Not pretty...
@ -140,6 +141,7 @@ public slots:
Tomahawk::ViewPage* showWelcomePage();
Tomahawk::ViewPage* showWhatsHotPage();
Tomahawk::ViewPage* showTopLovedPage();
Tomahawk::ViewPage* showRecentPlaysPage();
void showCurrentTrack();
// Returns the shown viewpage
@ -175,7 +177,7 @@ private slots:
void setFilter( const QString& filter );
void applyFilter();
void autoUpdateChanged( int );
void autoUpdateChanged( bool );
void onWidgetDestroyed( QWidget* widget );
@ -186,9 +188,9 @@ private:
void saveCurrentPlaylistSettings();
void loadCurrentPlaylistSettings();
Tomahawk::playlist_ptr playlistForInterface( Tomahawk::playlistinterface_ptr interface ) const;
Tomahawk::dynplaylist_ptr dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr interface ) const;
Tomahawk::collection_ptr collectionForInterface( Tomahawk::playlistinterface_ptr interface ) const;
Tomahawk::playlist_ptr playlistForInterface( Tomahawk::playlistinterface_ptr plInterface ) const;
Tomahawk::dynplaylist_ptr dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr plInterface ) const;
Tomahawk::collection_ptr collectionForInterface( Tomahawk::playlistinterface_ptr plInterface ) const;
QWidget* m_widget;
InfoBar* m_infobar;
@ -204,6 +206,7 @@ private:
WelcomeWidget* m_welcomeWidget;
WhatsHotWidget* m_whatsHotWidget;
Tomahawk::ViewPage* m_topLovedWidget;
Tomahawk::ViewPage* m_recentPlaysWidget;
QList< Tomahawk::collection_ptr > m_superCollections;

View File

@ -0,0 +1,114 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011 - 2012, 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 "FadingPixmap.h"
#include <QPainter>
#define ANIMATION_TIME 1000
FadingPixmap::FadingPixmap( QWidget* parent )
: QLabel( parent )
, m_fadePct( 100 )
{
// setCursor( Qt::PointingHandCursor );
m_timeLine = new QTimeLine( ANIMATION_TIME, this );
m_timeLine->setUpdateInterval( 20 );
m_timeLine->setEasingCurve( QEasingCurve::Linear );
connect( m_timeLine, SIGNAL( frameChanged( int ) ), SLOT( onAnimationStep( int ) ) );
connect( m_timeLine, SIGNAL( finished() ), SLOT( onAnimationFinished() ) );
}
FadingPixmap::~FadingPixmap()
{
}
void
FadingPixmap::onAnimationStep( int frame )
{
m_fadePct = (float)frame / 10.0;
repaint();
}
void
FadingPixmap::onAnimationFinished()
{
m_oldPixmap = QPixmap();
repaint();
if ( m_pixmapQueue.count() )
{
setPixmap( m_pixmapQueue.takeFirst() );
}
}
void
FadingPixmap::setPixmap( const QPixmap& pixmap, bool clearQueue )
{
if ( m_timeLine->state() == QTimeLine::Running )
{
if ( clearQueue )
m_pixmapQueue.clear();
m_pixmapQueue << pixmap;
return;
}
m_oldPixmap = m_pixmap;
m_pixmap = pixmap;
m_timeLine->setFrameRange( 0, 1000 );
m_timeLine->setDirection( QTimeLine::Forward );
m_timeLine->start();
}
void
FadingPixmap::mouseReleaseEvent( QMouseEvent* event )
{
QFrame::mouseReleaseEvent( event );
emit clicked();
}
void
FadingPixmap::paintEvent( QPaintEvent* event )
{
Q_UNUSED( event );
QPainter p( this );
QRect r = contentsRect();
p.save();
p.setRenderHint( QPainter::Antialiasing );
p.setOpacity( float( 100.0 - m_fadePct ) / 100.0 );
p.drawPixmap( r, m_oldPixmap );
p.setOpacity( float( m_fadePct ) / 100.0 );
p.drawPixmap( r, m_pixmap );
p.restore();
}

View File

@ -0,0 +1,64 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011 - 2012, 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 FADINGPIXMAP_H
#define FADINGPIXMAP_H
#include <QLabel>
#include <QPaintEvent>
#include <QTimeLine>
#include "dllmacro.h"
/**
* \class FadingPixmap
* \brief Fades to the new image when calling setPixmap.
*/
class DLLEXPORT FadingPixmap : public QLabel
{
Q_OBJECT
public:
FadingPixmap( QWidget* parent = 0 );
virtual ~FadingPixmap();
public slots:
virtual void setPixmap( const QPixmap& pixmap, bool clearQueue = true );
signals:
void clicked();
protected:
virtual void paintEvent( QPaintEvent* );
void mouseReleaseEvent( QMouseEvent* event );
private slots:
void onAnimationStep( int frame );
void onAnimationFinished();
private:
QPixmap m_pixmap;
QPixmap m_oldPixmap;
QList<QPixmap> m_pixmapQueue;
QTimeLine* m_timeLine;
int m_fadePct;
};
#endif

View File

@ -2,6 +2,7 @@
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.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
@ -232,7 +233,7 @@ AlbumInfoWidget::loadAlbums( bool autoRefetch )
artistInfo["artist"] = m_album->artist()->name();
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.customData["refetch"] = QVariant( autoRefetch );
requestData.customData["refetch"] = autoRefetch;
requestData.caller = m_infoId;
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
requestData.type = Tomahawk::InfoSystem::InfoArtistReleases;
@ -309,7 +310,7 @@ AlbumInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDa
tDebug() << "Adding" << al.count() << "albums";
gotAlbums( al );
}
else if ( requestData.customData[ "refetch" ].toInt() > 0 )
else if ( requestData.customData[ "refetch" ].toBool() )
{
tDebug() << "Auto refetching";
m_buttonAlbums->setChecked( false );

View File

@ -2,6 +2,7 @@
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.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

View File

@ -80,7 +80,7 @@ void
QueryLabel::init()
{
m_contextMenu = new ContextMenu( this );
m_contextMenu->setSupportedActions( ContextMenu::ActionQueue | ContextMenu::ActionCopyLink );
m_contextMenu->setSupportedActions( ContextMenu::ActionQueue | ContextMenu::ActionCopyLink | ContextMenu::ActionStopAfter | ContextMenu::ActionLove );
m_hoverType = None;
setContentsMargins( 0, 0, 0, 0 );

View File

@ -22,6 +22,7 @@
#include "thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.h"
#include "ubuntuunityhack.h"
#include "tomahawksettings.h"
#include "config.h"
#include <QTranslator>
@ -123,8 +124,11 @@ main( int argc, char *argv[] )
new TomahawkSettingsGui( &a );
#endif
#ifndef ENABLE_HEADLESS
new BreakPad( QDir::tempPath(), TomahawkSettings::instance()->crashReporterEnabled() );
#ifndef ENABLE_HEADLESSs
#ifdef WITH_BREAKPAD
new BreakPad( QDir::tempPath(), TomahawkSettings::instance()->crashReporterEnabled() );
#endif
#endif
KDSingleApplicationGuard guard( &a, KDSingleApplicationGuard::AutoKillOtherInstances );

View File

@ -296,6 +296,7 @@ CategoryAddItem::playlistToRenameLoaded()
QTimer::singleShot( 400, APP->mainWindow()->sourceTreeView(), SLOT( renamePlaylist() ) );
disconnect( pl, SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( playlistToRenameLoaded() ) );
disconnect( pl, SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistToRenameLoaded() ) );
}
@ -307,8 +308,7 @@ CategoryAddItem::parsedDroppedTracks( const QList< query_ptr >& tracks )
playlist_ptr newpl = Playlist::create( SourceList::instance()->getLocal(), uuid(), "New Playlist", "", SourceList::instance()->getLocal()->friendlyName(), false, tracks );
ViewManager::instance()->show( newpl );
// Give a shot to try to rename it. The playlist has to be created first. ugly.
QTimer::singleShot( 300, APP->mainWindow()->sourceTreeView(), SLOT( renamePlaylist() ) );
connect( newpl.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistToRenameLoaded() ) );
} else if( m_categoryType == SourcesModel::StationsCategory ) {
// seed the playlist with these song or artist filters
QString name;

View File

@ -24,6 +24,7 @@
#include "query.h"
#include "viewmanager.h"
#include "playlist/dynamic/GeneratorInterface.h"
#include "playlist/playlistview.h"
#include "categoryitems.h"
#include "sourceitem.h"
#include "utils/tomahawkutils.h"
@ -136,6 +137,17 @@ PlaylistItem::activate()
}
void
PlaylistItem::doubleClicked()
{
ViewPage* p = ViewManager::instance()->currentPage();
if ( PlaylistView* view = dynamic_cast< PlaylistView* >( p ) )
{
view->startPlayingFromStart();
}
}
void
PlaylistItem::setLoaded( bool loaded )
{

View File

@ -31,7 +31,6 @@ public:
virtual QString text() const;
virtual Tomahawk::playlist_ptr playlist() const;
virtual Qt::ItemFlags flags() const;
virtual void activate();
virtual bool willAcceptDrag( const QMimeData* data ) const;
virtual DropTypes supportedDropTypes( const QMimeData* data ) const;
virtual bool dropMimeData( const QMimeData* data, Qt::DropAction action );
@ -43,6 +42,10 @@ public:
virtual SourceTreeItem* activateCurrent();
public slots:
virtual void activate();
virtual void doubleClicked();
protected:
void setLoaded( bool loaded );

View File

@ -504,7 +504,7 @@ SourceItem::lovedTracksClicked()
if ( !m_lovedTracksPage )
{
CustomPlaylistView* view = new CustomPlaylistView( m_source.isNull() ? CustomPlaylistView::TopLovedTracks : CustomPlaylistView::SourceLovedTracks, m_source, ViewManager::instance()->widget() );
view->setItemDelegate( new PlaylistLargeItemDelegate( view, view->proxyModel() ) );
view->setItemDelegate( new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::LovedTracks, view, view->proxyModel() ) );
m_lovedTracksPage = view;
}
@ -533,7 +533,7 @@ SourceItem::latestAdditionsClicked()
RecentlyAddedModel* raModel = new RecentlyAddedModel( m_source, cv );
raModel->setStyle( TrackModel::Large );
cv->setItemDelegate( new PlaylistLargeItemDelegate( cv, cv->proxyModel() ) );
cv->setItemDelegate( new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::LatestAdditions, cv, cv->proxyModel() ) );
cv->setTrackModel( raModel );
cv->sortByColumn( TrackModel::Age, Qt::DescendingOrder );
@ -564,7 +564,7 @@ SourceItem::recentPlaysClicked()
RecentlyPlayedModel* raModel = new RecentlyPlayedModel( m_source, pv );
raModel->setStyle( TrackModel::Large );
pv->setItemDelegate( new PlaylistLargeItemDelegate( pv, pv->proxyModel() ) );
pv->setItemDelegate( new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::RecentlyPlayed, pv, pv->proxyModel() ) );
pv->setPlaylistModel( raModel );
m_recentPlaysPage = pv;

View File

@ -78,6 +78,7 @@ public:
public slots:
virtual void activate() {}
virtual void doubleClicked() {}
signals:
void updated();

View File

@ -44,6 +44,7 @@
SourceDelegate::SourceDelegate( QAbstractItemView* parent )
: QStyledItemDelegate( parent )
, m_parent( parent )
, m_lastClicked( -1 )
{
m_dropTypeMap.insert( 0, SourceTreeItem::DropTypeThisTrack );
m_dropTypeMap.insert( 1, SourceTreeItem::DropTypeThisAlbum );
@ -632,7 +633,27 @@ SourceDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QSt
// a mouse press event. Since we want to swallow click events when they are on headphones other action items, here wemake sure we only
// emit if we really want to
if ( event->type() == QEvent::MouseButtonRelease )
emit clicked( index );
{
if ( m_lastClicked == -1 )
{
m_lastClicked = QDateTime::currentMSecsSinceEpoch();
emit clicked( index );
}
else
{
qint64 elapsed = QDateTime::currentMSecsSinceEpoch() - m_lastClicked;
if ( elapsed < QApplication::doubleClickInterval() )
{
m_lastClicked = -1;
emit doubleClicked( index );
} else
{
m_lastClicked = QDateTime::currentMSecsSinceEpoch();
emit clicked( index );
}
}
}
return QStyledItemDelegate::editorEvent ( event, model, option, index );
}

View File

@ -44,6 +44,7 @@ public:
signals:
void clicked( const QModelIndex& idx );
void doubleClicked( const QModelIndex& idx );
void latchOn( const Tomahawk::source_ptr& idx );
void latchOff( const Tomahawk::source_ptr& idx );
void toggleRealtimeLatch( const Tomahawk::source_ptr& idx, bool realtime );
@ -73,6 +74,7 @@ private:
mutable SourceTreeItem::DropType m_hoveredDropType; // Hack to keep easily track of the current highlighted DropType in paint()
QMap< QModelIndex, AnimationHelper* > m_expandedMap;
QPixmap m_headphonesOn, m_headphonesOff, m_realtimeLocked, m_realtimeUnlocked, m_nowPlayingSpeaker, m_nowPlayingSpeakerDark;
qint64 m_lastClicked;
QMap< int, SourceTreeItem::DropType > m_dropTypeMap;
QMap< int, QString > m_dropTypeTextMap;

View File

@ -263,13 +263,18 @@ SourcesModel::flags( const QModelIndex& index ) const
void
SourcesModel::appendGroups()
{
beginInsertRows( QModelIndex(), rowCount(), rowCount() + 2 );
beginInsertRows( QModelIndex(), rowCount(), rowCount() + 3 );
GroupItem* browse = new GroupItem( this, m_rootItem, tr( "Browse" ), 0 );
new HistoryItem( this, m_rootItem, tr( "Search History" ), 1 );
// new SourceTreeItem( this, m_rootItem, SourcesModel::Divider, 2 );
m_myMusicGroup = new GroupItem( this, m_rootItem, tr( "My Music" ), 3 );
GenericPageItem* dashboard = new GenericPageItem( this, browse, tr( "Dashboard" ), QIcon( RESPATH "images/dashboard.png" ),
boost::bind( &ViewManager::showWelcomePage, ViewManager::instance() ),
boost::bind( &ViewManager::welcomeWidget, ViewManager::instance() ) );
dashboard->setSortValue( 0 );
// super collection
GenericPageItem* sc = new GenericPageItem( this, browse, tr( "SuperCollection" ), QIcon( RESPATH "images/supercollection.png" ),
boost::bind( &ViewManager::showSuperCollection, ViewManager::instance() ),
@ -282,15 +287,15 @@ SourcesModel::appendGroups()
boost::bind( &ViewManager::topLovedWidget, ViewManager::instance() ) );
loved->setSortValue( 2 );
GenericPageItem* recent = new GenericPageItem( this, browse, tr( "Dashboard" ), QIcon( RESPATH "images/dashboard.png" ),
boost::bind( &ViewManager::showWelcomePage, ViewManager::instance() ),
boost::bind( &ViewManager::welcomeWidget, ViewManager::instance() ) );
recent->setSortValue( 0 );
GenericPageItem* recent = new GenericPageItem( this, browse, tr( "Recently Played" ), QIcon( RESPATH "images/recently-played.png" ),
boost::bind( &ViewManager::showRecentPlaysPage, ViewManager::instance() ),
boost::bind( &ViewManager::recentPlaysWidget, ViewManager::instance() ) );
recent->setSortValue( 3 );
GenericPageItem* hot = new GenericPageItem( this, browse, tr( "Charts" ), QIcon( RESPATH "images/charts.png" ),
boost::bind( &ViewManager::showWhatsHotPage, ViewManager::instance() ),
boost::bind( &ViewManager::whatsHotWidget, ViewManager::instance() ) );
hot->setSortValue( 3 );
hot->setSortValue( 4 );
m_collectionsGroup = new GroupItem( this, m_rootItem, tr( "Friends" ), 4 );

View File

@ -79,6 +79,7 @@ SourceTreeView::SourceTreeView( QWidget* parent )
sortByColumn( 0, Qt::AscendingOrder );
setVerticalScrollMode( QTreeView::ScrollPerPixel );
setMouseTracking( true );
setEditTriggers( NoEditTriggers );
// TODO animation conflicts with the expanding-playlists-when-collection-is-null
// so investigate
@ -89,6 +90,7 @@ SourceTreeView::SourceTreeView( QWidget* parent )
connect( m_delegate, SIGNAL( latchOff( Tomahawk::source_ptr ) ), SLOT( latchOff( Tomahawk::source_ptr ) ) );
connect( m_delegate, SIGNAL( toggleRealtimeLatch( Tomahawk::source_ptr, bool ) ), m_latchManager, SLOT( latchModeChangeRequest( Tomahawk::source_ptr,bool ) ) );
connect( m_delegate, SIGNAL( clicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) );
connect( m_delegate, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemDoubleClicked( QModelIndex ) ) );
setItemDelegate( m_delegate );
@ -97,7 +99,7 @@ SourceTreeView::SourceTreeView( QWidget* parent )
m_model = new SourcesModel( this );
m_proxyModel = new SourcesProxyModel( m_model, this );
connect( m_proxyModel, SIGNAL( selectRequest( QPersistentModelIndex ) ), SLOT( selectRequest( QPersistentModelIndex ) ) );
connect( m_proxyModel, SIGNAL( selectRequest( QPersistentModelIndex ) ), SLOT( selectRequest( QPersistentModelIndex ) ), Qt::QueuedConnection );
connect( m_proxyModel, SIGNAL( expandRequest( QPersistentModelIndex ) ), SLOT( expandRequest( QPersistentModelIndex ) ) );
connect( m_proxyModel, SIGNAL( toggleExpandRequest( QPersistentModelIndex ) ), SLOT( toggleExpandRequest( QPersistentModelIndex ) ) );
@ -231,6 +233,17 @@ SourceTreeView::onItemActivated( const QModelIndex& index )
}
void
SourceTreeView::onItemDoubleClicked( const QModelIndex& idx )
{
if ( !selectionModel()->selectedIndexes().contains( idx ) )
onItemActivated( idx );
SourceTreeItem* item = itemFromIndex< SourceTreeItem >( idx );
item->doubleClicked();
}
void
SourceTreeView::onItemExpanded( const QModelIndex& idx )
{

View File

@ -67,6 +67,7 @@ private slots:
void selectRequest( const QPersistentModelIndex& idx );
void expandRequest( const QPersistentModelIndex& idx );
void toggleExpandRequest( const QPersistentModelIndex& idx );
void onItemDoubleClicked( const QModelIndex& idx );
void loadPlaylist();
void deletePlaylist( const QModelIndex& = QModelIndex() );

View File

@ -393,7 +393,7 @@
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Playdar HTTP API</string>
<string>Allow web browsers to interact with Tomahawk</string>
</property>
<property name="checked">
<bool>true</bool>

View File

@ -270,6 +270,7 @@ TomahawkApp::init()
{
initHTTP();
}
connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( initHTTP() ) );
#ifndef ENABLE_HEADLESS
if ( !s->hasScannerPaths() )
@ -314,6 +315,11 @@ TomahawkApp::~TomahawkApp()
{
tLog() << "Shutting down Tomahawk...";
if ( !m_session.isNull() )
delete m_session.data();
if ( !m_connector.isNull() )
delete m_connector.data();
Pipeline::instance()->stop();
if ( !m_servent.isNull() )
@ -475,15 +481,43 @@ TomahawkApp::initDatabase()
void
TomahawkApp::initHTTP()
{
m_session.setPort( 60210 ); //TODO config
m_session.setListenInterface( QHostAddress::LocalHost );
m_session.setConnector( &m_connector );
if ( !TomahawkSettings::instance()->httpEnabled() )
{
tLog() << "Stopping HTTPd, not enabled";
if ( !m_session.isNull() )
delete m_session.data();
if ( !m_connector.isNull() )
delete m_connector.data();
return;
}
Api_v1* api = new Api_v1( &m_session );
m_session.setStaticContentService( api );
if ( m_session )
{
tLog() << "HTTPd session already exists, returning";
return;
}
tLog() << "Starting HTTPd on" << m_session.listenInterface().toString() << m_session.port();
m_session.start();
m_session = QWeakPointer< QxtHttpSessionManager >( new QxtHttpSessionManager() );
m_connector = QWeakPointer< QxtHttpServerConnector >( new QxtHttpServerConnector );
if ( m_session.isNull() || m_connector.isNull() )
{
if ( !m_session.isNull() )
delete m_session.data();
if ( !m_connector.isNull() )
delete m_connector.data();
tLog() << "Failed to start HTTPd, could not create object";
return;
}
m_session.data()->setPort( 60210 ); //TODO config
m_session.data()->setListenInterface( QHostAddress::LocalHost );
m_session.data()->setConnector( m_connector.data() );
Api_v1* api = new Api_v1( m_session.data() );
m_session.data()->setStaticContentService( api );
tLog() << "Starting HTTPd on" << m_session.data()->listenInterface().toString() << m_session.data()->port();
m_session.data()->start();
}

View File

@ -108,6 +108,7 @@ public slots:
private slots:
void initServent();
void initSIP();
void initHTTP();
void spotifyApiCheckFinished();
@ -121,8 +122,6 @@ private:
void initLocalCollection();
void initPipeline();
void initHTTP();
QWeakPointer<Database> m_database;
QWeakPointer<ScanManager> m_scanManager;
QWeakPointer<AudioEngine> m_audioEngine;
@ -143,8 +142,8 @@ private:
bool m_headless, m_loaded;
QxtHttpServerConnector m_connector;
QxtHttpSessionManager m_session;
QWeakPointer< QxtHttpServerConnector > m_connector;
QWeakPointer< QxtHttpSessionManager > m_session;
};
Q_DECLARE_METATYPE( QPersistentModelIndex )

View File

@ -33,7 +33,6 @@ handleAccountAdded( Tomahawk::Accounts::Account* account, bool added )
if ( added )
{
account->setEnabled( true );
account->setAutoConnect( true );
account->saveConfig();
TomahawkSettings::instance()->addAccount( account->accountId() );

View File

@ -1,6 +1,8 @@
ADD_SUBDIRECTORY( qxt )
ADD_SUBDIRECTORY( liblastfm2 )
ADD_SUBDIRECTORY( breakpad )
IF( WITH_BREAKPAD )
ADD_SUBDIRECTORY( breakpad )
ENDIF()
IF( APPLE )
ADD_SUBDIRECTORY( SPMediaKeyTap )
ENDIF()

View File

@ -575,9 +575,14 @@ void QxtHttpSessionManager::processEvents()
*/
void QxtHttpSessionManager::chunkReadyRead(int requestID)
{
if (!connector()) return;
const QSharedPointer<QIODevice>& dataSource = connector()->getRequestDataSource( requestID );
if (!dataSource->bytesAvailable()) return;
QIODevice* device = connector()->getRequestConnection(requestID);
if (!device) return;
if (!device->bytesToWrite() || qxt_d().connectionState[device].readyRead == false)
{
qxt_d().connectionState[device].readyRead = true;
@ -590,6 +595,9 @@ void QxtHttpSessionManager::chunkReadyRead(int requestID)
*/
void QxtHttpSessionManager::sendNextChunk(int requestID)
{
if ( !connector() )
return;
const QSharedPointer<QIODevice>& dataSource = connector()->getRequestDataSource( requestID );
QIODevice* device = connector()->getRequestConnection(requestID);
QxtHttpSessionManagerPrivate::ConnectionState& state = qxt_d().connectionState[device];