mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-09-12 23:12:05 +02:00
Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a104e92471 | ||
|
1929804541 | ||
|
a564b3b272 | ||
|
d083528ad5 | ||
|
4d63a9462d | ||
|
5a64886b7c | ||
|
76986e8908 | ||
|
9a9a7148af | ||
|
aec7a0b140 | ||
|
eff42af593 | ||
|
ad2b54ad90 | ||
|
4e316a48ea | ||
|
87863ae7e2 | ||
|
5e439b990f | ||
|
5dcf426cdf | ||
|
5b6c4560ae | ||
|
fec670f27c | ||
|
fb13ccd285 | ||
|
b3b70cea82 | ||
|
f84d08e011 | ||
|
9c5966000c | ||
|
79bfdec895 | ||
|
9f5215302c | ||
|
73d7ba03f5 | ||
|
d623bbefc2 | ||
|
907dad95e1 | ||
|
565217a53a | ||
|
bee6485475 | ||
|
ace18dfa1f | ||
|
95f1162b6e | ||
|
e5bdd2242f | ||
|
deb0eb819c | ||
|
04864c7d79 | ||
|
43c4daa4e3 | ||
|
fc95cee6ce | ||
|
fff8fbfe80 | ||
|
eec8b76de0 | ||
|
68f03dbd13 | ||
|
753e1b3c90 | ||
|
e828dadec8 | ||
|
6e929986cb | ||
|
e1b086e3a4 | ||
|
27147a0140 | ||
|
66836ae0bd | ||
|
6342e6a9f8 | ||
|
042ccbe730 | ||
|
6c6411561b | ||
|
18e3669911 | ||
|
240517b0cd | ||
|
fab36b2262 | ||
|
dd74ce04e6 |
@@ -16,7 +16,7 @@ SET( TOMAHAWK_DESCRIPTION_SUMMARY "The social media player" )
|
||||
|
||||
SET( TOMAHAWK_VERSION_MAJOR 0 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 4 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 0 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 2 )
|
||||
|
||||
#SET( TOMAHAWK_VERSION_RC 0 )
|
||||
|
||||
|
85
ChangeLog
85
ChangeLog
@@ -1,38 +1,55 @@
|
||||
Version 0.4.2:
|
||||
* Updated translations for various languages.
|
||||
* Resuming playback restores correct volume settings.
|
||||
* Reduced CPU usage during playback.
|
||||
* Fixed not starting up due to case sensitivity issue on OS X.
|
||||
* Fixed volume issue (too quiet) on Windows.
|
||||
|
||||
Version 0.4.1:
|
||||
* Fixed various crashes.
|
||||
* Fixed issues with auto-updating XSPF playlists.
|
||||
* Double-clicking a playlist starts playing it.
|
||||
* Resolvers can now return disc number and album position for results.
|
||||
* Fixed sorting playlists by track number.
|
||||
* Fixed issues with changing proxy.
|
||||
* Fixed Twitter authentication issues.
|
||||
* Fixed Grooveshark support on Windows.
|
||||
|
||||
Version 0.4.0:
|
||||
* Added visual notification for database indexing job.
|
||||
* Fixed icons not appearing in resolvers list.
|
||||
* Fixed various UI glitches and stray error messages in stations.
|
||||
* Fixed bug where album page would resolve bottom-to-top.
|
||||
* Fixed bug where Footnotes would not update when changing selected album in Album View.
|
||||
* Fixed dragging albums and artists from charts, album, and artist views.
|
||||
* Fixed bug where filter text would be one step behind filter value.
|
||||
* Fixed bug where resolvers would enable themselves after auto-updating.
|
||||
* Fixed occasional crash when dropping tracks onto New Station item.
|
||||
* Added jump-to-current-track support for search results page.
|
||||
* Fixed out of sync Show/Hide menu items on OS X when hidden with cmd-h.
|
||||
* Fixed non-resolving tracks when dragging from album view.
|
||||
* Fixed /Volumes directory not showing up on OS X.
|
||||
* Fixed fetching album covers for albums with special characters.
|
||||
* Show errors and continue gracefully when resolved audio is not available.
|
||||
* Fixed various crashes on exit.
|
||||
* Added basic command-line options for playback control.
|
||||
* Bumped up web api timeouts to allow web clients to finish resolving.
|
||||
* Added filename suggestion when exporting a playlist.
|
||||
* Cleaned up highlighting of artist names in album view.
|
||||
* Cleaned up alignment of playlist items.
|
||||
* Fixed potential crash when searching.
|
||||
* Added support for disc number.
|
||||
* Added SoundCloudWall.com charts.
|
||||
* Added ability to "lock on" to a user when listening along, to skip along.
|
||||
* Fixed bug where loved tracks would be refreshed much too often.
|
||||
* Fixed startup crash on OS X.
|
||||
* Fixed some font size issues.
|
||||
* Sped up Tomahawk startup by moving chart loading into a separate thread.
|
||||
* Added support for parsing Grooveshark and Tinysong tracks and playlists.
|
||||
* Reorganized sidebar to follow more logical item groupings.
|
||||
* Added artist and album results to global searches.
|
||||
* Fixed style and contrast issues when using GTK styles.
|
||||
* Fixed paths to artwork when using MPRIS2 interface.
|
||||
* Added visual notification for database indexing job.
|
||||
* Fixed icons not appearing in resolvers list.
|
||||
* Fixed various UI glitches and stray error messages in stations.
|
||||
* Fixed bug where album page would resolve bottom-to-top.
|
||||
* Fixed bug where Footnotes would not update when changing selected album in Album View.
|
||||
* Fixed dragging albums and artists from charts, album, and artist views.
|
||||
* Fixed bug where filter text would be one step behind filter value.
|
||||
* Fixed bug where resolvers would enable themselves after auto-updating.
|
||||
* Fixed occasional crash when dropping tracks onto New Station item.
|
||||
* Added jump-to-current-track support for search results page.
|
||||
* Fixed non-resolving tracks when dragging from album view.
|
||||
* Fixed fetching album covers for albums with special characters.
|
||||
* Show errors and continue gracefully when resolved audio is not available.
|
||||
* Fixed various crashes on exit.
|
||||
* Added basic command-line options for playback control.
|
||||
* Bumped up web api timeouts to allow web clients to finish resolving.
|
||||
* Added filename suggestion when exporting a playlist.
|
||||
* Cleaned up highlighting of artist names in album view.
|
||||
* Cleaned up alignment of playlist items.
|
||||
* Fixed potential crash when searching.
|
||||
* Added support for disc number.
|
||||
* Added SoundCloudWall.com charts.
|
||||
* Added ability to "lock on" to a user when listening along, to skip along.
|
||||
* Fixed bug where loved tracks would be refreshed much too often.
|
||||
* Fixed some font size issues.
|
||||
* Sped up Tomahawk startup by moving chart loading into a separate thread.
|
||||
* Added support for parsing Grooveshark and Tinysong tracks and playlists.
|
||||
* Reorganized sidebar to follow more logical item groupings.
|
||||
* Added artist and album results to global searches.
|
||||
* Fixed style and contrast issues when using GTK styles.
|
||||
* Fixed paths to artwork when using MPRIS2 interface.
|
||||
* Fixed out of sync Show/Hide menu items on OS X when hidden with cmd-h.
|
||||
* Fixed /Volumes directory not showing up on OS X.
|
||||
* Fixed startup crash on OS X.
|
||||
|
||||
Version 0.3.3:
|
||||
* Automatically load Super Collection tracks when no official release
|
||||
|
6
README
6
README
@@ -39,13 +39,13 @@ Dependencies
|
||||
The following dependencies are optional, but recommended:
|
||||
|
||||
Attica 0.2.0 - ftp://ftp.kde.org/pub/kde/stable/attica/
|
||||
Jreen 1.0.1 - https://github.com/euroelessar/jreen
|
||||
QTweetLib 0.3.0 - https://github.com/minimoog/QTweetLib
|
||||
QuaZip 0.4.3 - http://quazip.sourceforge.net/
|
||||
Jreen 1.0.3 - https://github.com/euroelessar/jreen
|
||||
QTweetLib 0.5.0 - https://github.com/minimoog/QTweetLib
|
||||
|
||||
Third party libraries that we ship with our source:
|
||||
|
||||
MiniUPnP 1.6 - http://miniupnp.free.fr/
|
||||
liblastfm 0.4.0 - http://github.com/jonocole/liblastfm/
|
||||
QuaZip 0.4.3 - http://quazip.sourceforge.net/
|
||||
|
||||
Enjoy!
|
||||
|
@@ -250,7 +250,7 @@ frameworks_dir = os.path.join(bundle_dir, 'Contents', 'Frameworks')
|
||||
commands.append(['mkdir', '-p', frameworks_dir])
|
||||
resources_dir = os.path.join(bundle_dir, 'Contents', 'Resources')
|
||||
commands.append(['mkdir', '-p', resources_dir])
|
||||
plugins_dir = os.path.join(bundle_dir, 'Contents', 'plugins')
|
||||
plugins_dir = os.path.join(bundle_dir, 'Contents', 'PlugIns')
|
||||
binary = os.path.join(bundle_dir, 'Contents', 'MacOS', bundle_name)
|
||||
|
||||
fixed_libraries = []
|
||||
|
3541
lang/tomahawk_bg.ts
Normal file
3541
lang/tomahawk_bg.ts
Normal file
File diff suppressed because it is too large
Load Diff
2497
lang/tomahawk_de.ts
2497
lang/tomahawk_de.ts
File diff suppressed because it is too large
Load Diff
3367
lang/tomahawk_en.ts
3367
lang/tomahawk_en.ts
File diff suppressed because it is too large
Load Diff
2228
lang/tomahawk_es.ts
2228
lang/tomahawk_es.ts
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
|
2324
lang/tomahawk_pl.ts
2324
lang/tomahawk_pl.ts
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3393
lang/tomahawk_sv.ts
3393
lang/tomahawk_sv.ts
File diff suppressed because it is too large
Load Diff
@@ -92,14 +92,12 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
ui->metaDataArea->setStyleSheet( "QWidget#metaDataArea {\nborder-width: 4px;\nborder-image: url(" RESPATH "images/now-playing-panel.png) 4 4 4 4 stretch stretch; }" );
|
||||
|
||||
ui->seekSlider->setEnabled( true );
|
||||
ui->seekSlider->setTimeLine( &m_sliderTimeLine );
|
||||
ui->volumeSlider->setRange( 0, 100 );
|
||||
ui->volumeSlider->setValue( AudioEngine::instance()->volume() );
|
||||
|
||||
m_phononTickCheckTimer.setSingleShot( true );
|
||||
|
||||
m_sliderTimeLine.setCurveShape( QTimeLine::LinearCurve );
|
||||
ui->seekSlider->setTimeLine( &m_sliderTimeLine );
|
||||
|
||||
connect( &m_phononTickCheckTimer, SIGNAL( timeout() ), SLOT( phononTickCheckTimeout() ) );
|
||||
connect( &m_sliderTimeLine, SIGNAL( frameChanged( int ) ), ui->seekSlider, SLOT( setValue( int ) ) );
|
||||
|
||||
@@ -199,6 +197,7 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
|
||||
|
||||
ui->seekSlider->setRange( 0, duration );
|
||||
ui->seekSlider->setValue( 0 );
|
||||
ui->seekSlider->setEnabled( AudioEngine::instance()->canSeek() );
|
||||
|
||||
m_phononTickCheckTimer.stop();
|
||||
|
||||
@@ -207,9 +206,12 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
|
||||
m_sliderTimeLine.setFrameRange( 0, duration );
|
||||
m_sliderTimeLine.setCurrentTime( 0 );
|
||||
m_seekMsecs = -1;
|
||||
|
||||
|
||||
ui->seekSlider->setVisible( true );
|
||||
|
||||
int updateRate = (double)1000 / ( (double)ui->seekSlider->contentsRect().width() / (double)( duration / 1000 ) );
|
||||
m_sliderTimeLine.setUpdateInterval( qBound( 40, updateRate, 500 ) );
|
||||
|
||||
m_noTimeChange = false;
|
||||
m_lastSliderCheck = 0;
|
||||
}
|
||||
@@ -237,6 +239,7 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result )
|
||||
ui->timeLabel->setText( TomahawkUtils::timeToString( 0 ) );
|
||||
ui->timeLeftLabel->setFixedWidth( ui->timeLeftLabel->fontMetrics().width( QString( duration.length() + 1, QChar( '0' ) ) ) );
|
||||
ui->timeLeftLabel->setText( "-" + duration );
|
||||
m_lastTextSecondShown = 0;
|
||||
|
||||
ui->stackedLayout->setCurrentWidget( ui->pauseButton );
|
||||
|
||||
@@ -277,7 +280,7 @@ void
|
||||
AudioControls::onSocialActionsLoaded()
|
||||
{
|
||||
Query* query = qobject_cast< Query* >( sender() );
|
||||
if ( !query )
|
||||
if ( !query || !m_currentTrack || query != m_currentTrack->toQuery().data() )
|
||||
return;
|
||||
|
||||
query_ptr currentQuery = m_currentTrack->toQuery();
|
||||
@@ -361,6 +364,14 @@ AudioControls::onPlaybackStopped()
|
||||
void
|
||||
AudioControls::onPlaybackTimer( qint64 msElapsed )
|
||||
{
|
||||
const int seconds = msElapsed / 1000;
|
||||
if ( seconds != m_lastTextSecondShown && !m_currentTrack.isNull() )
|
||||
{
|
||||
ui->timeLabel->setText( TomahawkUtils::timeToString( seconds ) );
|
||||
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( m_currentTrack->duration() - seconds ) );
|
||||
m_lastTextSecondShown = seconds;
|
||||
}
|
||||
|
||||
//tDebug( LOGEXTRA ) << Q_FUNC_INFO << "msElapsed =" << msElapsed << "and timer current time =" << m_sliderTimeLine.currentTime() << "and m_seekMsecs =" << m_seekMsecs;
|
||||
if ( msElapsed > 0 && msElapsed != m_lastSliderCheck && m_seekMsecs == -1 && msElapsed - 500 < m_lastSliderCheck )
|
||||
return;
|
||||
@@ -376,14 +387,11 @@ AudioControls::onPlaybackTimer( qint64 msElapsed )
|
||||
|
||||
if ( sender() != &m_phononTickCheckTimer )
|
||||
m_phononTickCheckTimer.start( 1000 );
|
||||
|
||||
const int seconds = msElapsed / 1000;
|
||||
ui->timeLabel->setText( TomahawkUtils::timeToString( seconds ) );
|
||||
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( m_currentTrack->duration() - seconds ) );
|
||||
|
||||
|
||||
int currentTime = m_sliderTimeLine.currentTime();
|
||||
if ( m_noTimeChange )
|
||||
{
|
||||
if ( m_sliderTimeLine.currentTime() != msElapsed )
|
||||
if ( currentTime != msElapsed )
|
||||
{
|
||||
m_sliderTimeLine.setPaused( true );
|
||||
m_noTimeChange = false;
|
||||
@@ -392,12 +400,12 @@ AudioControls::onPlaybackTimer( qint64 msElapsed )
|
||||
m_sliderTimeLine.resume();
|
||||
}
|
||||
}
|
||||
else if ( m_sliderTimeLine.currentTime() >= msElapsed || m_seekMsecs != -1 )
|
||||
else if ( currentTime >= msElapsed || m_seekMsecs != -1 )
|
||||
{
|
||||
m_sliderTimeLine.setPaused( true );
|
||||
|
||||
m_noTimeChange = false;
|
||||
if ( m_sliderTimeLine.currentTime() == msElapsed )
|
||||
if ( currentTime == msElapsed )
|
||||
m_noTimeChange = true;
|
||||
|
||||
m_sliderTimeLine.setCurrentTime( msElapsed );
|
||||
@@ -407,12 +415,10 @@ AudioControls::onPlaybackTimer( qint64 msElapsed )
|
||||
}
|
||||
else if ( m_sliderTimeLine.duration() > msElapsed && m_sliderTimeLine.state() == QTimeLine::NotRunning && AudioEngine::instance()->state() == AudioEngine::Playing )
|
||||
{
|
||||
ui->seekSlider->setEnabled( AudioEngine::instance()->canSeek() );
|
||||
m_sliderTimeLine.start();
|
||||
}
|
||||
else if ( m_sliderTimeLine.state() == QTimeLine::Paused && AudioEngine::instance()->state() != AudioEngine::Paused )
|
||||
{
|
||||
ui->seekSlider->setEnabled( AudioEngine::instance()->canSeek() );
|
||||
m_sliderTimeLine.resume();
|
||||
}
|
||||
|
||||
|
@@ -100,6 +100,7 @@ private:
|
||||
qint64 m_seekMsecs;
|
||||
qint64 m_lastSliderCheck;
|
||||
bool m_noTimeChange;
|
||||
qint64 m_lastTextSecondShown;
|
||||
};
|
||||
|
||||
#endif // AUDIOCONTROLS_H
|
||||
|
@@ -116,6 +116,7 @@ set( libGuiSources
|
||||
utils/dropjobnotifier.cpp
|
||||
utils/proxystyle.cpp
|
||||
utils/tomahawkutilsgui.cpp
|
||||
utils/closure.cpp
|
||||
|
||||
widgets/checkdirtree.cpp
|
||||
widgets/querylabel.cpp
|
||||
@@ -240,6 +241,7 @@ set( libGuiHeaders
|
||||
utils/rdioparser.h
|
||||
utils/shortenedlinkparser.h
|
||||
utils/dropjobnotifier.h
|
||||
utils/closure.h
|
||||
|
||||
widgets/checkdirtree.h
|
||||
widgets/querylabel.h
|
||||
|
@@ -61,7 +61,7 @@ Album::get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& ar
|
||||
return s_albums.value( id );
|
||||
}
|
||||
|
||||
album_ptr a = album_ptr( new Album( id, name, artist ) );
|
||||
album_ptr a = album_ptr( new Album( id, name, artist ), &QObject::deleteLater );
|
||||
if ( id > 0 )
|
||||
s_albums.insert( id, a );
|
||||
|
||||
|
@@ -61,7 +61,7 @@ Artist::get( unsigned int id, const QString& name )
|
||||
return s_artists.value( id );
|
||||
}
|
||||
|
||||
artist_ptr a = artist_ptr( new Artist( id, name ) );
|
||||
artist_ptr a = artist_ptr( new Artist( id, name ), &QObject::deleteLater );
|
||||
if ( id > 0 )
|
||||
s_artists.insert( id, a );
|
||||
|
||||
|
@@ -131,8 +131,11 @@ AudioEngine::play()
|
||||
|
||||
if ( isPaused() )
|
||||
{
|
||||
setVolume( m_volume );
|
||||
m_mediaObject->play();
|
||||
setVolume( m_volume );
|
||||
emit resumed();
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash trackInfo;
|
||||
|
||||
trackInfo["title"] = m_currentTrack->track();
|
||||
@@ -152,6 +155,7 @@ AudioEngine::pause()
|
||||
{
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO;
|
||||
|
||||
m_volume = volume();
|
||||
m_mediaObject->pause();
|
||||
emit paused();
|
||||
|
||||
|
@@ -155,6 +155,7 @@ private:
|
||||
|
||||
mutable QStringList m_supportedMimeTypes;
|
||||
AudioState m_state;
|
||||
unsigned int m_volume;
|
||||
|
||||
static AudioEngine* s_instance;
|
||||
};
|
||||
|
@@ -37,6 +37,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 ) );
|
||||
|
@@ -142,7 +142,7 @@ DatabaseCollection::autoPlaylistCreated( const source_ptr& source, const QVarian
|
||||
static_cast<GeneratorMode>(data[6].toInt()), // dynamic mode
|
||||
data[7].toBool(), //shared
|
||||
data[8].toInt(), //lastmod
|
||||
data[9].toString() ) ); //GUID
|
||||
data[9].toString() ), &QObject::deleteLater ); //GUID
|
||||
addAutoPlaylist( p );
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ DatabaseCollection::stationCreated( const source_ptr& source, const QVariantList
|
||||
static_cast<GeneratorMode>(data[6].toInt()), // dynamic mode
|
||||
data[7].toBool(), //shared
|
||||
data[8].toInt(), //lastmod
|
||||
data[9].toString() ) ); //GUID
|
||||
data[9].toString() ), &QObject::deleteLater ); //GUID
|
||||
addStation( p );
|
||||
}
|
||||
|
||||
|
@@ -71,7 +71,7 @@ DatabaseCommand_LoadAllPlaylists::exec( DatabaseImpl* dbi )
|
||||
query.value(5).toBool(), //shared
|
||||
query.value(4).toInt(), //lastmod
|
||||
query.value(0).toString() //GUID
|
||||
) );
|
||||
), &QObject::deleteLater );
|
||||
plists.append( p );
|
||||
}
|
||||
|
||||
|
@@ -55,9 +55,6 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
|
||||
qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint();
|
||||
|
||||
Tomahawk::result_ptr result = lib->resultFromHint( m_query );
|
||||
/* qDebug() << "Result null:" << result.isNull();
|
||||
* qDebug() << "Collection null:" << result->collection().isNull();
|
||||
* qDebug() << "Source null:" << result->collection()->source().isNull();*/
|
||||
if ( !result.isNull() && !result->collection().isNull() && result->collection()->source()->isOnline() )
|
||||
{
|
||||
QList<Tomahawk::result_ptr> res;
|
||||
@@ -137,7 +134,7 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
|
||||
else
|
||||
{
|
||||
s = SourceList::instance()->get( files_query.value( 16 ).toUInt() );
|
||||
if( s.isNull() )
|
||||
if ( s.isNull() )
|
||||
{
|
||||
qDebug() << "Could not find source" << files_query.value( 16 ).toUInt();
|
||||
continue;
|
||||
@@ -146,13 +143,18 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
|
||||
url = QString( "servent://%1\t%2" ).arg( s->userName() ).arg( url );
|
||||
}
|
||||
|
||||
bool cached = Tomahawk::Result::isCached( url );
|
||||
Tomahawk::result_ptr result = Tomahawk::Result::get( url );
|
||||
Tomahawk::artist_ptr artist =
|
||||
Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() );
|
||||
Tomahawk::album_ptr album =
|
||||
Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist );
|
||||
Tomahawk::artist_ptr composer =
|
||||
Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() );
|
||||
if ( cached )
|
||||
{
|
||||
qDebug() << "Result already cached:" << result->toString();
|
||||
res << result;
|
||||
continue;
|
||||
}
|
||||
|
||||
Tomahawk::artist_ptr artist = Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() );
|
||||
Tomahawk::album_ptr album = Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist );
|
||||
Tomahawk::artist_ptr composer = Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() );
|
||||
|
||||
result->setModificationTime( files_query.value( 1 ).toUInt() );
|
||||
result->setSize( files_query.value( 2 ).toUInt() );
|
||||
@@ -181,6 +183,7 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
|
||||
|
||||
result->setAttributes( attr );
|
||||
result->setCollection( s->collection() );
|
||||
|
||||
res << result;
|
||||
}
|
||||
|
||||
@@ -270,7 +273,7 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
||||
else
|
||||
{
|
||||
s = SourceList::instance()->get( files_query.value( 16 ).toUInt() );
|
||||
if( s.isNull() )
|
||||
if ( s.isNull() )
|
||||
{
|
||||
qDebug() << "Could not find source" << files_query.value( 16 ).toUInt();
|
||||
continue;
|
||||
@@ -279,13 +282,18 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
||||
url = QString( "servent://%1\t%2" ).arg( s->userName() ).arg( url );
|
||||
}
|
||||
|
||||
bool cached = Tomahawk::Result::isCached( url );
|
||||
Tomahawk::result_ptr result = Tomahawk::Result::get( url );
|
||||
Tomahawk::artist_ptr artist =
|
||||
Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() );
|
||||
Tomahawk::album_ptr album =
|
||||
Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist );
|
||||
Tomahawk::artist_ptr composer =
|
||||
Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() );
|
||||
if ( cached )
|
||||
{
|
||||
qDebug() << "Result already cached:" << result->toString();
|
||||
res << result;
|
||||
continue;
|
||||
}
|
||||
|
||||
Tomahawk::artist_ptr artist = Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() );
|
||||
Tomahawk::album_ptr album = Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist );
|
||||
Tomahawk::artist_ptr composer = Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() );
|
||||
|
||||
result->setModificationTime( files_query.value( 1 ).toUInt() );
|
||||
result->setSize( files_query.value( 2 ).toUInt() );
|
||||
@@ -322,8 +330,8 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
||||
}
|
||||
|
||||
result->setAttributes( attr );
|
||||
|
||||
result->setCollection( s->collection() );
|
||||
|
||||
res << result;
|
||||
}
|
||||
|
||||
|
@@ -227,7 +227,7 @@ FuzzyIndex::search( const Tomahawk::query_ptr& query )
|
||||
fqry = _CLNEW FuzzyQuery( term );
|
||||
qry->add( fqry, true, BooleanClause::MUST );
|
||||
|
||||
minScore = 0.05;
|
||||
minScore = 0.00;
|
||||
}
|
||||
|
||||
Hits* hits = m_luceneSearcher->search( qry );
|
||||
|
@@ -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 );
|
||||
|
||||
|
@@ -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 );
|
||||
|
@@ -456,7 +456,7 @@ LastFmPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSy
|
||||
imgurl.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artistName, "", "+" ) );
|
||||
imgurl.addEncodedQueryItem( "album", QUrl::toPercentEncoding( albumName, "", "+" ) );
|
||||
imgurl.addQueryItem( "autocorrect", QString::number( 1 ) );
|
||||
imgurl.addQueryItem( "size", "large" );
|
||||
imgurl.addQueryItem( "size", "largesquare" );
|
||||
imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" );
|
||||
|
||||
QNetworkRequest req( imgurl );
|
||||
@@ -475,7 +475,7 @@ LastFmPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSy
|
||||
imgurl.addQueryItem( "method", "artist.imageredirect" );
|
||||
imgurl.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artistName, "", "+" ) );
|
||||
imgurl.addQueryItem( "autocorrect", QString::number( 1 ) );
|
||||
imgurl.addQueryItem( "size", "large" );
|
||||
imgurl.addQueryItem( "size", "largesquare" );
|
||||
imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" );
|
||||
|
||||
QNetworkRequest req( imgurl );
|
||||
@@ -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;
|
||||
|
||||
|
@@ -185,7 +185,7 @@ Playlist::create( const source_ptr& author,
|
||||
entries << p;
|
||||
}
|
||||
|
||||
playlist_ptr playlist( new Playlist( author, guid, title, info, creator, shared, entries ) );
|
||||
playlist_ptr playlist( new Playlist( author, guid, title, info, creator, shared, entries ), &QObject::deleteLater );
|
||||
|
||||
// save to DB in the background
|
||||
// Watch for the created() signal if you need to be sure it's written.
|
||||
|
@@ -182,7 +182,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();
|
||||
|
@@ -55,31 +55,34 @@ 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( ok ( Tomahawk::playlist_ptr ) ), this, SLOT( playlistLoaded() ) );
|
||||
connect( l, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( playlistLoaded( QList<Tomahawk::query_ptr> ) ) );
|
||||
}
|
||||
|
||||
void
|
||||
XspfUpdater::playlistLoaded()
|
||||
XspfUpdater::playlistLoaded( const QList<Tomahawk::query_ptr>& newEntries )
|
||||
{
|
||||
XSPFLoader* loader = qobject_cast<XSPFLoader*>( sender() );
|
||||
Q_ASSERT( loader );
|
||||
|
||||
QList< query_ptr > tracks;
|
||||
foreach ( const plentry_ptr ple, playlist()->entries() )
|
||||
tracks << ple->query();
|
||||
|
||||
bool changed = false;
|
||||
QList< query_ptr > mergedTracks = TomahawkUtils::mergePlaylistChanges( tracks, loader->entries(), changed );
|
||||
QList< query_ptr > mergedTracks = TomahawkUtils::mergePlaylistChanges( tracks, newEntries, changed );
|
||||
|
||||
if ( !changed )
|
||||
return;
|
||||
|
||||
QList<Tomahawk::plentry_ptr> el = playlist()->entriesFromQueries( mergedTracks, true );
|
||||
playlist()->createNewRevision( uuid(), playlist()->currentrevision(), el );
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -37,6 +37,7 @@ public:
|
||||
virtual ~XspfUpdater();
|
||||
|
||||
virtual QString type() const { return "xspf"; }
|
||||
|
||||
public slots:
|
||||
void updateNow();
|
||||
|
||||
@@ -46,7 +47,7 @@ protected:
|
||||
virtual void removeFromSettings(const QString& group) const;
|
||||
|
||||
private slots:
|
||||
void playlistLoaded();
|
||||
void playlistLoaded( const QList<Tomahawk::query_ptr> & );
|
||||
|
||||
private:
|
||||
QString m_url;
|
||||
|
@@ -178,6 +178,7 @@ AlbumModel::mimeData( const QModelIndexList &indexes ) const
|
||||
QByteArray queryData;
|
||||
QDataStream queryStream( &queryData, QIODevice::WriteOnly );
|
||||
|
||||
bool isAlbumData = true;
|
||||
foreach ( const QModelIndex& i, indexes )
|
||||
{
|
||||
if ( i.column() > 0 )
|
||||
@@ -185,16 +186,25 @@ AlbumModel::mimeData( const QModelIndexList &indexes ) const
|
||||
|
||||
QModelIndex idx = index( i.row(), 0, i.parent() );
|
||||
AlbumItem* item = itemFromIndex( idx );
|
||||
if ( item )
|
||||
if ( item && !item->album().isNull() )
|
||||
{
|
||||
const album_ptr& album = item->album();
|
||||
queryStream << album->artist()->name();
|
||||
queryStream << album->name();
|
||||
|
||||
isAlbumData = true;
|
||||
}
|
||||
else if ( item && !item->artist().isNull() )
|
||||
{
|
||||
const artist_ptr& artist = item->artist();
|
||||
queryStream << artist->name();
|
||||
|
||||
isAlbumData = false;
|
||||
}
|
||||
}
|
||||
|
||||
QMimeData* mimeData = new QMimeData();
|
||||
mimeData->setData( "application/tomahawk.metadata.album", queryData );
|
||||
QMimeData* mimeData = new QMimeData;
|
||||
mimeData->setData( isAlbumData ? "application/tomahawk.metadata.album" : "application/tomahawk.metadata.artist", queryData );
|
||||
|
||||
return mimeData;
|
||||
}
|
||||
@@ -431,7 +441,7 @@ AlbumModel::findItem( const artist_ptr& artist ) const
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -447,6 +457,6 @@ AlbumModel::findItem( const album_ptr& album ) const
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -152,7 +152,7 @@ DynamicPlaylist::create( const Tomahawk::source_ptr& author,
|
||||
bool autoLoad
|
||||
)
|
||||
{
|
||||
dynplaylist_ptr dynplaylist = Tomahawk::dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared, autoLoad ) );
|
||||
dynplaylist_ptr dynplaylist = Tomahawk::dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared, autoLoad ), &QObject::deleteLater );
|
||||
|
||||
DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist, autoLoad );
|
||||
connect( cmd, SIGNAL(finished()), dynplaylist.data(), SIGNAL(created()) );
|
||||
|
@@ -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;
|
||||
|
@@ -104,10 +104,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 ) );
|
||||
}
|
||||
|
@@ -69,7 +69,7 @@ TrackProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParen
|
||||
return false;
|
||||
|
||||
const Tomahawk::query_ptr& q = pi->query();
|
||||
if( q.isNull() ) // uh oh? filter out invalid queries i guess
|
||||
if ( q.isNull() ) // uh oh? filter out invalid queries i guess
|
||||
return false;
|
||||
|
||||
Tomahawk::result_ptr r;
|
||||
@@ -190,7 +190,7 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c
|
||||
album1 = r->album()->name();
|
||||
track1 = r->track();
|
||||
albumpos1 = r->albumpos();
|
||||
discnumber1 = r->discnumber();
|
||||
discnumber1 = qMax( 1, (int)r->discnumber() );
|
||||
bitrate1 = r->bitrate();
|
||||
mtime1 = r->modificationTime();
|
||||
id1 = r->trackId();
|
||||
@@ -203,7 +203,7 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c
|
||||
album2 = r->album()->name();
|
||||
track2 = r->track();
|
||||
albumpos2 = r->albumpos();
|
||||
discnumber2 = r->discnumber();
|
||||
discnumber2 = qMax( 1, (int)r->discnumber() );
|
||||
bitrate2 = r->bitrate();
|
||||
mtime2 = r->modificationTime();
|
||||
id2 = r->trackId();
|
||||
@@ -223,7 +223,7 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c
|
||||
{
|
||||
if ( album1 == album2 )
|
||||
{
|
||||
if( discnumber1 == discnumber2 )
|
||||
if ( discnumber1 == discnumber2 )
|
||||
{
|
||||
if ( albumpos1 == albumpos2 )
|
||||
return id1 < id2;
|
||||
@@ -243,7 +243,7 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c
|
||||
{
|
||||
if ( album1 == album2 )
|
||||
{
|
||||
if( discnumber1 == discnumber2 )
|
||||
if ( discnumber1 == discnumber2 )
|
||||
{
|
||||
if ( albumpos1 == albumpos2 )
|
||||
return id1 < id2;
|
||||
@@ -277,6 +277,18 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c
|
||||
|
||||
return size1 < size2;
|
||||
}
|
||||
else if ( left.column() == TrackModel::AlbumPos ) // sort by album pos
|
||||
{
|
||||
if ( discnumber1 != discnumber2 )
|
||||
{
|
||||
return discnumber1 < discnumber2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( albumpos1 != albumpos2 )
|
||||
return albumpos1 < albumpos2;
|
||||
}
|
||||
}
|
||||
|
||||
const QString& lefts = sourceModel()->data( left ).toString();
|
||||
const QString& rights = sourceModel()->data( right ).toString();
|
||||
|
@@ -32,6 +32,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"
|
||||
@@ -152,6 +153,41 @@ TrackView::setTrackModel( TrackModel* model )
|
||||
}
|
||||
|
||||
|
||||
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 )
|
||||
{
|
||||
@@ -174,15 +210,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;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -64,6 +64,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 );
|
||||
|
||||
@@ -98,7 +101,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;
|
||||
@@ -117,6 +124,9 @@ private:
|
||||
|
||||
QModelIndex m_hoveredIndex;
|
||||
QModelIndex m_contextMenuIndex;
|
||||
|
||||
Tomahawk::query_ptr m_autoPlaying;
|
||||
|
||||
Tomahawk::ContextMenu* m_contextMenu;
|
||||
};
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@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
|
||||
@@ -622,7 +623,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 );
|
||||
}
|
||||
@@ -660,8 +661,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;
|
||||
@@ -796,7 +797,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 );
|
||||
}
|
||||
|
||||
@@ -886,7 +887,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 );
|
||||
|
||||
@@ -940,7 +941,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 );
|
||||
|
||||
|
@@ -301,28 +301,35 @@ TreeProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) co
|
||||
albumpos2 = p2->query()->albumpos();
|
||||
discnumber2 = p2->query()->discnumber();
|
||||
}
|
||||
if ( !p1->result().isNull() )
|
||||
{
|
||||
if ( albumpos1 == 0 )
|
||||
albumpos1 = p1->result()->albumpos();
|
||||
if ( discnumber1 == 0 )
|
||||
discnumber1 = p1->result()->discnumber();
|
||||
}
|
||||
if ( !p2->result().isNull() )
|
||||
{
|
||||
if ( albumpos2 == 0 )
|
||||
albumpos2 = p2->result()->albumpos();
|
||||
if ( discnumber2 == 0 )
|
||||
discnumber2 = p2->result()->discnumber();
|
||||
}
|
||||
discnumber1 = qMax( 1, (int)discnumber1 );
|
||||
discnumber2 = qMax( 1, (int)discnumber2 );
|
||||
|
||||
if ( albumpos1 == 0 && !p1->result().isNull() )
|
||||
albumpos1 = p1->result()->albumpos();
|
||||
if ( discnumber1 == 0 && !p1->result().isNull() )
|
||||
discnumber1 = p1->result()->discnumber();
|
||||
|
||||
if ( albumpos2 == 0 && !p2->result().isNull() )
|
||||
albumpos2 = p2->result()->albumpos();
|
||||
if ( discnumber2 == 0 && !p2->result().isNull() )
|
||||
discnumber2 = p2->result()->discnumber();
|
||||
|
||||
const QString& lefts = textForItem( p1 );
|
||||
const QString& rights = textForItem( p2 );
|
||||
|
||||
if( discnumber1 != discnumber2 )
|
||||
if ( discnumber1 != discnumber2 )
|
||||
{
|
||||
return discnumber1 < discnumber2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( albumpos1 != albumpos2 )
|
||||
return albumpos1 < albumpos2;
|
||||
}
|
||||
|
||||
const QString& lefts = textForItem( p1 );
|
||||
const QString& rights = textForItem( p2 );
|
||||
if ( lefts == rights )
|
||||
return (qint64)&p1 < (qint64)&p2;
|
||||
|
||||
|
@@ -44,7 +44,7 @@ Query::get( const QString& artist, const QString& track, const QString& album, c
|
||||
if ( qid.isEmpty() )
|
||||
autoResolve = false;
|
||||
|
||||
query_ptr q = query_ptr( new Query( artist, track, album, qid, autoResolve ) );
|
||||
query_ptr q = query_ptr( new Query( artist, track, album, qid, autoResolve ), &QObject::deleteLater );
|
||||
q->setWeakRef( q.toWeakRef() );
|
||||
|
||||
if ( autoResolve )
|
||||
@@ -58,7 +58,7 @@ query_ptr
|
||||
Query::get( const QString& query, const QID& qid )
|
||||
{
|
||||
|
||||
query_ptr q = query_ptr( new Query( query, qid ) );
|
||||
query_ptr q = query_ptr( new Query( query, qid ), &QObject::deleteLater );
|
||||
q->setWeakRef( q.toWeakRef() );
|
||||
|
||||
if ( !qid.isEmpty() )
|
||||
@@ -106,6 +106,7 @@ Query::~Query()
|
||||
{
|
||||
QMutexLocker lock( &m_mutex );
|
||||
m_ownRef.clear();
|
||||
m_results.clear();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -392,10 +392,13 @@ QtScriptResolver::parseResultVariantList( const QVariantList& reslist )
|
||||
rp->setArtist( ap );
|
||||
rp->setAlbum( Tomahawk::Album::get( ap, m.value( "album" ).toString(), false ) );
|
||||
rp->setTrack( m.value( "track" ).toString() );
|
||||
rp->setAlbumPos( m.value( "albumpos" ).toUInt() );
|
||||
rp->setBitrate( m.value( "bitrate" ).toUInt() );
|
||||
rp->setSize( m.value( "size" ).toUInt() );
|
||||
rp->setRID( uuid() );
|
||||
rp->setFriendlySource( name() );
|
||||
rp->setScore( m.value( "score" ).toFloat() );
|
||||
rp->setDiscNumber( m.value( "discnumber" ).toUInt() );
|
||||
|
||||
if ( m.contains( "year" ) )
|
||||
{
|
||||
|
@@ -41,6 +41,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;
|
||||
@@ -61,9 +62,10 @@ ScriptResolver::ScriptResolver( const QString& exe )
|
||||
ScriptResolver::~ScriptResolver()
|
||||
{
|
||||
disconnect( &m_proc, SIGNAL( finished( int, QProcess::ExitStatus ) ), this, SLOT( cmdExited( int, QProcess::ExitStatus ) ) );
|
||||
m_deleting = true;
|
||||
|
||||
m_proc.kill();
|
||||
m_proc.waitForFinished();
|
||||
m_proc.waitForFinished(); // might call handleMsg
|
||||
|
||||
Tomahawk::Pipeline::instance()->removeResolver( this );
|
||||
|
||||
@@ -207,6 +209,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 )
|
||||
|
@@ -85,7 +85,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;
|
||||
|
@@ -43,13 +43,21 @@ Result::get( const QString& url )
|
||||
return s_results.value( url );
|
||||
}
|
||||
|
||||
result_ptr r = result_ptr( new Result( url ) );
|
||||
result_ptr r = result_ptr( new Result( url ), &Result::deleteLater );
|
||||
s_results.insert( url, r );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Result::isCached( const QString& url )
|
||||
{
|
||||
QMutexLocker lock( &s_mutex );
|
||||
return ( s_results.contains( url ) );
|
||||
}
|
||||
|
||||
|
||||
Result::Result( const QString& url )
|
||||
: QObject()
|
||||
, m_url( url )
|
||||
@@ -68,12 +76,21 @@ Result::Result( const QString& url )
|
||||
|
||||
|
||||
Result::~Result()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Result::deleteLater()
|
||||
{
|
||||
QMutexLocker lock( &s_mutex );
|
||||
|
||||
if ( s_results.contains( m_url ) )
|
||||
{
|
||||
s_results.remove( m_url );
|
||||
}
|
||||
|
||||
QObject::deleteLater();
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +187,7 @@ Result::toVariant() const
|
||||
QString
|
||||
Result::toString() const
|
||||
{
|
||||
return QString( "Result(%1 %2\t%3 - %4 %5" ).arg( id() ).arg( score() ).arg( artist()->name() ).arg( track() ).arg( url() );
|
||||
return QString( "Result(%1 %2\t%3 - %4 %5" ).arg( id() ).arg( score() ).arg( artist().isNull() ? QString() : artist()->name() ).arg( track() ).arg( url() );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -56,6 +56,7 @@ friend class ::DatabaseCommand_LoadFile;
|
||||
|
||||
public:
|
||||
static Tomahawk::result_ptr get( const QString& url );
|
||||
static bool isCached( const QString& url );
|
||||
virtual ~Result();
|
||||
|
||||
QVariant toVariant() const;
|
||||
@@ -108,6 +109,9 @@ public:
|
||||
unsigned int trackId() const { return m_trackId; }
|
||||
unsigned int fileId() const { return m_fileId; }
|
||||
|
||||
public slots:
|
||||
void deleteLater();
|
||||
|
||||
signals:
|
||||
// emitted when the collection this result comes from is going offline/online:
|
||||
void statusChanged();
|
||||
@@ -115,7 +119,7 @@ signals:
|
||||
private slots:
|
||||
void onOffline();
|
||||
void onOnline();
|
||||
|
||||
|
||||
private:
|
||||
// private constructor
|
||||
explicit Result( const QString& url );
|
||||
|
89
src/libtomahawk/utils/closure.cpp
Normal file
89
src/libtomahawk/utils/closure.cpp
Normal 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);
|
||||
}
|
225
src/libtomahawk/utils/closure.h
Normal file
225
src/libtomahawk/utils/closure.h
Normal 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
|
@@ -301,10 +301,11 @@ extensionToMimetype( const QString& extension )
|
||||
return s_ext2mime.value( extension, "unknown" );
|
||||
}
|
||||
|
||||
static QMutex s_noProxyHostsMutex;
|
||||
static QStringList s_noProxyHosts;
|
||||
|
||||
NetworkProxyFactory::NetworkProxyFactory( const NetworkProxyFactory& other )
|
||||
{
|
||||
m_noProxyHosts = QStringList( other.m_noProxyHosts );
|
||||
m_proxy = QNetworkProxy( other.m_proxy );
|
||||
}
|
||||
|
||||
@@ -312,13 +313,17 @@ NetworkProxyFactory::NetworkProxyFactory( const NetworkProxyFactory& other )
|
||||
QList< QNetworkProxy >
|
||||
NetworkProxyFactory::queryProxy( const QNetworkProxyQuery& query )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "query hostname is " << query.peerHostName();
|
||||
QList< QNetworkProxy > proxies;
|
||||
QString hostname = query.peerHostName();
|
||||
if ( m_proxy.hostName().isEmpty() || hostname.isEmpty() || m_noProxyHosts.contains( hostname ) || TomahawkSettings::instance()->proxyType() == QNetworkProxy::NoProxy )
|
||||
s_noProxyHostsMutex.lock();
|
||||
if ( s_noProxyHosts.contains( hostname ) )
|
||||
proxies << QNetworkProxy::NoProxy << systemProxyForQuery( query );
|
||||
else if ( m_proxy.hostName().isEmpty() || hostname.isEmpty() || TomahawkSettings::instance()->proxyType() == QNetworkProxy::NoProxy )
|
||||
proxies << systemProxyForQuery( query );
|
||||
else
|
||||
proxies << m_proxy << systemProxyForQuery( query );
|
||||
|
||||
s_noProxyHostsMutex.unlock();
|
||||
return proxies;
|
||||
}
|
||||
|
||||
@@ -335,7 +340,9 @@ NetworkProxyFactory::setNoProxyHosts( const QStringList& hosts )
|
||||
//TODO: wildcard support
|
||||
}
|
||||
tDebug() << Q_FUNC_INFO << "New no-proxy hosts:" << newList;
|
||||
m_noProxyHosts = newList;
|
||||
s_noProxyHostsMutex.lock();
|
||||
s_noProxyHosts = newList;
|
||||
s_noProxyHostsMutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -357,7 +364,6 @@ NetworkProxyFactory::operator=( const NetworkProxyFactory& rhs )
|
||||
if ( this != &rhs )
|
||||
{
|
||||
m_proxy = QNetworkProxy( rhs.m_proxy );
|
||||
m_noProxyHosts = QStringList( rhs.m_noProxyHosts );
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -367,7 +373,7 @@ NetworkProxyFactory::operator=( const NetworkProxyFactory& rhs )
|
||||
bool NetworkProxyFactory::operator==( const NetworkProxyFactory& other ) const
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
if ( m_noProxyHosts != other.m_noProxyHosts || m_proxy != other.m_proxy )
|
||||
if ( m_proxy != other.m_proxy )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -378,25 +384,29 @@ static QMap< QThread*, NetworkProxyFactory* > s_threadProxyFactoryHash;
|
||||
static QMutex s_namAccessMutex;
|
||||
|
||||
NetworkProxyFactory*
|
||||
proxyFactory( bool noMutexLocker )
|
||||
proxyFactory( bool makeClone, bool noMutexLocker )
|
||||
{
|
||||
// Don't lock if being called from nam()
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
QMutex otherMutex;
|
||||
QMutexLocker locker( noMutexLocker ? &otherMutex : &s_namAccessMutex );
|
||||
|
||||
if ( s_threadProxyFactoryHash.contains( QThread::currentThread() ) )
|
||||
return s_threadProxyFactoryHash[ QThread::currentThread() ];
|
||||
if ( !makeClone )
|
||||
{
|
||||
if ( s_threadProxyFactoryHash.contains( QThread::currentThread() ) )
|
||||
return s_threadProxyFactoryHash[ QThread::currentThread() ];
|
||||
|
||||
if ( !s_threadProxyFactoryHash.contains( TOMAHAWK_APPLICATION::instance()->thread() ) )
|
||||
return 0;
|
||||
if ( !s_threadProxyFactoryHash.contains( TOMAHAWK_APPLICATION::instance()->thread() ) )
|
||||
return 0;
|
||||
}
|
||||
|
||||
// create a new proxy factory for this thread
|
||||
TomahawkUtils::NetworkProxyFactory *mainProxyFactory = s_threadProxyFactoryHash[ TOMAHAWK_APPLICATION::instance()->thread() ];
|
||||
TomahawkUtils::NetworkProxyFactory *newProxyFactory = new TomahawkUtils::NetworkProxyFactory();
|
||||
*newProxyFactory = *mainProxyFactory;
|
||||
|
||||
s_threadProxyFactoryHash[ QThread::currentThread() ] = newProxyFactory;
|
||||
if ( !makeClone )
|
||||
s_threadProxyFactoryHash[ QThread::currentThread() ] = newProxyFactory;
|
||||
|
||||
return newProxyFactory;
|
||||
}
|
||||
@@ -455,7 +465,7 @@ nam()
|
||||
|
||||
newNam->setConfiguration( QNetworkConfiguration( mainNam->configuration() ) );
|
||||
newNam->setNetworkAccessible( mainNam->networkAccessible() );
|
||||
newNam->setProxyFactory( proxyFactory( true ) );
|
||||
newNam->setProxyFactory( proxyFactory( false, true ) );
|
||||
|
||||
s_threadNamHash[ QThread::currentThread() ] = newNam;
|
||||
|
||||
@@ -485,9 +495,15 @@ setNam( QNetworkAccessManager* nam, bool noMutexLocker )
|
||||
QNetworkProxy proxy( s->proxyType(), s->proxyHost(), s->proxyPort(), s->proxyUsername(), s->proxyPassword() );
|
||||
proxyFactory->setProxy( proxy );
|
||||
//FIXME: Jreen is broke without this
|
||||
QNetworkProxy::setApplicationProxy( proxy );
|
||||
if ( !s->proxyNoProxyHosts().isEmpty() )
|
||||
//QNetworkProxy::setApplicationProxy( proxy );
|
||||
s_noProxyHostsMutex.lock();
|
||||
if ( !s->proxyNoProxyHosts().isEmpty() && s_noProxyHosts.isEmpty() )
|
||||
{
|
||||
s_noProxyHostsMutex.unlock();
|
||||
proxyFactory->setNoProxyHosts( s->proxyNoProxyHosts().split( ',', QString::SkipEmptyParts ) );
|
||||
}
|
||||
else
|
||||
s_noProxyHostsMutex.unlock();
|
||||
}
|
||||
|
||||
nam->setProxyFactory( proxyFactory );
|
||||
|
@@ -92,7 +92,7 @@ namespace TomahawkUtils
|
||||
DLLEXPORT QString extensionToMimetype( const QString& extension );
|
||||
DLLEXPORT bool newerVersion( const QString& oldVersion, const QString& newVersion );
|
||||
|
||||
DLLEXPORT NetworkProxyFactory* proxyFactory( bool noMutexLocker = false );
|
||||
DLLEXPORT NetworkProxyFactory* proxyFactory( bool makeClone = false, bool noMutexLocker = false );
|
||||
DLLEXPORT void setProxyFactory( TomahawkUtils::NetworkProxyFactory* factory, bool noMutexLocker = false );
|
||||
DLLEXPORT QNetworkAccessManager* nam();
|
||||
DLLEXPORT void setNam( QNetworkAccessManager* nam, bool noMutexLocker = false );
|
||||
|
@@ -60,6 +60,7 @@ XSPFLoader::XSPFLoader( bool autoCreate, bool autoUpdate, QObject *parent )
|
||||
, m_autoCreate( autoCreate )
|
||||
, m_autoUpdate( autoUpdate )
|
||||
, m_autoResolve( true )
|
||||
, m_autoDelete( true )
|
||||
, m_NS("http://xspf.org/ns/0/")
|
||||
{
|
||||
qRegisterMetaType< XSPFErrorCode >("XSPFErrorCode");
|
||||
@@ -121,7 +122,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();
|
||||
}
|
||||
@@ -262,15 +267,17 @@ XSPFLoader::gotBody()
|
||||
|
||||
// 10 minute default---for now, no way to change it
|
||||
connect( m_playlist.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistCreated() ) );
|
||||
new Tomahawk::XspfUpdater( m_playlist, 6000000, m_autoUpdate, m_url.toString() );
|
||||
new Tomahawk::XspfUpdater( m_playlist, 600000, m_autoUpdate, m_url.toString() );
|
||||
emit ok( m_playlist );
|
||||
}
|
||||
else{
|
||||
else
|
||||
{
|
||||
|
||||
if( !m_entries.isEmpty() )
|
||||
emit tracks( m_entries );
|
||||
}
|
||||
|
||||
deleteLater();
|
||||
if ( m_autoDelete )
|
||||
deleteLater();
|
||||
|
||||
}
|
||||
|
@@ -48,6 +48,8 @@ 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 );
|
||||
|
||||
@@ -69,10 +71,10 @@ private:
|
||||
void reportError();
|
||||
void gotBody();
|
||||
|
||||
bool m_autoCreate, m_autoUpdate, m_autoResolve;
|
||||
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;
|
||||
|
@@ -112,7 +112,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() ) );
|
||||
@@ -537,9 +537,9 @@ ViewManager::applyFilter()
|
||||
|
||||
|
||||
void
|
||||
ViewManager::autoUpdateChanged( int state )
|
||||
ViewManager::autoUpdateChanged( bool toggled )
|
||||
{
|
||||
currentPage()->setAutoUpdate( state == Qt::Checked );
|
||||
currentPage()->setAutoUpdate( toggled );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -84,7 +84,7 @@ 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 );
|
||||
|
||||
@@ -174,7 +174,7 @@ private slots:
|
||||
void setFilter( const QString& filter );
|
||||
void applyFilter();
|
||||
|
||||
void autoUpdateChanged( int );
|
||||
void autoUpdateChanged( bool );
|
||||
|
||||
void onWidgetDestroyed( QWidget* widget );
|
||||
|
||||
@@ -185,9 +185,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;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@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
|
||||
@@ -231,7 +232,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;
|
||||
@@ -308,7 +309,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 );
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@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
|
||||
|
@@ -173,6 +173,7 @@ MusicScanner::scan()
|
||||
SLOT( commitBatch( QVariantList, QVariantList ) ), Qt::DirectConnection );
|
||||
|
||||
m_dirListerThreadController = new QThread( this );
|
||||
m_dirListerThreadController->setPriority( QThread::IdlePriority );
|
||||
|
||||
m_dirLister = QWeakPointer< DirLister >( new DirLister( m_dirs ) );
|
||||
m_dirLister.data()->moveToThread( m_dirListerThreadController );
|
||||
|
@@ -139,7 +139,8 @@
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>No Proxy Hosts:</string>
|
||||
<string>No Proxy Hosts:
|
||||
(Overrides system proxy)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@@ -195,6 +195,7 @@ ScanManager::runDirScan()
|
||||
{
|
||||
m_scanTimer->stop();
|
||||
m_musicScannerThreadController = new QThread( this );
|
||||
m_musicScannerThreadController->setPriority( QThread::IdlePriority );
|
||||
m_scanner = QWeakPointer< MusicScanner >( new MusicScanner( paths ) );
|
||||
m_scanner.data()->moveToThread( m_musicScannerThreadController );
|
||||
connect( m_scanner.data(), SIGNAL( finished() ), SLOT( scannerFinished() ) );
|
||||
|
@@ -22,13 +22,13 @@
|
||||
|
||||
#include "utils/tomahawkutilsgui.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkConfiguration>
|
||||
#include <QNetworkProxy>
|
||||
#include <QVBoxLayout>
|
||||
#include <QSizeGrip>
|
||||
#include <QtGui/QDesktopServices>
|
||||
#include <QtGui/QFileDialog>
|
||||
#include <QtGui/QMessageBox>
|
||||
#include <QtNetwork/QNetworkConfiguration>
|
||||
#include <QtNetwork/QNetworkProxy>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QSizeGrip>
|
||||
|
||||
#ifdef LIBLASTFM_FOUND
|
||||
#include <lastfm/ws.h>
|
||||
@@ -859,7 +859,6 @@ ProxyDialog::ProxyDialog( QWidget *parent )
|
||||
ui->userLineEdit->setEnabled( false );
|
||||
ui->passwordLineEdit->setEnabled( false );
|
||||
ui->checkBoxUseProxyForDns->setEnabled( false );
|
||||
ui->noHostLineEdit->setEnabled( false );
|
||||
}
|
||||
|
||||
connect( ui->typeBox, SIGNAL( currentIndexChanged( int ) ), SLOT( proxyTypeChangedSlot( int ) ) );
|
||||
@@ -876,7 +875,6 @@ ProxyDialog::proxyTypeChangedSlot( int index )
|
||||
ui->userLineEdit->setEnabled( false );
|
||||
ui->passwordLineEdit->setEnabled( false );
|
||||
ui->checkBoxUseProxyForDns->setEnabled( false );
|
||||
ui->noHostLineEdit->setEnabled( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -885,7 +883,6 @@ ProxyDialog::proxyTypeChangedSlot( int index )
|
||||
ui->userLineEdit->setEnabled( true );
|
||||
ui->passwordLineEdit->setEnabled( true );
|
||||
ui->checkBoxUseProxyForDns->setEnabled( true );
|
||||
ui->noHostLineEdit->setEnabled( true );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -923,8 +920,8 @@ ProxyDialog::saveSettings()
|
||||
proxyFactory->setProxy( QNetworkProxy( type, s->proxyHost(), s->proxyPort(), s->proxyUsername(), s->proxyPassword() ) );
|
||||
if ( !ui->noHostLineEdit->text().isEmpty() )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "hosts line edit is " << ui->noHostLineEdit->text();
|
||||
tDebug() << Q_FUNC_INFO << "split hosts line edit is " << ui->noHostLineEdit->text().split( ' ', QString::SkipEmptyParts );
|
||||
tDebug() << Q_FUNC_INFO << "noproxy line edit is " << ui->noHostLineEdit->text();
|
||||
tDebug() << Q_FUNC_INFO << "split noproxy line edit is " << ui->noHostLineEdit->text().split( ' ', QString::SkipEmptyParts );
|
||||
proxyFactory->setNoProxyHosts( ui->noHostLineEdit->text().split( ' ', QString::SkipEmptyParts ) );
|
||||
}
|
||||
}
|
||||
|
@@ -19,8 +19,8 @@
|
||||
#ifndef SETTINGSDIALOG_H
|
||||
#define SETTINGSDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QModelIndex>
|
||||
#include <QtGui/QDialog>
|
||||
#include <QtCore/QModelIndex>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
@@ -102,6 +102,7 @@ JabberPlugin::JabberPlugin( const QString& pluginId )
|
||||
|
||||
// general client setup
|
||||
m_client = new Jreen::Client( jid, m_currentPassword );
|
||||
m_client->setProxyFactory( TomahawkUtils::proxyFactory( true ) );
|
||||
setupClientHelper();
|
||||
|
||||
m_client->registerPayload(new TomahawkSipMessageFactory);
|
||||
|
@@ -12,15 +12,15 @@ TomahawkOAuthTwitter::TomahawkOAuthTwitter( QNetworkAccessManager *nam, QObject*
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
const QString
|
||||
TomahawkOAuthTwitter::authorizationWidget()
|
||||
{
|
||||
bool ok;
|
||||
int i = QInputDialog::getInt(0, tr( "Twitter PIN" ), tr( "After authenticating on Twitter's web site,\nenter the displayed PIN number here:" ), 0, 0, 2147483647, 1, &ok);
|
||||
if (ok)
|
||||
return i;
|
||||
const QString str = QInputDialog::getText(0, tr( "Twitter PIN" ), tr( "After authenticating on Twitter's web site,\nenter the displayed PIN number here:" ), QLineEdit::Normal, QString(), &ok);
|
||||
if ( ok && !str.isEmpty() )
|
||||
return str;
|
||||
|
||||
return 0;
|
||||
return QString();
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -16,7 +16,7 @@ public:
|
||||
~TomahawkOAuthTwitter() {}
|
||||
|
||||
protected:
|
||||
virtual int authorizationWidget();
|
||||
virtual const QString authorizationWidget();
|
||||
|
||||
private slots:
|
||||
void error();
|
||||
|
@@ -295,6 +295,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() ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -306,8 +307,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;
|
||||
|
@@ -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 )
|
||||
{
|
||||
|
@@ -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 );
|
||||
|
||||
|
@@ -78,6 +78,7 @@ public:
|
||||
|
||||
public slots:
|
||||
virtual void activate() {}
|
||||
virtual void doubleClicked() {}
|
||||
|
||||
signals:
|
||||
void updated();
|
||||
|
@@ -43,6 +43,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 );
|
||||
@@ -631,7 +632,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 );
|
||||
}
|
||||
|
@@ -43,6 +43,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 );
|
||||
@@ -72,6 +73,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;
|
||||
|
@@ -78,6 +78,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
|
||||
@@ -88,6 +89,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 );
|
||||
|
||||
@@ -96,7 +98,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 ) ) );
|
||||
|
||||
@@ -230,6 +232,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 )
|
||||
{
|
||||
|
@@ -66,6 +66,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() );
|
||||
|
@@ -644,7 +644,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>
|
||||
|
@@ -28,7 +28,6 @@
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtNetwork/QNetworkProxy>
|
||||
|
||||
#include "artist.h"
|
||||
#include "album.h"
|
||||
@@ -256,6 +255,7 @@ TomahawkApp::init()
|
||||
{
|
||||
initHTTP();
|
||||
}
|
||||
connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( initHTTP() ) );
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
if ( !s->hasScannerPaths() )
|
||||
@@ -297,6 +297,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() )
|
||||
@@ -459,15 +464,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;
|
||||
}
|
||||
|
||||
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() );
|
||||
|
||||
tLog() << "Starting HTTPd on" << m_session.listenInterface().toString() << m_session.port();
|
||||
m_session.start();
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -101,6 +101,7 @@ public slots:
|
||||
private slots:
|
||||
void initServent();
|
||||
void initSIP();
|
||||
void initHTTP();
|
||||
|
||||
void spotifyApiCheckFinished();
|
||||
|
||||
@@ -114,8 +115,6 @@ private:
|
||||
void initLocalCollection();
|
||||
void initPipeline();
|
||||
|
||||
void initHTTP();
|
||||
|
||||
QWeakPointer<Database> m_database;
|
||||
QWeakPointer<ScanManager> m_scanManager;
|
||||
QWeakPointer<AudioEngine> m_audioEngine;
|
||||
@@ -135,8 +134,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 )
|
||||
|
@@ -741,11 +741,21 @@ TomahawkWindow::setWindowTitle( const QString& title )
|
||||
void
|
||||
TomahawkWindow::showAboutTomahawk()
|
||||
{
|
||||
QMessageBox::about( this, tr( "About Tomahawk" ),
|
||||
tr( "<h2><b>Tomahawk %1<br/>(%2)</h2>Copyright 2010 - 2012<br/>Christian Muehlhaeuser <muesli@tomahawk-player.org><br/><br/>"
|
||||
"Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindström, Michael Zanetti, Harald Sitter and Steve Robertson" )
|
||||
.arg( TomahawkUtils::appFriendlyVersion() )
|
||||
.arg( qApp->applicationVersion() ) );
|
||||
QString head, desc;
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
head = tr( "<h2><b>Tomahawk %1<br/>(%2)</h2>" )
|
||||
.arg( TomahawkUtils::appFriendlyVersion() )
|
||||
.arg( qApp->applicationVersion() );
|
||||
#else
|
||||
head = tr( "<h2><b>Tomahawk %1</h2>" )
|
||||
.arg( TomahawkUtils::appFriendlyVersion() );
|
||||
#endif
|
||||
|
||||
desc = tr( "Copyright 2010 - 2012<br/>Christian Muehlhaeuser <muesli@tomahawk-player.org><br/><br/>"
|
||||
"Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindström, Michael Zanetti, Harald Sitter and Steve Robertson" );
|
||||
|
||||
QMessageBox::about( this, tr( "About Tomahawk" ), head + desc );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -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];
|
||||
|
Reference in New Issue
Block a user