1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-03-20 07:49:42 +01:00

Refactor latching into it's own manager for easier handling, and clean up some corner cases

This commit is contained in:
Leo Franchi 2011-09-28 18:58:45 -04:00
parent b83e9bbf82
commit 66581fcaa2
6 changed files with 254 additions and 122 deletions

View File

@ -33,6 +33,7 @@ set( libSources
contextmenu.cpp
dropjob.cpp
playlistinterface.cpp
LatchManager.cpp
sip/SipPlugin.cpp
sip/SipHandler.cpp
@ -246,6 +247,7 @@ set( libHeaders
contextmenu.h
dropjob.h
AtticaManager.h
LatchManager.h
artist.h
album.h

View File

@ -0,0 +1,144 @@
/* === This file is part of Tomahawk Player - <http://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
* 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 "LatchManager.h"
#include "audio/audioengine.h"
#include "database/database.h"
#include <QtCore/QStateMachine>
#include <QtCore/QState>
#include "sourcelist.h"
#include "database/databasecommand_socialaction.h"
#include "sourceplaylistinterface.h"
using namespace Tomahawk;
LatchManager::LatchManager( QObject* parent )
: QObject( parent )
, m_state( NotLatched )
{
connect( AudioEngine::instance(), SIGNAL( playlistChanged( Tomahawk::PlaylistInterface* ) ), this, SLOT( playlistChanged( Tomahawk::PlaylistInterface* ) ) );
connect( AudioEngine::instance(), SIGNAL( stopped() ), this, SLOT( playlistChanged() ) );
}
LatchManager::~LatchManager()
{
}
bool
LatchManager::isLatched( const source_ptr& src )
{
return m_state == Latched && m_latchedOnTo == src;
}
void
LatchManager::latchRequest( const source_ptr& source )
{
qDebug() << Q_FUNC_INFO;
if ( isLatched( source ) )
return;
m_state = Latching;
m_waitingForLatch = source;
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
}
void
LatchManager::playlistChanged( PlaylistInterface* )
{
// If we were latched on and changed, send the listening along stop
if ( m_latchedOnTo.isNull() )
{
if ( m_waitingForLatch.isNull() )
return; // Neither latched on nor waiting to be latched on, no-op
m_latchedOnTo = m_waitingForLatch;
m_latchedInterface = m_waitingForLatch->getPlaylistInterface();
m_waitingForLatch.clear();
m_state = Latched;
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction();
cmd->setSource( SourceList::instance()->getLocal() );
cmd->setAction( "latchOn");
cmd->setComment( m_latchedOnTo->userName() );
cmd->setTimestamp( QDateTime::currentDateTime().toTime_t() );
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
// If not, then keep waiting
return;
}
// We're current latched, and the user changed playlist, so stop
const PlaylistInterface* pi = AudioEngine::instance()->playlist();
bool listeningAlong = false;
source_ptr newSource;
if ( pi && dynamic_cast< const SourcePlaylistInterface* >( pi ) )
{
// Check if we're listening along to someone, to make sure it's not the same person
const SourcePlaylistInterface* sourcepi = dynamic_cast< const SourcePlaylistInterface* >( pi );
if ( !AudioEngine::instance()->state() == AudioEngine::Stopped )
{
listeningAlong = true;
newSource = sourcepi->source();
}
}
SourcePlaylistInterface* origsourcepi = dynamic_cast< SourcePlaylistInterface* >( m_latchedInterface.data() );
Q_ASSERT( origsourcepi );
const source_ptr source = origsourcepi->source();
// if we're currently listening along to the same source, no change
if ( listeningAlong && ( !origsourcepi->source().isNull() && origsourcepi->source()->id() == newSource->id() ) )
return;
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction();
cmd->setSource( SourceList::instance()->getLocal() );
cmd->setAction( "latchOff");
cmd->setComment( source->userName() );
cmd->setTimestamp( QDateTime::currentDateTime().toTime_t() );
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
m_latchedOnTo.clear();
m_waitingForLatch.clear();
m_latchedInterface.clear();
m_state = NotLatched;
}
void
LatchManager::catchUpRequest()
{
//it's a catch-up -- logic in audioengine should take care of it
AudioEngine::instance()->next();
}
void
LatchManager::unlatchRequest( const source_ptr& source )
{
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
AudioEngine::instance()->stop();
AudioEngine::instance()->setPlaylist( 0 );
}

View File

@ -0,0 +1,65 @@
/* === This file is part of Tomahawk Player - <http://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
* 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 LATCHMANAGER_H
#define LATCHMANAGER_H
#include "dllmacro.h"
#include "source.h"
#include <QtCore/QObject>
class QState;
class QStateMachine;
namespace Tomahawk
{
class DLLEXPORT LatchManager : public QObject
{
Q_OBJECT
public:
explicit LatchManager( QObject* parent = 0 );
virtual ~LatchManager();
bool isLatched( const source_ptr& src );
public slots:
void latchRequest( const Tomahawk::source_ptr& source );
void unlatchRequest( const Tomahawk::source_ptr& source );
void catchUpRequest();
private slots:
void playlistChanged( Tomahawk::PlaylistInterface* );
private:
enum State {
NotLatched = 0,
Latching,
Latched
};
State m_state;
source_ptr m_latchedOnTo;
source_ptr m_waitingForLatch;
playlistinterface_ptr m_latchedInterface;
};
}
#endif // LATCHMANAGER_H

View File

@ -561,7 +561,10 @@ AudioEngine::playItem( Tomahawk::PlaylistInterface* playlist, const Tomahawk::re
else if ( !m_playlist.isNull() && m_playlist.data()->retryMode() == PlaylistInterface::Retry )
{
m_waitingOnNewTrack = true;
stop();
if ( isStopped() )
sendWaitingNotification();
else
stop();
}
}

View File

@ -43,14 +43,16 @@
#include "utils/logger.h"
#include "items/genericpageitems.h"
#include "items/temporarypageitem.h"
#include <database/databasecommand_socialaction.h>
#include <database/database.h>
#include "database/databasecommand_socialaction.h"
#include "database/database.h"
#include "LatchManager.h"
using namespace Tomahawk;
SourceTreeView::SourceTreeView( QWidget* parent )
: QTreeView( parent )
, m_latchManager( new LatchManager( this ) )
, m_dragging( false )
{
setFrameShape( QFrame::NoFrame );
@ -78,8 +80,8 @@ SourceTreeView::SourceTreeView( QWidget* parent )
// setAnimated( true );
m_delegate = new SourceDelegate( this );
connect( m_delegate, SIGNAL( latchOn( Tomahawk::source_ptr ) ), this, SLOT( doLatchOn( Tomahawk::source_ptr ) ), Qt::QueuedConnection );
connect( m_delegate, SIGNAL( latchOff( Tomahawk::source_ptr ) ), this, SLOT( doLatchOff( Tomahawk::source_ptr ) ), Qt::QueuedConnection );
connect( m_delegate, SIGNAL( latchOn( Tomahawk::source_ptr ) ), this, SIGNAL( latchRequest( Tomahawk::source_ptr ) ), Qt::QueuedConnection );
connect( m_delegate, SIGNAL( latchOff( Tomahawk::source_ptr ) ), this, SIGNAL( unlatchRequest( Tomahawk::source_ptr ) ), Qt::QueuedConnection );
setItemDelegate( m_delegate );
@ -102,15 +104,15 @@ SourceTreeView::SourceTreeView( QWidget* parent )
showOfflineSources( TomahawkSettings::instance()->showOfflineSources() );
connect( AudioEngine::instance(), SIGNAL( playlistChanged( Tomahawk::PlaylistInterface* ) ), this, SLOT( playlistChanged( Tomahawk::PlaylistInterface* ) ) );
connect( AudioEngine::instance(), SIGNAL( stopped() ), this, SLOT( playlistChanged() ) );
// Light-blue sourcetree on osx
#ifdef Q_WS_MAC
setStyleSheet( "SourceTreeView:active { background: #DDE4EB; } "
"SourceTreeView { background: #EDEDED; } " );
#endif
connect( this, SIGNAL( latchRequest( Tomahawk::source_ptr ) ), m_latchManager, SLOT( latchRequest( Tomahawk::source_ptr ) ) );
connect( this, SIGNAL( unlatchRequest( Tomahawk::source_ptr ) ), m_latchManager, SLOT( unlatchRequest( Tomahawk::source_ptr ) ) );
connect( this, SIGNAL( catchUpRequest() ), m_latchManager, SLOT( catchUpRequest() ) );
}
SourceTreeView::~SourceTreeView()
@ -144,18 +146,21 @@ SourceTreeView::setupMenus()
source_ptr source = item->source();
if ( !source.isNull() )
{
PlaylistInterface* pi = AudioEngine::instance()->playlist();
if ( pi && dynamic_cast< SourcePlaylistInterface* >( pi ) )
if ( m_latchManager->isLatched( source ) )
{
SourcePlaylistInterface* sourcepi = dynamic_cast< SourcePlaylistInterface* >( pi );
if ( !sourcepi->source().isNull() && sourcepi->source()->id() == source->id() && !AudioEngine::instance()->state() == AudioEngine::Stopped )
{
m_latchOnAction->setText( tr( "&Catch Up" ) );
m_latchMenu.addSeparator();
m_latchOffAction = m_latchMenu.addAction( tr( "&Stop Listening Along" ) );
connect( m_latchOffAction, SIGNAL( triggered() ), SLOT( latchOff() ) );
}
m_latchOnAction->setText( tr( "&Catch Up" ) );
m_latchMenu.addSeparator();
m_latchOffAction = m_latchMenu.addAction( tr( "&Stop Listening Along" ) );
connect( m_latchOffAction, SIGNAL( triggered() ), SLOT( latchOff() ) );
}
// PlaylistInterface* pi = AudioEngine::instance()->playlist();
// if ( pi && dynamic_cast< SourcePlaylistInterface* >( pi ) )
// {
// SourcePlaylistInterface* sourcepi = dynamic_cast< SourcePlaylistInterface* >( pi );
// if ( !sourcepi->source().isNull() && sourcepi->source()->id() == source->id() && !AudioEngine::instance()->state() == AudioEngine::Stopped )
// {
// }
// }
}
}
@ -189,7 +194,7 @@ SourceTreeView::setupMenus()
connect( m_deletePlaylistAction, SIGNAL( triggered() ), SLOT( deletePlaylist() ) );
connect( m_copyPlaylistAction, SIGNAL( triggered() ), SLOT( copyPlaylistLink() ) );
connect( m_addToLocalAction, SIGNAL( triggered() ), SLOT( addToLocal() ) );
connect( m_latchOnAction, SIGNAL( triggered() ), SLOT( latchOn() ) );
connect( m_latchOnAction, SIGNAL( triggered() ), SLOT( latchOnOrCatchUp() ) );
}
@ -338,7 +343,7 @@ SourceTreeView::addToLocal()
void
SourceTreeView::latchOn()
SourceTreeView::latchOnOrCatchUp()
{
if ( !m_contextMenuIndex.isValid() )
return;
@ -350,100 +355,10 @@ SourceTreeView::latchOn()
CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
source_ptr source = item->source();
doLatchOn( source );
}
if ( m_latchManager->isLatched( source ) )
emit catchUpRequest();
void
SourceTreeView::doLatchOn( const source_ptr& source )
{
qDebug() << Q_FUNC_INFO;
PlaylistInterface* pi = AudioEngine::instance()->playlist();
bool catchUp = false;
if ( pi && dynamic_cast< SourcePlaylistInterface* >( pi ) )
{
SourcePlaylistInterface* sourcepi = dynamic_cast< SourcePlaylistInterface* >( pi );
if ( !sourcepi->source().isNull() && sourcepi->source()->id() == source->id() )
{
//it's a catch-up -- logic in audioengine should take care of it
AudioEngine::instance()->next();
catchUp = true;
m_latch = sourcepi->getSharedPointer();
}
}
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction();
cmd->setSource( SourceList::instance()->getLocal() );
cmd->setAction( "latchOn");
cmd->setComment( source->userName() );
cmd->setTimestamp( QDateTime::currentDateTime().toTime_t() );
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
if ( !catchUp )
{
m_waitingToPlayLatch = source;
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
}
}
void
SourceTreeView::doLatchOff( const source_ptr& source )
{
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
AudioEngine::instance()->stop();
AudioEngine::instance()->setPlaylist( 0 );
}
void
SourceTreeView::playlistChanged( PlaylistInterface* newInterface )
{
Q_UNUSED( newInterface );
// If we were latched on and changed, send the listening along stop
if ( m_latch.isNull() )
{
if ( m_waitingToPlayLatch.isNull() )
return;
m_latch = m_waitingToPlayLatch->getPlaylistInterface();
m_waitingToPlayLatch.clear();
return;
}
const PlaylistInterface* pi = AudioEngine::instance()->playlist();
bool listeningAlong = false;
source_ptr newSource;
if ( pi && dynamic_cast< const SourcePlaylistInterface* >( pi ) )
{
const SourcePlaylistInterface* sourcepi = dynamic_cast< const SourcePlaylistInterface* >( pi );
if ( !AudioEngine::instance()->state() == AudioEngine::Stopped )
{
listeningAlong = true;
newSource = sourcepi->source();
}
}
SourcePlaylistInterface* origsourcepi = dynamic_cast< SourcePlaylistInterface* >( m_latch.data() );
Q_ASSERT( origsourcepi );
const source_ptr source = origsourcepi->source();
// if we're currently listening along to the same source, no change
if ( listeningAlong && ( !origsourcepi->source().isNull() && origsourcepi->source()->id() == newSource->id() ) )
return;
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction();
cmd->setSource( SourceList::instance()->getLocal() );
cmd->setAction( "latchOff");
cmd->setComment( source->userName() );
cmd->setTimestamp( QDateTime::currentDateTime().toTime_t() );
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
m_latch.clear();
emit latchRequest( source );
}
void
@ -460,7 +375,7 @@ SourceTreeView::latchOff()
const CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
const source_ptr source = item->source();
doLatchOff( source );
emit unlatchRequest( source );
}

View File

@ -31,6 +31,11 @@ class SourcesModel;
class SourcesProxyModel;
class SourceDelegate;
namespace Tomahawk
{
class LatchManager;
}
class SourceTreeView : public QTreeView
{
Q_OBJECT
@ -50,6 +55,10 @@ signals:
void onOnline( const QModelIndex& index );
void onOffline( const QModelIndex& index );
void latchRequest( const Tomahawk::source_ptr& source );
void unlatchRequest( const Tomahawk::source_ptr& source );
void catchUpRequest();
private slots:
void onItemExpanded( const QModelIndex& idx );
void onItemActivated( const QModelIndex& index );
@ -61,12 +70,8 @@ private slots:
void copyPlaylistLink();
void addToLocal();
void latchOn();
void doLatchOn( const Tomahawk::source_ptr& idx );
void latchOnOrCatchUp();
void latchOff();
void doLatchOff( const Tomahawk::source_ptr& idx );
void playlistChanged( Tomahawk::PlaylistInterface* = 0 );
void onCustomContextMenu( const QPoint& pos );
@ -91,6 +96,7 @@ private:
SourcesProxyModel* m_proxyModel;
QModelIndex m_contextMenuIndex;
SourceDelegate* m_delegate;
Tomahawk::LatchManager* m_latchManager;
QMenu m_playlistMenu;
QMenu m_roPlaylistMenu;
@ -103,9 +109,6 @@ private:
QAction* m_latchOnAction;
QAction* m_latchOffAction;
Tomahawk::source_ptr m_waitingToPlayLatch;
Tomahawk::playlistinterface_ptr m_latch;
bool m_dragging;
QRect m_dropRect;
QPersistentModelIndex m_dropIndex;