mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-09-18 09:51:31 +02:00
Compare commits
163 Commits
whatsnew_0
...
0.5.4
Author | SHA1 | Date | |
---|---|---|---|
|
e19423e08f | ||
|
e041ce87fc | ||
|
6eacdf808e | ||
|
b6d5c86952 | ||
|
b7fb9a03bf | ||
|
37fad49393 | ||
|
fa83fde05e | ||
|
b3b34cacbd | ||
|
d0f697cd4b | ||
|
c144a0142f | ||
|
318866d37a | ||
|
70e93faa3f | ||
|
89e21289a6 | ||
|
fe0d2d87fc | ||
|
8531ca2234 | ||
|
8d5082fe2c | ||
|
7672c7caec | ||
|
bf2139824d | ||
|
eb749b1e44 | ||
|
53226f37c2 | ||
|
20032a40b2 | ||
|
a6d1bbb91e | ||
|
f7240a5d39 | ||
|
2142a04fda | ||
|
0406b38f1c | ||
|
8e2174baf1 | ||
|
7caeaddc21 | ||
|
f4a01ec6aa | ||
|
ed81799294 | ||
|
0283d534f0 | ||
|
4a00ff4d24 | ||
|
b98c535247 | ||
|
fbcffed27b | ||
|
e521150d33 | ||
|
2a0aa602b6 | ||
|
cf37aae430 | ||
|
292f395c47 | ||
|
047f3cc2d4 | ||
|
97681ace31 | ||
|
6be5257bc0 | ||
|
8cfbe1f38b | ||
|
8db8e42ec4 | ||
|
9492055fc6 | ||
|
3dc624858b | ||
|
f154c2bbcd | ||
|
e9127ae3ec | ||
|
c7d9d8e5b7 | ||
|
e525291213 | ||
|
44269ee8f6 | ||
|
53c4a2d675 | ||
|
ebfc53e009 | ||
|
190845a86e | ||
|
25af4f4275 | ||
|
bca64a70ed | ||
|
10462ee257 | ||
|
ba4532593b | ||
|
c84fd28dd2 | ||
|
dbbb491a81 | ||
|
bab5e27673 | ||
|
17f71bd366 | ||
|
e96bbc11e1 | ||
|
d492ba0317 | ||
|
b6466a6027 | ||
|
6b5d391cde | ||
|
0680dec5df | ||
|
a4e8f4216c | ||
|
355c95e068 | ||
|
da07361ec0 | ||
|
aafe8797ad | ||
|
95343ca024 | ||
|
f85bcc1c64 | ||
|
e53e51aefc | ||
|
d22b33bc50 | ||
|
c36414bb4c | ||
|
a78349f9f1 | ||
|
fa41b96260 | ||
|
7f2bf85663 | ||
|
85fe824df3 | ||
|
c37bbb4deb | ||
|
1a9bf84ab4 | ||
|
a283ea1ed0 | ||
|
d27dd0785a | ||
|
5e1f808d28 | ||
|
aba78c7a24 | ||
|
f45e92a24d | ||
|
5ae04043d4 | ||
|
5f521a6cf5 | ||
|
a4b30dcecd | ||
|
700394a054 | ||
|
819ee17b74 | ||
|
79c55f1699 | ||
|
f42696de23 | ||
|
adfaf5ce53 | ||
|
32aca98a97 | ||
|
294809debb | ||
|
e4593079f3 | ||
|
cfa4210854 | ||
|
91084885fb | ||
|
0b7f420bef | ||
|
046237f009 | ||
|
85d9755a47 | ||
|
98bd7b1857 | ||
|
37510fc2d7 | ||
|
a91ad7dd5f | ||
|
2cc85c8f4f | ||
|
19625fffd4 | ||
|
a98cab55b7 | ||
|
ec7b98e589 | ||
|
1262dcb60a | ||
|
fc9c6e6017 | ||
|
fa4463dc88 | ||
|
3fb403c695 | ||
|
fdb1d1b621 | ||
|
127da50144 | ||
|
5640923d51 | ||
|
4a2ef91638 | ||
|
012556ca0a | ||
|
8d0a51cc64 | ||
|
253120a35c | ||
|
671bd5361b | ||
|
3dc969a31f | ||
|
64a70f5073 | ||
|
1911d4b8a0 | ||
|
92229ce3e2 | ||
|
7df3f867ea | ||
|
6e66c4a192 | ||
|
49fe0f945e | ||
|
0d915513b9 | ||
|
6c69edd0e7 | ||
|
23c2c77869 | ||
|
cd7c64ac0a | ||
|
0637ee7338 | ||
|
7765aa116b | ||
|
c46ed53930 | ||
|
22105d448a | ||
|
4f4efdfbab | ||
|
686730e27c | ||
|
fdfe4d12d4 | ||
|
669e7550f2 | ||
|
d4a2294963 | ||
|
66b0ecc846 | ||
|
c3563a2449 | ||
|
05efe29a67 | ||
|
3480690479 | ||
|
a1fb66e024 | ||
|
02e9f99ce4 | ||
|
95c74fe370 | ||
|
358226bdb1 | ||
|
a2d81d0099 | ||
|
292e97fcee | ||
|
6dafcf3c80 | ||
|
ee1b13aee6 | ||
|
ce8eecd40f | ||
|
f674b3b751 | ||
|
44cd64a8b6 | ||
|
a9418fc8aa | ||
|
44546763b9 | ||
|
66a74ad6e2 | ||
|
6aae2dd96f | ||
|
ffd2cee2ff | ||
|
438f8444c3 | ||
|
b55be311b4 | ||
|
7a4d113af6 |
@@ -13,7 +13,7 @@ SET( TOMAHAWK_DESCRIPTION_SUMMARY "The social media player" )
|
||||
|
||||
SET( TOMAHAWK_VERSION_MAJOR 0 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 5 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 0 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 4 )
|
||||
|
||||
#SET( TOMAHAWK_VERSION_RC 0 )
|
||||
|
||||
@@ -35,8 +35,11 @@ IF( CMAKE_SYSTEM_PROCESSOR MATCHES "arm" )
|
||||
ENDIF()
|
||||
|
||||
# add definitions based on build options
|
||||
IF(WITH_BREAKPAD)
|
||||
IF( WITH_BREAKPAD )
|
||||
message(STATUS "Build with support for breakpad.")
|
||||
IF( CMAKE_COMPILER_IS_GNUCXX )
|
||||
ADD_DEFINITIONS( -DSTDC_HEADERS -std=gnu++98 )
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
# generate version string
|
||||
@@ -157,8 +160,8 @@ SET( LIBPORTFWD_LIBRARIES ${LIBPORTFWD_LIBRARY} )
|
||||
ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/libportfwd )
|
||||
|
||||
# we need pthreads too
|
||||
#macro_optional_find_package(Threads)
|
||||
#macro_log_feature(THREADS_FOUND "Threads" "Threading Library" "" TRUE "" "Platform specific library for threading")
|
||||
macro_optional_find_package(Threads)
|
||||
macro_log_feature(THREADS_FOUND "Threads" "Threading Library" "" TRUE "" "Platform specific library for threading")
|
||||
|
||||
macro_optional_find_package(KDE4)
|
||||
macro_optional_find_package(KDE4Installed)
|
||||
|
31
ChangeLog
31
ChangeLog
@@ -1,3 +1,26 @@
|
||||
Version 0.5.4:
|
||||
* Improved stability.
|
||||
* Added support for Spotify album lookups.
|
||||
* Fixed not always updating the database index after scanning.
|
||||
* Fixed connection issue between Tomahawk peers.
|
||||
|
||||
Version 0.5.3:
|
||||
* Fixed broken artist names when importing Last.fm playback history.
|
||||
* Fixed crash when filtering collections.
|
||||
|
||||
Version 0.5.2:
|
||||
* Fixed a crash when invalid results are coming back from a resolver or
|
||||
are found in a playlist.
|
||||
|
||||
Version 0.5.1:
|
||||
* Fixed a few issues with automatic downloading and launching
|
||||
of the Spotify account.
|
||||
* Show an error message when not able to resolve a requested song.
|
||||
* Fixed a few crash and freeze issues.
|
||||
* Better detection of local networks for the Local Network connector.
|
||||
* Don't prompt for access permission for your own accounts.
|
||||
* (OS X) Fixed not being able to connect to Last.fm.
|
||||
|
||||
Version 0.5.0:
|
||||
* SOCKS5 proxy support improvements for resolvers and more.
|
||||
* Initial Access Control support, allowing users to define who is able to
|
||||
@@ -52,7 +75,7 @@ Version 0.4.0:
|
||||
* 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.
|
||||
* 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.
|
||||
@@ -77,7 +100,7 @@ Version 0.4.0:
|
||||
* 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
|
||||
information is available.
|
||||
@@ -89,7 +112,7 @@ Version 0.3.3:
|
||||
* Fixed dupe menu entry appearing on OS X.
|
||||
* Fixed invisible sidebar items on Linux.
|
||||
|
||||
Version 0.3.2:
|
||||
Version 0.3.2:
|
||||
* Improved syncing process, it's faster and more reliable now.
|
||||
* Fixed UPnP issues.
|
||||
* Fixed not updating collections and views after a collection changes.
|
||||
@@ -143,7 +166,7 @@ Version 0.3.0:
|
||||
* Added YouTube resolver.
|
||||
* Fixed bug where going offline then online would not re-connect to many
|
||||
peers.
|
||||
* Added support for auto-updating live XSPF playlists.
|
||||
* Added support for auto-updating live XSPF playlists.
|
||||
* Don't show an age of 41 years for tracks that have no age information.
|
||||
* Show config UI for resolvers that have them as soon as you add them.
|
||||
* Add support for Echo Nest Personal Catalogs and User Radio. Synchronize
|
||||
|
@@ -28,9 +28,6 @@ FRAMEWORK_SEARCH_PATH=[
|
||||
|
||||
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Cellar/gettext/0.18.1.1/lib', '.']
|
||||
|
||||
LIBSPOTIFY_VERSION = commands.getoutput("brew ls -version libspotify | tr -s \" \" \"\\\\012\" | tail -n 1").strip()
|
||||
LIBSPOTIFY_PATH = "/usr/local/lib/libspotify.%s.dylib" % LIBSPOTIFY_VERSION
|
||||
|
||||
VLC_PLUGINS=[
|
||||
'libaccess_attachment_plugin.dylib',
|
||||
#'libaccess_avio_plugin.dylib',
|
||||
@@ -512,11 +509,6 @@ try:
|
||||
except:
|
||||
print 'Failed to find tomahawk_crash_reporter'
|
||||
|
||||
try:
|
||||
FixPlugin(LIBSPOTIFY_PATH, "../Frameworks")
|
||||
except:
|
||||
print "Failed to copy libspotify from os: %s" % LIBSPOTIFY_PATH
|
||||
|
||||
for plugin in QT_PLUGINS:
|
||||
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -85,7 +85,7 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
ui->socialButton->setPixmap( RESPATH "images/share.png" );
|
||||
ui->loveButton->setPixmap( RESPATH "images/not-loved.png" );
|
||||
ui->loveButton->setCheckable( true );
|
||||
|
||||
|
||||
ui->socialButton->setFixedSize( QSize( 20, 20 ) );
|
||||
ui->loveButton->setFixedSize( QSize( 20, 20 ) );
|
||||
|
||||
@@ -352,7 +352,7 @@ AudioControls::onPlaybackStopped()
|
||||
ui->ownerLabel->setText( "" );
|
||||
ui->timeLabel->setText( "" );
|
||||
ui->timeLeftLabel->setText( "" );
|
||||
ui->coverImage->setPixmap( QPixmap(), true );
|
||||
ui->coverImage->setPixmap( QPixmap(), false );
|
||||
ui->seekSlider->setVisible( false );
|
||||
m_sliderTimeLine.stop();
|
||||
m_sliderTimeLine.setCurrentTime( 0 );
|
||||
@@ -588,7 +588,7 @@ AudioControls::droppedTracks( QList< query_ptr > tracks )
|
||||
{
|
||||
// queue and play the first no matter what
|
||||
GlobalActionManager::instance()->handlePlayTrack( tracks.first() );
|
||||
ViewManager::instance()->queue()->model()->append( tracks );
|
||||
ViewManager::instance()->queue()->model()->appendQueries( tracks );
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -129,6 +129,8 @@ IF( UNIX )
|
||||
ENDIF( UNIX )
|
||||
|
||||
IF( APPLE )
|
||||
SET( CMAKE_LINKER_FLAGS "-headerpad_max_install_names ${CMAKE_LINKER_FLAGS}" )
|
||||
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/thirdparty/SPMediaKeyTap )
|
||||
|
||||
SET( tomahawkSources ${tomahawkSources} mac/TomahawkApp_Mac.mm mac/MacShortcutHandler.cpp )
|
||||
|
@@ -22,10 +22,6 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "accounts/AccountManager.h"
|
||||
#include "network/Servent.h"
|
||||
#include "SourceList.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QTextEdit>
|
||||
#include <QDialogButtonBox>
|
||||
@@ -34,8 +30,13 @@
|
||||
#include <QClipboard>
|
||||
#include <QDebug>
|
||||
|
||||
#include "utils/Logger.h"
|
||||
#include "accounts/AccountManager.h"
|
||||
#include "network/Servent.h"
|
||||
#include "SourceList.h"
|
||||
|
||||
#include "sip/SipHandler.h"
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
|
||||
DiagnosticsDialog::DiagnosticsDialog( QWidget *parent )
|
||||
@@ -44,11 +45,10 @@ DiagnosticsDialog::DiagnosticsDialog( QWidget *parent )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
|
||||
connect( ui->clipboardButton, SIGNAL( clicked() ), this, SLOT( copyToClipboard() ) );
|
||||
connect( ui->buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
|
||||
connect( ui->clipboardButton, SIGNAL( clicked() ), SLOT( copyToClipboard() ) );
|
||||
connect( ui->logfileButton, SIGNAL( clicked() ), SLOT( openLogfile() ) );
|
||||
connect( ui->buttonBox, SIGNAL( rejected() ), SLOT( reject() ) );
|
||||
|
||||
ui->scrollAreaWidgetContents->setLayout( new QVBoxLayout() );
|
||||
|
||||
updateLogView();
|
||||
}
|
||||
|
||||
@@ -58,16 +58,10 @@ DiagnosticsDialog::updateLogView()
|
||||
{
|
||||
QString log;
|
||||
|
||||
log.append(
|
||||
QString("TOMAHAWK DIAGNOSTICS LOG -%1 \n\n")
|
||||
.arg( QDateTime::currentDateTime().toString() )
|
||||
);
|
||||
|
||||
// network
|
||||
log.append( QString( "TOMAHAWK DIAGNOSTICS LOG -%1 \n\n" ).arg( QDateTime::currentDateTime().toString() ) );
|
||||
log.append( "TOMAHAWK-VERSION: " TOMAHAWK_VERSION "\n\n" );
|
||||
|
||||
// network
|
||||
log.append( "NETWORK:\n General:\n" );
|
||||
|
||||
if ( Servent::instance()->visibleExternally() )
|
||||
{
|
||||
log.append(
|
||||
@@ -86,10 +80,8 @@ DiagnosticsDialog::updateLogView()
|
||||
log.append( " visible: false" );
|
||||
}
|
||||
|
||||
ui->scrollAreaWidgetContents->layout()->addWidget( new QLabel( log, this ) );
|
||||
// Peers / Accounts, TODO
|
||||
ui->scrollAreaWidgetContents->layout()->addWidget( new QLabel( "ACCOUNTS:\n", this ) );
|
||||
|
||||
log.append( "ACCOUNTS:\n" );
|
||||
|
||||
const QList< Tomahawk::source_ptr > sources = SourceList::instance()->sources( true );
|
||||
const QList< Tomahawk::Accounts::Account* > accounts = Tomahawk::Accounts::AccountManager::instance()->accounts( Tomahawk::Accounts::SipType );
|
||||
foreach ( Tomahawk::Accounts::Account* account, accounts )
|
||||
@@ -98,165 +90,98 @@ DiagnosticsDialog::updateLogView()
|
||||
if ( !account || !account->sipPlugin() )
|
||||
continue;
|
||||
|
||||
connect( account, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ),
|
||||
SLOT( onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ) );
|
||||
connect( account, SIGNAL( error( int, QString ) ),
|
||||
SLOT( onAccountError( int, QString ) ) );
|
||||
connect( account, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
|
||||
connect( account, SIGNAL( error( int, QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
|
||||
connect( account->sipPlugin(), SIGNAL( peerOnline( QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
|
||||
connect( account->sipPlugin(), SIGNAL( peerOffline( QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
|
||||
connect( account->sipPlugin(), SIGNAL( sipInfoReceived( QString, SipInfo ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
|
||||
connect( account->sipPlugin(), SIGNAL( softwareVersionReceived( QString, QString ) ), SLOT( updateLogView() ), Qt::UniqueConnection );
|
||||
|
||||
connect( account->sipPlugin(), SIGNAL( peerOnline( QString ) ), SLOT( onPeerOnline( QString ) ) );
|
||||
connect( account->sipPlugin(), SIGNAL( peerOffline( QString ) ), SLOT( onPeerOffline( QString ) ) );
|
||||
connect( account->sipPlugin(), SIGNAL( sipInfoReceived( QString, SipInfo ) ), SLOT( onSipInfoReceived( QString, SipInfo ) ) );
|
||||
connect( account->sipPlugin(), SIGNAL( softwareVersionReceived( QString, QString ) ), SLOT( onSoftwareVersionReceived( QString, QString ) ) );
|
||||
|
||||
QLabel* accountInfoLabel = new QLabel( this );
|
||||
ui->scrollAreaWidgetContents->layout()->addWidget( accountInfoLabel );
|
||||
m_accountDescriptionStore.insert( account, accountInfoLabel );
|
||||
|
||||
updateAccountLabel( account );
|
||||
log.append( accountLog( account ) + "\n" );
|
||||
}
|
||||
|
||||
ui->text->setText( log );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DiagnosticsDialog::copyToClipboard()
|
||||
{
|
||||
QString log;
|
||||
foreach ( QLabel* label, m_accountDescriptionStore.values() )
|
||||
QApplication::clipboard()->setText( ui->text->toPlainText() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DiagnosticsDialog::openLogfile()
|
||||
{
|
||||
TomahawkUtils::openUrl( Logger::logFile() );
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
DiagnosticsDialog::accountLog( Tomahawk::Accounts::Account* account )
|
||||
{
|
||||
QString accountInfo;
|
||||
QString stateString;
|
||||
switch( account->connectionState() )
|
||||
{
|
||||
log += label->text() + "\n\n";
|
||||
case Tomahawk::Accounts::Account::Connecting:
|
||||
stateString = "Connecting";
|
||||
break;
|
||||
case Tomahawk::Accounts::Account::Connected:
|
||||
stateString = "Connected";
|
||||
break;
|
||||
|
||||
case Tomahawk::Accounts::Account::Disconnected:
|
||||
stateString = "Disconnected";
|
||||
break;
|
||||
case Tomahawk::Accounts::Account::Disconnecting:
|
||||
stateString = "Disconnecting";
|
||||
}
|
||||
accountInfo.append(
|
||||
QString( " %2 (%1): %3 (%4)\n" )
|
||||
.arg( account->accountServiceName() )
|
||||
.arg( account->sipPlugin()->friendlyName() )
|
||||
.arg( account->accountFriendlyName())
|
||||
.arg( stateString )
|
||||
);
|
||||
|
||||
QApplication::clipboard()->setText( log );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DiagnosticsDialog::onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState /* state */ )
|
||||
{
|
||||
Tomahawk::Accounts::Account* account = qobject_cast< Tomahawk::Accounts::Account* >( sender() );
|
||||
Q_ASSERT( account );
|
||||
|
||||
updateAccountLabel( account );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DiagnosticsDialog::onAccountError( int /* errorId */ , QString /* errorString */ )
|
||||
{
|
||||
Tomahawk::Accounts::Account* account = qobject_cast< Tomahawk::Accounts::Account* >( sender() );
|
||||
Q_ASSERT( account );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DiagnosticsDialog::onPeerOnline( const QString& )
|
||||
{
|
||||
Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account();
|
||||
Q_ASSERT( account );
|
||||
|
||||
updateAccountLabel( account );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DiagnosticsDialog::onPeerOffline( const QString& )
|
||||
{
|
||||
Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account();
|
||||
Q_ASSERT( account );
|
||||
|
||||
updateAccountLabel( account );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DiagnosticsDialog::onSipInfoReceived( const QString& /* peerId */ , const SipInfo& /* info */ )
|
||||
{
|
||||
Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account();
|
||||
Q_ASSERT( account );
|
||||
|
||||
updateAccountLabel( account );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DiagnosticsDialog::onSoftwareVersionReceived( const QString& /* peerId */ , const QString& /* versionString */ )
|
||||
{
|
||||
Tomahawk::Accounts::Account* account = qobject_cast< SipPlugin* >( sender() )->account();
|
||||
Q_ASSERT( account );
|
||||
|
||||
updateAccountLabel( account );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DiagnosticsDialog::updateAccountLabel( Tomahawk::Accounts::Account* account )
|
||||
{
|
||||
QLabel* accountInfoLabel = m_accountDescriptionStore.value( account );
|
||||
|
||||
if ( accountInfoLabel )
|
||||
foreach( const QString& peerId, account->sipPlugin()->peersOnline() )
|
||||
{
|
||||
QString accountInfo;
|
||||
QString stateString;
|
||||
switch( account->connectionState() )
|
||||
QString versionString = SipHandler::instance()->versionString( peerId );
|
||||
SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId );
|
||||
if ( !sipInfo.isValid() )
|
||||
{
|
||||
case Tomahawk::Accounts::Account::Connecting:
|
||||
stateString = "Connecting";
|
||||
break;
|
||||
case Tomahawk::Accounts::Account::Connected:
|
||||
stateString = "Connected";
|
||||
break;
|
||||
|
||||
case Tomahawk::Accounts::Account::Disconnected:
|
||||
stateString = "Disconnected";
|
||||
break;
|
||||
case Tomahawk::Accounts::Account::Disconnecting:
|
||||
stateString = "Disconnecting";
|
||||
accountInfo.append(
|
||||
QString(" %1: %2 %3" /*"(%4)"*/ "\n")
|
||||
.arg( peerId )
|
||||
.arg( "sipinfo invalid" )
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
);
|
||||
}
|
||||
accountInfo.append(
|
||||
QString( " %2 (%1): %3 (%4)\n" )
|
||||
.arg( account->accountServiceName() )
|
||||
.arg( account->sipPlugin()->friendlyName() )
|
||||
.arg( account->accountFriendlyName())
|
||||
.arg( stateString )
|
||||
);
|
||||
|
||||
foreach( const QString& peerId, account->sipPlugin()->peersOnline() )
|
||||
else if ( sipInfo.isVisible() )
|
||||
{
|
||||
QString versionString = SipHandler::instance()->versionString( peerId );
|
||||
SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId );
|
||||
if ( !sipInfo.isValid() )
|
||||
{
|
||||
accountInfo.append(
|
||||
QString(" %1: %2 %3" /*"(%4)"*/ "\n")
|
||||
.arg( peerId )
|
||||
.arg( "sipinfo invalid" )
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
);
|
||||
}
|
||||
else if ( sipInfo.isVisible() )
|
||||
{
|
||||
accountInfo.append(
|
||||
QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n")
|
||||
.arg( peerId )
|
||||
.arg( sipInfo.host().hostName() )
|
||||
.arg( sipInfo.port() )
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
accountInfo.append(
|
||||
QString(" %1: visible: false %2" /*" (%3)"*/ "\n")
|
||||
.arg( peerId )
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
);
|
||||
}
|
||||
accountInfo.append(
|
||||
QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n")
|
||||
.arg( peerId )
|
||||
.arg( sipInfo.host() )
|
||||
.arg( sipInfo.port() )
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
accountInfo.append(
|
||||
QString(" %1: visible: false %2" /*" (%3)"*/ "\n")
|
||||
.arg( peerId )
|
||||
.arg( versionString )
|
||||
// .arg( connected ? "connected" : "not connected")
|
||||
);
|
||||
}
|
||||
accountInfo.append( "\n" );
|
||||
|
||||
accountInfoLabel->setText( accountInfo );
|
||||
}
|
||||
accountInfo.append( "\n" );
|
||||
|
||||
return accountInfo;
|
||||
}
|
@@ -45,19 +45,11 @@ public:
|
||||
private slots:
|
||||
void updateLogView();
|
||||
void copyToClipboard();
|
||||
|
||||
void onAccountConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState state );
|
||||
void onAccountError( int errorId, QString errorString );
|
||||
void onPeerOnline( const QString& );
|
||||
void onPeerOffline( const QString& );
|
||||
void onSipInfoReceived( const QString& peerId, const SipInfo& info );
|
||||
void onSoftwareVersionReceived( const QString& peerId, const QString& versionString );
|
||||
void openLogfile();
|
||||
|
||||
QString accountLog( Tomahawk::Accounts::Account* );
|
||||
|
||||
void updateAccountLabel( Tomahawk::Accounts::Account* );
|
||||
private:
|
||||
|
||||
QMap< Tomahawk::Accounts::Account*, QLabel* > m_accountDescriptionStore;
|
||||
|
||||
Ui::DiagnosticsDialog* ui;
|
||||
};
|
||||
|
||||
|
@@ -26,20 +26,10 @@
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
<widget class="QTextBrowser" name="text">
|
||||
<property name="lineWrapMode">
|
||||
<enum>QTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>708</width>
|
||||
<height>386</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -49,7 +39,14 @@
|
||||
<item>
|
||||
<widget class="QPushButton" name="clipboardButton">
|
||||
<property name="text">
|
||||
<string>Copy to Clipboard</string>
|
||||
<string>&Copy to Clipboard</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="logfileButton">
|
||||
<property name="text">
|
||||
<string>Open &Log-file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@@ -208,6 +208,7 @@ MusicScanner::listerFinished()
|
||||
|
||||
if ( m_filesToDelete.length() || m_scannedfiles.length() )
|
||||
{
|
||||
SourceList::instance()->getLocal()->updateIndexWhenSynced();
|
||||
commitBatch( m_scannedfiles, m_filesToDelete );
|
||||
m_scannedfiles.clear();
|
||||
m_filesToDelete.clear();
|
||||
@@ -335,7 +336,7 @@ MusicScanner::readFile( const QFileInfo& fi )
|
||||
|
||||
int bitrate = 0;
|
||||
int duration = 0;
|
||||
|
||||
|
||||
Tag *tag = Tag::fromFile( f );
|
||||
if ( f.audioProperties() )
|
||||
{
|
||||
|
@@ -200,7 +200,7 @@ TomahawkApp::init()
|
||||
QFontMetrics fm( f );
|
||||
TomahawkUtils::setHeaderHeight( fm.height() + 8 );
|
||||
#endif
|
||||
|
||||
|
||||
TomahawkUtils::setHeadless( m_headless );
|
||||
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
@@ -210,11 +210,18 @@ TomahawkApp::init()
|
||||
Q_UNUSED( TomahawkUtils::nam() );
|
||||
|
||||
m_audioEngine = QWeakPointer<AudioEngine>( new AudioEngine );
|
||||
m_scanManager = QWeakPointer<ScanManager>( new ScanManager( this ) );
|
||||
|
||||
// init pipeline and resolver factories
|
||||
new Pipeline();
|
||||
|
||||
m_servent = QWeakPointer<Servent>( new Servent( this ) );
|
||||
connect( m_servent.data(), SIGNAL( ready() ), SLOT( initSIP() ) );
|
||||
|
||||
tDebug() << "Init Database.";
|
||||
initDatabase();
|
||||
|
||||
m_scanManager = QWeakPointer<ScanManager>( new ScanManager( this ) );
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
Pipeline::instance()->addExternalResolverFactory( boost::bind( &QtScriptResolver::factory, _1 ) );
|
||||
Pipeline::instance()->addExternalResolverFactory( boost::bind( &ScriptResolver::factory, _1 ) );
|
||||
@@ -223,12 +230,6 @@ TomahawkApp::init()
|
||||
connect( ActionCollection::instance()->getAction( "quit" ), SIGNAL( triggered() ), SLOT( quit() ), Qt::UniqueConnection );
|
||||
#endif
|
||||
|
||||
m_servent = QWeakPointer<Servent>( new Servent( this ) );
|
||||
connect( m_servent.data(), SIGNAL( ready() ), SLOT( initSIP() ) );
|
||||
|
||||
tDebug() << "Init Database.";
|
||||
initDatabase();
|
||||
|
||||
QByteArray magic = QByteArray::fromBase64( enApiSecret );
|
||||
QByteArray wand = QByteArray::fromBase64( QCoreApplication::applicationName().toLatin1() );
|
||||
int length = magic.length(), n2 = wand.length();
|
||||
@@ -359,35 +360,48 @@ TomahawkApp::~TomahawkApp()
|
||||
|
||||
if ( !m_session.isNull() )
|
||||
delete m_session.data();
|
||||
tLog() << "Deleting connector";
|
||||
if ( !m_connector.isNull() )
|
||||
delete m_connector.data();
|
||||
|
||||
tLog() << "Stopping pipeline";
|
||||
if ( Pipeline::instance() )
|
||||
Pipeline::instance()->stop();
|
||||
|
||||
tLog() << "Deleting servent";
|
||||
if ( !m_servent.isNull() )
|
||||
delete m_servent.data();
|
||||
tLog() << "Deleting ScanManager";
|
||||
if ( !m_scanManager.isNull() )
|
||||
delete m_scanManager.data();
|
||||
|
||||
tLog() << "Deleting AudioEngine";
|
||||
if ( !m_audioEngine.isNull() )
|
||||
delete m_audioEngine.data();
|
||||
|
||||
tLog() << "Deleting AccountManager";
|
||||
delete Tomahawk::Accounts::AccountManager::instance();
|
||||
delete TomahawkUtils::Cache::instance();
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
delete m_mainwindow;
|
||||
tLog() << "Deleting AtticaManager";
|
||||
delete AtticaManager::instance();
|
||||
tLog() << "Deleting Window";
|
||||
delete m_mainwindow;
|
||||
#endif
|
||||
|
||||
tLog() << "Deleting database";
|
||||
if ( !m_database.isNull() )
|
||||
delete m_database.data();
|
||||
|
||||
tLog() << "Deleting Pipeline";
|
||||
delete Pipeline::instance();
|
||||
|
||||
tLog() << "Deleting InfoSystem";
|
||||
if ( !m_infoSystem.isNull() )
|
||||
delete m_infoSystem.data();
|
||||
|
||||
tLog() << "Deleting Cache";
|
||||
delete TomahawkUtils::Cache::instance();
|
||||
|
||||
tLog() << "Finished shutdown.";
|
||||
}
|
||||
|
@@ -59,10 +59,10 @@ public slots:
|
||||
void disconnectPlugin();
|
||||
void configurationChanged();
|
||||
|
||||
void sendMsg( const QString& to, const QString& msg )
|
||||
void sendMsg( const QString& peerId, const SipInfo& info )
|
||||
{
|
||||
Q_UNUSED( to );
|
||||
Q_UNUSED( msg );
|
||||
Q_UNUSED( peerId );
|
||||
Q_UNUSED( info );
|
||||
}
|
||||
|
||||
void broadcastMsg( const QString &msg )
|
||||
@@ -70,9 +70,9 @@ public slots:
|
||||
Q_UNUSED( msg );
|
||||
}
|
||||
|
||||
void addContact( const QString &jid, const QString& msg = QString() )
|
||||
void addContact( const QString &peerId, const QString& msg = QString() )
|
||||
{
|
||||
Q_UNUSED( jid );
|
||||
Q_UNUSED( peerId );
|
||||
Q_UNUSED( msg );
|
||||
}
|
||||
|
||||
|
@@ -110,7 +110,7 @@ XmppSipPlugin::XmppSipPlugin( Account* account )
|
||||
Jreen::JID jid = Jreen::JID( readUsername() );
|
||||
|
||||
// general client setup
|
||||
m_client = new Jreen::Client( jid, m_currentPassword );
|
||||
m_client = new Jreen::Client( jid, m_currentPassword );
|
||||
setupClientHelper();
|
||||
|
||||
m_client->registerPayload( new TomahawkXmppMessageFactory );
|
||||
@@ -425,32 +425,17 @@ XmppSipPlugin::errorMessage( Jreen::Client::DisconnectReason reason )
|
||||
|
||||
|
||||
void
|
||||
XmppSipPlugin::sendMsg( const QString& to, const QString& msg )
|
||||
XmppSipPlugin::sendMsg( const QString& to, const SipInfo& info )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << to << msg;
|
||||
qDebug() << Q_FUNC_INFO << to << info;
|
||||
|
||||
if ( !m_client )
|
||||
return;
|
||||
|
||||
/*******************************************************
|
||||
* Obsolete this by a SipMessage class
|
||||
*/
|
||||
QJson::Parser parser;
|
||||
bool ok;
|
||||
QVariant v = parser.parse( msg.toAscii(), &ok );
|
||||
if ( !ok || v.type() != QVariant::Map )
|
||||
{
|
||||
qDebug() << "Invalid JSON in Xmpp msg";
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap m = v.toMap();
|
||||
/*******************************************************/
|
||||
|
||||
TomahawkXmppMessage *sipMessage;
|
||||
if ( m["visible"].toBool() )
|
||||
if ( info.isVisible() )
|
||||
{
|
||||
sipMessage = new TomahawkXmppMessage( m["ip"].toString(), m["port"].toInt(), m["uniqname"].toString(), m["key"].toString() );
|
||||
sipMessage = new TomahawkXmppMessage( info.host(), info.port(), info.uniqname(), info.key() );
|
||||
}
|
||||
else
|
||||
sipMessage = new TomahawkXmppMessage();
|
||||
@@ -467,13 +452,6 @@ XmppSipPlugin::sendMsg( const QString& to, const QString& msg )
|
||||
void
|
||||
XmppSipPlugin::broadcastMsg( const QString& msg )
|
||||
{
|
||||
if ( !m_client )
|
||||
return;
|
||||
|
||||
foreach ( const Jreen::JID& jid, m_peers.keys() )
|
||||
{
|
||||
sendMsg( jid.full(), msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -914,9 +892,7 @@ XmppSipPlugin::onNewIq( const Jreen::IQ& iq )
|
||||
info.setVisible( sipMessage->visible() );
|
||||
if ( sipMessage->visible() )
|
||||
{
|
||||
QHostInfo hi;
|
||||
hi.setHostName( sipMessage->ip() );
|
||||
info.setHost( hi );
|
||||
info.setHost( sipMessage->ip() );
|
||||
info.setPort( sipMessage->port() );
|
||||
info.setUniqname( sipMessage->uniqname() );
|
||||
info.setKey( sipMessage->key() );
|
||||
|
@@ -86,8 +86,8 @@ public slots:
|
||||
virtual void disconnectPlugin();
|
||||
virtual void checkSettings();
|
||||
virtual void configurationChanged();
|
||||
virtual void sendMsg( const QString& to, const QString& msg );
|
||||
virtual void addContact( const QString& jid, const QString& msg = QString() );
|
||||
virtual void sendMsg( const QString& peerId, const SipInfo& info );
|
||||
virtual void addContact( const QString& peerId, const QString& msg = QString() );
|
||||
|
||||
void broadcastMsg( const QString& msg );
|
||||
void showAddFriendDialog();
|
||||
|
@@ -64,7 +64,7 @@ public slots:
|
||||
|
||||
void advertise();
|
||||
|
||||
void sendMsg( const QString& , const QString& ) {}
|
||||
void sendMsg( const QString& peerId , const SipInfo& ) {}
|
||||
void broadcastMsg( const QString & ) {}
|
||||
void addContact( const QString &, const QString& ) {}
|
||||
|
||||
|
@@ -66,17 +66,17 @@ CrashReporter::CrashReporter( const QStringList& args )
|
||||
m_minidump = m_dir + '/' + args.value( 2 ) + ".dmp";
|
||||
m_product_name = args.value( 3 );
|
||||
|
||||
setFixedSize( sizeHint() );
|
||||
|
||||
//hide until "send report" has been clicked
|
||||
ui.progressBar->setVisible( false );
|
||||
ui.button->setVisible( false );
|
||||
ui.progressLabel->setVisible( false );
|
||||
connect( ui.sendButton, SIGNAL( clicked() ), SLOT( onSendButton() ));
|
||||
|
||||
connect( ui.sendButton, SIGNAL( clicked() ), SLOT( onSendButton() ) );
|
||||
|
||||
adjustSize();
|
||||
setFixedSize( size() );
|
||||
}
|
||||
|
||||
|
||||
CrashReporter::~CrashReporter()
|
||||
{
|
||||
delete m_http;
|
||||
@@ -186,6 +186,7 @@ CrashReporter::onFail( int error, const QString& errorString )
|
||||
qDebug() << "Error:" << error << errorString;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CrashReporter::onSendButton()
|
||||
{
|
||||
@@ -194,5 +195,9 @@ CrashReporter::onSendButton()
|
||||
ui.progressLabel->setVisible( true );
|
||||
ui.sendButton->setEnabled( false );
|
||||
ui.dontSendButton->setEnabled( false );
|
||||
|
||||
adjustSize();
|
||||
setFixedSize( size() );
|
||||
|
||||
QTimer::singleShot( 0, this, SLOT( send() ) );
|
||||
}
|
||||
|
@@ -9,8 +9,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>438</width>
|
||||
<height>246</height>
|
||||
<width>376</width>
|
||||
<height>216</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@@ -109,7 +109,7 @@ FdoNotifyPlugin::notifyUser( const QString &messageText )
|
||||
arguments << quint32( 0 ); //notification_id
|
||||
arguments << QString(); //app_icon
|
||||
arguments << QString( "Tomahawk" ); //summary
|
||||
arguments << messageText; //body
|
||||
arguments << QString( messageText ); //body
|
||||
arguments << QStringList(); //actions
|
||||
QVariantMap dict;
|
||||
dict["desktop-entry"] = QString( "tomahawk" );
|
||||
|
@@ -174,17 +174,21 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData,
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !output.isNull() && output.isValid() )
|
||||
if ( output.isNull() )
|
||||
{
|
||||
m_coverLoaded = true;
|
||||
}
|
||||
else if ( output.isValid() )
|
||||
{
|
||||
QVariantMap returnedData = output.value< QVariantMap >();
|
||||
const QByteArray ba = returnedData["imgbytes"].toByteArray();
|
||||
if ( ba.length() )
|
||||
{
|
||||
m_coverBuffer = ba;
|
||||
emit coverChanged();
|
||||
}
|
||||
|
||||
m_coverLoaded = true;
|
||||
emit coverChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,6 +241,6 @@ Album::infoid() const
|
||||
{
|
||||
if ( m_uuid.isEmpty() )
|
||||
m_uuid = uuid();
|
||||
|
||||
|
||||
return m_uuid;
|
||||
}
|
@@ -120,7 +120,7 @@ AlbumPlaylistInterface::tracks()
|
||||
DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( m_collection );
|
||||
cmd->setAlbum( m_album );
|
||||
cmd->setSortOrder( DatabaseCommand_AllTracks::AlbumPosition );
|
||||
|
||||
|
||||
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
|
||||
SLOT( onTracksLoaded( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
@@ -188,7 +188,7 @@ AlbumPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData re
|
||||
cmd->setAlbum( m_album );
|
||||
//this takes discnumber into account as well
|
||||
cmd->setSortOrder( DatabaseCommand_AllTracks::AlbumPosition );
|
||||
|
||||
|
||||
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
|
||||
SLOT( onTracksLoaded( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
@@ -196,6 +196,7 @@ AlbumPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData re
|
||||
}
|
||||
else
|
||||
{
|
||||
m_finished = true;
|
||||
emit tracksLoaded( m_mode, m_collection );
|
||||
}
|
||||
}
|
||||
@@ -212,5 +213,6 @@ AlbumPlaylistInterface::onTracksLoaded( const QList< query_ptr >& tracks )
|
||||
else
|
||||
m_queries << tracks;
|
||||
|
||||
m_finished = true;
|
||||
emit tracksLoaded( m_mode, m_collection );
|
||||
}
|
||||
|
@@ -315,16 +315,20 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari
|
||||
|
||||
case Tomahawk::InfoSystem::InfoArtistImages:
|
||||
{
|
||||
if ( !output.isNull() && output.isValid() )
|
||||
if ( output.isNull() )
|
||||
{
|
||||
m_coverLoaded = true;
|
||||
}
|
||||
else if ( output.isValid() )
|
||||
{
|
||||
const QByteArray ba = returnedData["imgbytes"].toByteArray();
|
||||
if ( ba.length() )
|
||||
{
|
||||
m_coverBuffer = ba;
|
||||
emit coverChanged();
|
||||
}
|
||||
|
||||
m_coverLoaded = true;
|
||||
emit coverChanged();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -353,7 +357,7 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari
|
||||
if ( source == "last.fm" )
|
||||
m_biography = bmap[ source ].toHash()[ "text" ].toString();
|
||||
}
|
||||
|
||||
|
||||
m_biographyLoaded = true;
|
||||
emit biographyLoaded();
|
||||
|
||||
@@ -459,7 +463,7 @@ Artist::playlistInterface( ModelMode mode, const Tomahawk::collection_ptr& colle
|
||||
pli = Tomahawk::playlistinterface_ptr( new Tomahawk::ArtistPlaylistInterface( this, mode, collection ) );
|
||||
connect( pli.data(), SIGNAL( tracksLoaded( Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
|
||||
SLOT( onTracksLoaded( Tomahawk::ModelMode, Tomahawk::collection_ptr ) ) );
|
||||
|
||||
|
||||
m_playlistInterface[ mode ][ collection ] = pli;
|
||||
}
|
||||
|
||||
@@ -479,6 +483,6 @@ Artist::infoid() const
|
||||
{
|
||||
if ( m_uuid.isEmpty() )
|
||||
m_uuid = uuid();
|
||||
|
||||
|
||||
return m_uuid;
|
||||
}
|
||||
|
@@ -118,7 +118,7 @@ ArtistPlaylistInterface::tracks()
|
||||
DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( m_collection );
|
||||
cmd->setArtist( m_artist );
|
||||
cmd->setSortOrder( DatabaseCommand_AllTracks::AlbumPosition );
|
||||
|
||||
|
||||
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
|
||||
SLOT( onTracksLoaded( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
@@ -186,7 +186,7 @@ ArtistPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData r
|
||||
cmd->setArtist( m_artist );
|
||||
//this takes discnumber into account as well
|
||||
cmd->setSortOrder( DatabaseCommand_AllTracks::AlbumPosition );
|
||||
|
||||
|
||||
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
|
||||
SLOT( onTracksLoaded( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
@@ -194,6 +194,7 @@ ArtistPlaylistInterface::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData r
|
||||
}
|
||||
else
|
||||
{
|
||||
m_finished = true;
|
||||
emit tracksLoaded( m_mode, m_collection );
|
||||
}
|
||||
}
|
||||
@@ -210,5 +211,6 @@ ArtistPlaylistInterface::onTracksLoaded( const QList< query_ptr >& tracks )
|
||||
else
|
||||
m_queries << tracks;
|
||||
|
||||
m_finished = true;
|
||||
emit tracksLoaded( m_mode, m_collection );
|
||||
}
|
||||
|
@@ -31,6 +31,9 @@
|
||||
#include <QTemporaryFile>
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
#include <QDomNode>
|
||||
|
||||
#include "utils/Logger.h"
|
||||
#include "accounts/ResolverAccount.h"
|
||||
@@ -64,7 +67,7 @@ AtticaManager::AtticaManager( QObject* parent )
|
||||
// resolvers
|
||||
// m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org/resolvers/providers.xml" ) );
|
||||
|
||||
const QString url = QString( "http://bakery.tomahawk-player.org/resolvers/providers.xml?version=%1" ).arg( TomahawkUtils::appFriendlyVersion() );
|
||||
const QString url = QString( "%1/resolvers/providers.xml?version=%2" ).arg( hostname() ).arg( TomahawkUtils::appFriendlyVersion() );
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( url ) ) );
|
||||
NewClosure( reply, SIGNAL( finished() ), this, SLOT( providerFetched( QNetworkReply* ) ), reply );
|
||||
connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( providerError( QNetworkReply::NetworkError ) ) );
|
||||
@@ -90,6 +93,12 @@ AtticaManager::~AtticaManager()
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
AtticaManager::hostname() const
|
||||
{
|
||||
return "http://bakery.tomahawk-player.org";
|
||||
}
|
||||
|
||||
void
|
||||
AtticaManager::loadPixmapsFromCache()
|
||||
{
|
||||
@@ -523,14 +532,15 @@ void AtticaManager::doInstallResolver( const Content& resolver, bool autoCreate,
|
||||
m_resolverStates[ resolver.id() ].version = resolver.version();
|
||||
emit resolverStateChanged( resolver.id() );
|
||||
|
||||
ItemJob< DownloadItem >* job = m_resolverProvider.downloadLink( resolver.id() );
|
||||
connect( job, SIGNAL( finished( Attica::BaseJob* ) ), this, SLOT( resolverDownloadFinished( Attica::BaseJob* ) ) );
|
||||
job->setProperty( "resolverId", resolver.id() );
|
||||
job->setProperty( "createAccount", autoCreate );
|
||||
job->setProperty( "handler", QVariant::fromValue< QObject* >( handler ) );
|
||||
job->setProperty( "binarySignature", resolver.attribute("signature"));
|
||||
|
||||
job->start();
|
||||
// ItemJob< DownloadItem >* job = m_resolverProvider.downloadLink( resolver.id() );
|
||||
QUrl url( QString( "%1/resolvers/v1/content/download/%2/1" ).arg( hostname() ).arg( resolver.id() ) );
|
||||
url.addQueryItem( "tomahawkversion", TomahawkUtils::appFriendlyVersion() );
|
||||
QNetworkReply* r = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
|
||||
NewClosure( r, SIGNAL( finished() ), this, SLOT( resolverDownloadFinished( QNetworkReply* ) ), r );
|
||||
r->setProperty( "resolverId", resolver.id() );
|
||||
r->setProperty( "createAccount", autoCreate );
|
||||
r->setProperty( "handler", QVariant::fromValue< QObject* >( handler ) );
|
||||
r->setProperty( "binarySignature", resolver.attribute("signature"));
|
||||
}
|
||||
|
||||
|
||||
@@ -552,25 +562,49 @@ AtticaManager::upgradeResolver( const Content& resolver )
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::resolverDownloadFinished ( BaseJob* j )
|
||||
AtticaManager::resolverDownloadFinished ( QNetworkReply *j )
|
||||
{
|
||||
ItemJob< DownloadItem >* job = static_cast< ItemJob< DownloadItem >* >( j );
|
||||
Q_ASSERT( j );
|
||||
if ( !j )
|
||||
return;
|
||||
|
||||
if ( job->metadata().error() == Attica::Metadata::NoError )
|
||||
if ( j->error() == QNetworkReply::NoError )
|
||||
{
|
||||
DownloadItem item = job->result();
|
||||
QUrl url = item.url();
|
||||
// download the resolver itself :)
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
|
||||
connect( reply, SIGNAL( finished() ), this, SLOT( payloadFetched() ) );
|
||||
reply->setProperty( "resolverId", job->property( "resolverId" ) );
|
||||
reply->setProperty( "createAccount", job->property( "createAccount" ) );
|
||||
reply->setProperty( "handler", job->property( "handler" ) );
|
||||
reply->setProperty( "binarySignature", job->property( "binarySignature" ) );
|
||||
QDomDocument doc;
|
||||
doc.setContent( j );
|
||||
|
||||
const QDomNodeList nodes = doc.documentElement().elementsByTagName( "downloadlink" );
|
||||
if ( nodes.length() < 1 )
|
||||
{
|
||||
tLog() << "Found no download link for resolver:" << doc.toString();
|
||||
return;
|
||||
}
|
||||
|
||||
QUrl url( nodes.item( 0 ).toElement().text() );
|
||||
// download the resolver itself :)
|
||||
tDebug() << "Downloading resolver from url:" << url.toString();
|
||||
|
||||
const QDomNodeList signatures = doc.documentElement().elementsByTagName( "signature" );
|
||||
|
||||
// Use the original signature provided
|
||||
QString signature = j->property( "binarySignature" ).toString();
|
||||
if ( signatures.size() > 0 )
|
||||
{
|
||||
// THis download has an overriding signature. Take that one instead
|
||||
const QString sig = signatures.item( 0 ).toElement().text();
|
||||
tLog() << "Found overridden signature in binary download:" << sig;
|
||||
signature = sig;
|
||||
}
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
|
||||
connect( reply, SIGNAL( finished() ), this, SLOT( payloadFetched() ) );
|
||||
reply->setProperty( "resolverId", j->property( "resolverId" ) );
|
||||
reply->setProperty( "createAccount", j->property( "createAccount" ) );
|
||||
reply->setProperty( "handler", j->property( "handler" ) );
|
||||
reply->setProperty( "binarySignature", signature );
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog() << "Failed to do resolver download job!" << job->metadata().error();
|
||||
tLog() << "Failed to do resolver download job!" << j->errorString() << j->error();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,19 +737,6 @@ AtticaManager::uninstallResolver( const Content& resolver )
|
||||
|
||||
m_resolverStates[ resolver.id() ].state = Uninstalled;
|
||||
TomahawkSettingsGui::instanceGui()->setAtticaResolverState( resolver.id(), Uninstalled );
|
||||
|
||||
// remove account as well
|
||||
QList< Tomahawk::Accounts::Account* > accounts = Tomahawk::Accounts::AccountManager::instance()->accounts( Tomahawk::Accounts::ResolverType );
|
||||
foreach ( Tomahawk::Accounts::Account* account, accounts )
|
||||
{
|
||||
if ( Tomahawk::Accounts::AtticaResolverAccount* atticaAccount = qobject_cast< Tomahawk::Accounts::AtticaResolverAccount* >( account ) )
|
||||
{
|
||||
if ( atticaAccount->atticaId() == resolver.id() ) // this is the account we want to remove
|
||||
{
|
||||
Tomahawk::Accounts::AccountManager::instance()->removeAccount( atticaAccount );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doResolverRemove( resolver.id() );
|
||||
|
@@ -132,7 +132,7 @@ private slots:
|
||||
void categoriesReturned( Attica::BaseJob* );
|
||||
void resolversList( Attica::BaseJob* );
|
||||
void binaryResolversList( Attica::BaseJob* );
|
||||
void resolverDownloadFinished( Attica::BaseJob* );
|
||||
void resolverDownloadFinished( QNetworkReply* );
|
||||
void payloadFetched();
|
||||
|
||||
void loadPixmapsFromCache();
|
||||
@@ -144,6 +144,7 @@ private slots:
|
||||
private:
|
||||
void doResolverRemove( const QString& id ) const;
|
||||
void doInstallResolver( const Attica::Content& resolver, bool autoCreate, Tomahawk::Accounts::AtticaResolverAccount* handler );
|
||||
QString hostname() const;
|
||||
|
||||
Attica::ProviderManager m_manager;
|
||||
|
||||
|
@@ -17,7 +17,6 @@ add_definitions( -DQT_SHARED )
|
||||
add_definitions( -DDLLEXPORT_PRO )
|
||||
add_definitions( -DQT_SHAREDPOINTER_TRACK_POINTERS )
|
||||
|
||||
|
||||
set( libGuiSources
|
||||
ActionCollection.cpp
|
||||
|
||||
@@ -192,6 +191,7 @@ set( libSources
|
||||
accounts/spotify/SpotifyAccount.cpp
|
||||
accounts/spotify/SpotifyAccountConfig.cpp
|
||||
accounts/spotify/SpotifyPlaylistUpdater.cpp
|
||||
accounts/spotify/SpotifyInfoPlugin.cpp
|
||||
|
||||
accounts/lastfm/LastFmAccount.cpp
|
||||
accounts/lastfm/LastFmConfig.cpp
|
||||
@@ -380,6 +380,8 @@ IF( APPLE )
|
||||
FIND_LIBRARY( SCRIPTINGBRIDGE_LIBRARY ScriptingBridge )
|
||||
MARK_AS_ADVANCED( COREAUDIO_LIBRARY COREFOUNDATION_LIBRARY FOUNDATION_LIBRARY SCRIPTINGBRIDGE_LIBRARY )
|
||||
|
||||
SET( CMAKE_SHARED_LINKER_FLAGS "-headerpad_max_install_names ${CMAKE_SHARED_LINKER_FLAGS}" )
|
||||
|
||||
SET( libSources ${libSources}
|
||||
utils/TomahawkUtils_Mac.mm
|
||||
mac/FileHelpers.mm
|
||||
|
@@ -85,9 +85,9 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
|
||||
if ( m_supportedActions & ActionStopAfter && itemCount() == 1 )
|
||||
{
|
||||
if ( AudioEngine::instance()->stopAfterTrack() == queries.first() )
|
||||
m_sigmap->setMapping( addAction( tr( "&Continue Playback after this Track" ) ), ActionStopAfter );
|
||||
m_sigmap->setMapping( addAction( tr( "Continue Playback after this &Track" ) ), ActionStopAfter );
|
||||
else
|
||||
m_sigmap->setMapping( addAction( tr( "&Stop Playback after this Track" ) ), ActionStopAfter );
|
||||
m_sigmap->setMapping( addAction( tr( "Stop Playback after this &Track" ) ), ActionStopAfter );
|
||||
}
|
||||
|
||||
addSeparator();
|
||||
@@ -122,6 +122,9 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
|
||||
void
|
||||
ContextMenu::setQuery( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
if ( query.isNull() )
|
||||
return;
|
||||
|
||||
QList<query_ptr> queries;
|
||||
queries << query;
|
||||
setQueries( queries );
|
||||
@@ -151,8 +154,8 @@ ContextMenu::setAlbums( const QList<Tomahawk::album_ptr>& albums )
|
||||
|
||||
addSeparator();
|
||||
|
||||
/* if ( m_supportedActions & ActionCopyLink && itemCount() == 1 )
|
||||
m_sigmap->setMapping( addAction( tr( "Copy Album &Link" ) ), ActionCopyLink ); */
|
||||
if ( m_supportedActions & ActionCopyLink && itemCount() == 1 )
|
||||
m_sigmap->setMapping( addAction( tr( "Copy Album &Link" ) ), ActionCopyLink );
|
||||
|
||||
foreach ( QAction* action, actions() )
|
||||
{
|
||||
@@ -193,8 +196,8 @@ ContextMenu::setArtists( const QList<Tomahawk::artist_ptr>& artists )
|
||||
|
||||
addSeparator();
|
||||
|
||||
/* if ( m_supportedActions & ActionCopyLink && itemCount() == 1 )
|
||||
m_sigmap->setMapping( addAction( tr( "Copy Artist &Link" ) ), ActionCopyLink ); */
|
||||
if ( m_supportedActions & ActionCopyLink && itemCount() == 1 )
|
||||
m_sigmap->setMapping( addAction( tr( "Copy Artist &Link" ) ), ActionCopyLink );
|
||||
|
||||
foreach ( QAction* action, actions() )
|
||||
{
|
||||
@@ -224,7 +227,7 @@ ContextMenu::onTriggered( int action )
|
||||
case ActionCopyLink:
|
||||
copyLink();
|
||||
break;
|
||||
|
||||
|
||||
case ActionPage:
|
||||
openPage();
|
||||
break;
|
||||
@@ -252,15 +255,15 @@ ContextMenu::addToQueue()
|
||||
{
|
||||
foreach ( const query_ptr& query, m_queries )
|
||||
{
|
||||
ViewManager::instance()->queue()->model()->append( query );
|
||||
ViewManager::instance()->queue()->model()->appendQuery( query );
|
||||
}
|
||||
foreach ( const artist_ptr& artist, m_artists )
|
||||
{
|
||||
ViewManager::instance()->queue()->model()->append( artist );
|
||||
ViewManager::instance()->queue()->model()->appendArtist( artist );
|
||||
}
|
||||
foreach ( const album_ptr& album, m_albums )
|
||||
{
|
||||
ViewManager::instance()->queue()->model()->append( album );
|
||||
ViewManager::instance()->queue()->model()->appendAlbum( album );
|
||||
}
|
||||
|
||||
ViewManager::instance()->showQueue();
|
||||
@@ -274,6 +277,14 @@ ContextMenu::copyLink()
|
||||
{
|
||||
GlobalActionManager::instance()->copyToClipboard( m_queries.first() );
|
||||
}
|
||||
else if ( m_albums.count() )
|
||||
{
|
||||
GlobalActionManager::instance()->copyOpenLink( m_albums.first() );
|
||||
}
|
||||
else if ( m_artists.count() )
|
||||
{
|
||||
GlobalActionManager::instance()->copyOpenLink( m_artists.first() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -298,6 +309,9 @@ ContextMenu::openPage()
|
||||
void
|
||||
ContextMenu::onSocialActionsLoaded()
|
||||
{
|
||||
if ( m_queries.isEmpty() || m_queries.first().isNull() )
|
||||
return;
|
||||
|
||||
if ( m_queries.first()->loved() )
|
||||
{
|
||||
m_loveAction->setText( tr( "Un-&Love" ) );
|
||||
|
@@ -699,8 +699,21 @@ DropJob::removeDuplicates()
|
||||
foreach ( const Tomahawk::query_ptr& item, m_resultList )
|
||||
{
|
||||
bool contains = false;
|
||||
Q_ASSERT( !item.isNull() );
|
||||
if ( item.isNull() )
|
||||
{
|
||||
m_resultList.removeOne( item );
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach( const Tomahawk::query_ptr &tmpItem, list )
|
||||
{
|
||||
if ( tmpItem.isNull() )
|
||||
{
|
||||
list.removeOne( tmpItem );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( item->album() == tmpItem->album()
|
||||
&& item->artist() == tmpItem->artist()
|
||||
&& item->track() == tmpItem->track() )
|
||||
@@ -726,10 +739,18 @@ DropJob::removeRemoteSources()
|
||||
QList< Tomahawk::query_ptr > list;
|
||||
foreach ( const Tomahawk::query_ptr& item, m_resultList )
|
||||
{
|
||||
Q_ASSERT( !item.isNull() );
|
||||
if ( item.isNull() )
|
||||
{
|
||||
m_resultList.removeOne( item );
|
||||
continue;
|
||||
}
|
||||
|
||||
bool hasLocalSource = false;
|
||||
foreach ( const Tomahawk::result_ptr& result, item->results() )
|
||||
{
|
||||
if ( !result->collection()->source().isNull() && result->collection()->source()->isLocal() )
|
||||
if ( !result->collection().isNull() && !result->collection()->source().isNull() &&
|
||||
!result->collection()->source().isNull() && result->collection()->source()->isLocal() )
|
||||
hasLocalSource = true;
|
||||
}
|
||||
if ( hasLocalSource )
|
||||
|
@@ -553,7 +553,7 @@ GlobalActionManager::handleOpenCommand( const QUrl& url )
|
||||
void
|
||||
GlobalActionManager::handleOpenTrack( const query_ptr& q )
|
||||
{
|
||||
ViewManager::instance()->queue()->model()->append( q );
|
||||
ViewManager::instance()->queue()->model()->appendQuery( q );
|
||||
ViewManager::instance()->showQueue();
|
||||
|
||||
if ( !AudioEngine::instance()->isPlaying() && !AudioEngine::instance()->isPaused() )
|
||||
@@ -570,7 +570,7 @@ GlobalActionManager::handleOpenTracks( const QList< query_ptr >& queries )
|
||||
if ( queries.isEmpty() )
|
||||
return;
|
||||
|
||||
ViewManager::instance()->queue()->model()->append( queries );
|
||||
ViewManager::instance()->queue()->model()->appendQueries( queries );
|
||||
ViewManager::instance()->showQueue();
|
||||
|
||||
if ( !AudioEngine::instance()->isPlaying() && !AudioEngine::instance()->isPaused() )
|
||||
@@ -617,16 +617,15 @@ GlobalActionManager::doQueueAdd( const QStringList& parts, const QList< QPair< Q
|
||||
{
|
||||
if ( parts.size() && parts[ 0 ] == "track" )
|
||||
{
|
||||
|
||||
if ( queueSpotify( parts, queryItems ) )
|
||||
return true;
|
||||
else if ( queueRdio( parts, queryItems ) )
|
||||
return true;
|
||||
|
||||
QPair< QString, QString > pair;
|
||||
|
||||
QString title, artist, album, urlStr;
|
||||
foreach ( pair, queryItems ) {
|
||||
foreach ( pair, queryItems )
|
||||
{
|
||||
pair.second = pair.second.replace( "+", " " ); // QUrl::queryItems doesn't decode + to a space :(
|
||||
if ( pair.first == "title" )
|
||||
title = pair.second;
|
||||
@@ -642,9 +641,12 @@ GlobalActionManager::doQueueAdd( const QStringList& parts, const QList< QPair< Q
|
||||
{
|
||||
// an individual; query to add to queue
|
||||
query_ptr q = Query::get( artist, title, album, uuid(), false );
|
||||
if ( q.isNull() )
|
||||
return false;
|
||||
|
||||
if ( !urlStr.isEmpty() )
|
||||
q->setResultHint( urlStr );
|
||||
Pipeline::instance()->resolve( q, true );
|
||||
Pipeline::instance()->resolve( q );
|
||||
|
||||
handleOpenTrack( q );
|
||||
return true;
|
||||
@@ -666,11 +668,13 @@ GlobalActionManager::doQueueAdd( const QStringList& parts, const QList< QPair< Q
|
||||
{ // give it a web result hint
|
||||
QFileInfo info( track.path() );
|
||||
query_ptr q = Query::get( QString(), info.baseName(), QString(), uuid(), false );
|
||||
if ( q.isNull() )
|
||||
continue;
|
||||
|
||||
q->setResultHint( track.toString() );
|
||||
Pipeline::instance()->resolve( q );
|
||||
|
||||
Pipeline::instance()->resolve( q, true );
|
||||
|
||||
ViewManager::instance()->queue()->model()->append( q );
|
||||
ViewManager::instance()->queue()->model()->appendQuery( q );
|
||||
ViewManager::instance()->showQueue();
|
||||
}
|
||||
return true;
|
||||
@@ -1067,6 +1071,9 @@ GlobalActionManager::handlePlayCommand( const QUrl& url )
|
||||
}
|
||||
|
||||
query_ptr q = Query::get( artist, title, album );
|
||||
if ( q.isNull() )
|
||||
return false;
|
||||
|
||||
if ( !urlStr.isEmpty() )
|
||||
q->setResultHint( urlStr );
|
||||
|
||||
@@ -1155,18 +1162,25 @@ bool GlobalActionManager::handleBookmarkCommand(const QUrl& url)
|
||||
urlStr = pair.second;
|
||||
}
|
||||
query_ptr q = Query::get( artist, title, album );
|
||||
if ( q.isNull() )
|
||||
return false;
|
||||
|
||||
if ( !urlStr.isEmpty() )
|
||||
q->setResultHint( urlStr );
|
||||
Pipeline::instance()->resolve( q, true );
|
||||
Pipeline::instance()->resolve( q );
|
||||
|
||||
// now we add it to the special "bookmarks" playlist, creating it if it doesn't exist. if nothing is playing, start playing the track
|
||||
QSharedPointer< LocalCollection > col = SourceList::instance()->getLocal()->collection().dynamicCast< LocalCollection >();
|
||||
playlist_ptr bookmarkpl = col->bookmarksPlaylist();
|
||||
if ( bookmarkpl.isNull() ) { // create it and do the deed then
|
||||
if ( bookmarkpl.isNull() )
|
||||
{
|
||||
// create it and do the deed then
|
||||
m_waitingToBookmark = q;
|
||||
col->createBookmarksPlaylist();
|
||||
connect( col.data(), SIGNAL( bookmarkPlaylistCreated( Tomahawk::playlist_ptr ) ), this, SLOT( bookmarkPlaylistCreated( Tomahawk::playlist_ptr ) ), Qt::UniqueConnection );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
doBookmark( bookmarkpl, q );
|
||||
}
|
||||
|
||||
@@ -1343,7 +1357,7 @@ GlobalActionManager::waitingForResolved( bool /* success */ )
|
||||
AudioEngine::instance()->playItem( AudioEngine::instance()->playlist(), m_waitingToPlay->results().first() );
|
||||
else
|
||||
{
|
||||
ViewManager::instance()->queue()->model()->append( m_waitingToPlay );
|
||||
ViewManager::instance()->queue()->model()->appendQuery( m_waitingToPlay );
|
||||
AudioEngine::instance()->play();
|
||||
}
|
||||
}
|
||||
|
@@ -272,9 +272,16 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results )
|
||||
}
|
||||
const query_ptr& q = m_qids.value( qid );
|
||||
|
||||
Q_ASSERT( !q.isNull() );
|
||||
if ( q.isNull() )
|
||||
return;
|
||||
|
||||
QList< result_ptr > cleanResults;
|
||||
foreach ( const result_ptr& r, results )
|
||||
{
|
||||
if ( r.isNull() )
|
||||
continue;
|
||||
|
||||
float score = q->howSimilar( r );
|
||||
r->setScore( score );
|
||||
if ( !q->isFullTextQuery() && score < MINSCORE )
|
||||
|
@@ -54,6 +54,7 @@ PlaylistEntry::setQueryVariant( const QVariant& v )
|
||||
QString artist = m.value( "artist" ).toString();
|
||||
QString album = m.value( "album" ).toString();
|
||||
QString track = m.value( "track" ).toString();
|
||||
|
||||
m_query = Tomahawk::Query::get( artist, track, album );
|
||||
}
|
||||
|
||||
|
@@ -59,10 +59,11 @@ public:
|
||||
PlaylistEntry();
|
||||
virtual ~PlaylistEntry();
|
||||
|
||||
bool isValid() const { return !m_query.isNull(); }
|
||||
|
||||
void setQuery( const Tomahawk::query_ptr& q );
|
||||
const Tomahawk::query_ptr& query() const;
|
||||
|
||||
// I wish Qt did this for me once i specified the Q_PROPERTIES:
|
||||
void setQueryVariant( const QVariant& v );
|
||||
QVariant queryVariant() const;
|
||||
|
||||
|
@@ -29,6 +29,7 @@ using namespace Tomahawk;
|
||||
PlaylistInterface::PlaylistInterface ()
|
||||
: QObject()
|
||||
, m_latchMode( PlaylistModes::StayOnSong )
|
||||
, m_finished( false )
|
||||
{
|
||||
m_id = uuid();
|
||||
}
|
||||
|
@@ -40,6 +40,7 @@ public:
|
||||
const QString id() { return m_id; }
|
||||
|
||||
virtual QList< Tomahawk::query_ptr > tracks() = 0;
|
||||
virtual bool isFinished() const { return m_finished; }
|
||||
|
||||
virtual int unfilteredTrackCount() const = 0;
|
||||
virtual int trackCount() const = 0;
|
||||
@@ -91,7 +92,8 @@ protected:
|
||||
virtual QList<Tomahawk::query_ptr> filterTracks( const QList<Tomahawk::query_ptr>& queries );
|
||||
|
||||
PlaylistModes::LatchMode m_latchMode;
|
||||
|
||||
bool m_finished;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY( PlaylistInterface )
|
||||
|
||||
|
@@ -82,6 +82,9 @@ PlaybackLog::PlaybackLog( const PlaybackLog& other )
|
||||
query_ptr
|
||||
Query::get( const QString& artist, const QString& track, const QString& album, const QID& qid, bool autoResolve )
|
||||
{
|
||||
if ( artist.trimmed().isEmpty() || track.trimmed().isEmpty() )
|
||||
return query_ptr();
|
||||
|
||||
if ( qid.isEmpty() )
|
||||
autoResolve = false;
|
||||
|
||||
@@ -98,6 +101,8 @@ Query::get( const QString& artist, const QString& track, const QString& album, c
|
||||
query_ptr
|
||||
Query::get( const QString& query, const QID& qid )
|
||||
{
|
||||
Q_ASSERT( !query.trimmed().isEmpty() );
|
||||
|
||||
query_ptr q = query_ptr( new Query( query, qid ), &QObject::deleteLater );
|
||||
q->setWeakRef( q.toWeakRef() );
|
||||
|
||||
@@ -170,14 +175,14 @@ Query::updateSortNames()
|
||||
if ( isFullTextQuery() )
|
||||
{
|
||||
m_artistSortname = DatabaseImpl::sortname( m_fullTextQuery, true );
|
||||
m_composerSortName = DatabaseImpl::sortname( m_composer, true );
|
||||
m_composerSortname = DatabaseImpl::sortname( m_composer, true );
|
||||
m_albumSortname = DatabaseImpl::sortname( m_fullTextQuery );
|
||||
m_trackSortname = m_albumSortname;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_artistSortname = DatabaseImpl::sortname( m_artist, true );
|
||||
m_composerSortName = DatabaseImpl::sortname( m_composer, true );
|
||||
m_composerSortname = DatabaseImpl::sortname( m_composer, true );
|
||||
m_albumSortname = DatabaseImpl::sortname( m_album );
|
||||
m_trackSortname = DatabaseImpl::sortname( m_track );
|
||||
}
|
||||
@@ -189,7 +194,7 @@ Query::displayQuery() const
|
||||
{
|
||||
if ( !results().isEmpty() )
|
||||
return results().first()->toQuery();
|
||||
|
||||
|
||||
return m_ownRef.toStrongRef();
|
||||
}
|
||||
|
||||
@@ -223,6 +228,7 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults )
|
||||
|
||||
checkResults();
|
||||
emit resultsAdded( newresults );
|
||||
emit resultsChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -287,6 +293,7 @@ Query::removeResult( const Tomahawk::result_ptr& result )
|
||||
|
||||
emit resultsRemoved( result );
|
||||
checkResults();
|
||||
emit resultsChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -491,15 +498,20 @@ Query::toString() const
|
||||
float
|
||||
Query::howSimilar( const Tomahawk::result_ptr& r )
|
||||
{
|
||||
Q_ASSERT( !r->artist().isNull() );
|
||||
Q_ASSERT( !r->album().isNull() );
|
||||
if ( r->artist().isNull() || r->album().isNull() )
|
||||
return 0.0;
|
||||
|
||||
// result values
|
||||
const QString rArtistname = r->artist()->sortname();
|
||||
const QString rAlbumname = DatabaseImpl::sortname( r->album()->name() );
|
||||
const QString rAlbumname = r->album()->sortname();
|
||||
const QString rTrackname = DatabaseImpl::sortname( r->track() );
|
||||
|
||||
// normal edit distance
|
||||
int artdist = levenshtein( m_artistSortname, rArtistname );
|
||||
int albdist = levenshtein( m_albumSortname, rAlbumname );
|
||||
int trkdist = levenshtein( m_trackSortname, rTrackname );
|
||||
int artdist = TomahawkUtils::levenshtein( m_artistSortname, rArtistname );
|
||||
int albdist = TomahawkUtils::levenshtein( m_albumSortname, rAlbumname );
|
||||
int trkdist = TomahawkUtils::levenshtein( m_trackSortname, rTrackname );
|
||||
|
||||
// max length of name
|
||||
int mlart = qMax( m_artistSortname.length(), rArtistname.length() );
|
||||
@@ -516,7 +528,7 @@ Query::howSimilar( const Tomahawk::result_ptr& r )
|
||||
const QString artistTrackname = DatabaseImpl::sortname( fullTextQuery() );
|
||||
const QString rArtistTrackname = DatabaseImpl::sortname( r->artist()->name() + " " + r->track() );
|
||||
|
||||
int atrdist = levenshtein( artistTrackname, rArtistTrackname );
|
||||
int atrdist = TomahawkUtils::levenshtein( artistTrackname, rArtistTrackname );
|
||||
int mlatr = qMax( artistTrackname.length(), rArtistTrackname.length() );
|
||||
float dcatr = (float)( mlatr - atrdist ) / mlatr;
|
||||
|
||||
@@ -566,7 +578,7 @@ Query::playbackHistory( const Tomahawk::source_ptr& source ) const
|
||||
history << log;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return history;
|
||||
}
|
||||
|
||||
@@ -588,7 +600,7 @@ Query::playbackCount( const source_ptr& source )
|
||||
if ( source.isNull() || log.source == source )
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -596,6 +608,9 @@ Query::playbackCount( const source_ptr& source )
|
||||
void
|
||||
Query::loadSocialActions()
|
||||
{
|
||||
if ( m_socialActionsLoaded )
|
||||
return;
|
||||
|
||||
m_socialActionsLoaded = true;
|
||||
query_ptr q = m_ownRef.toStrongRef();
|
||||
|
||||
@@ -670,12 +685,12 @@ Query::setLoved( bool loved )
|
||||
trackInfo["album"] = album();
|
||||
|
||||
loveInfo[ "trackinfo" ] = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
|
||||
|
||||
|
||||
Tomahawk::InfoSystem::InfoPushData pushData ( id(),
|
||||
( loved ? Tomahawk::InfoSystem::InfoLove : Tomahawk::InfoSystem::InfoUnLove ),
|
||||
loveInfo,
|
||||
Tomahawk::InfoSystem::PushShortUrlFlag );
|
||||
|
||||
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData );
|
||||
|
||||
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction( q, QString( "Love" ), loved ? QString( "true" ) : QString( "false" ) );
|
||||
@@ -783,10 +798,10 @@ Query::coverLoaded() const
|
||||
{
|
||||
if ( m_albumPtr.isNull() )
|
||||
return false;
|
||||
|
||||
|
||||
if ( m_albumPtr->coverLoaded() && !m_albumPtr->cover( QSize( 0, 0 ) ).isNull() )
|
||||
return true;
|
||||
|
||||
|
||||
return m_artistPtr->coverLoaded();
|
||||
}
|
||||
|
||||
@@ -809,7 +824,7 @@ Query::similarTracks() const
|
||||
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
|
||||
requestData.type = Tomahawk::InfoSystem::InfoTrackSimilars;
|
||||
requestData.requestId = TomahawkUtils::infosystemRequestId();
|
||||
|
||||
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
|
||||
@@ -821,7 +836,7 @@ Query::similarTracks() const
|
||||
m_infoJobs++;
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
|
||||
}
|
||||
|
||||
|
||||
return m_similarTracks;
|
||||
}
|
||||
|
||||
@@ -842,7 +857,7 @@ Query::lyrics() const
|
||||
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
|
||||
requestData.type = Tomahawk::InfoSystem::InfoTrackLyrics;
|
||||
requestData.requestId = TomahawkUtils::infosystemRequestId();
|
||||
|
||||
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
|
||||
@@ -854,7 +869,7 @@ Query::lyrics() const
|
||||
m_infoJobs++;
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
|
||||
}
|
||||
|
||||
|
||||
return m_lyrics;
|
||||
}
|
||||
|
||||
@@ -871,7 +886,7 @@ Query::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVaria
|
||||
case InfoSystem::InfoTrackLyrics:
|
||||
{
|
||||
m_lyrics = output.value< QVariant >().toString().split( "\n" );
|
||||
|
||||
|
||||
m_lyricsLoaded = true;
|
||||
emit lyricsLoaded();
|
||||
break;
|
||||
@@ -887,7 +902,7 @@ Query::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVaria
|
||||
m_similarTracks << Query::get( artists.at( i ), tracks.at( i ), QString(), uuid(), false );
|
||||
}
|
||||
Pipeline::instance()->resolve( m_similarTracks );
|
||||
|
||||
|
||||
m_simTracksLoaded = true;
|
||||
emit similarTracksLoaded();
|
||||
|
||||
@@ -917,83 +932,3 @@ Query::infoSystemFinished( QString target )
|
||||
|
||||
emit updated();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Query::levenshtein( const QString& source, const QString& target )
|
||||
{
|
||||
// Step 1
|
||||
const int n = source.length();
|
||||
const int m = target.length();
|
||||
|
||||
if ( n == 0 )
|
||||
return m;
|
||||
if ( m == 0 )
|
||||
return n;
|
||||
|
||||
// Good form to declare a TYPEDEF
|
||||
typedef QVector< QVector<int> > Tmatrix;
|
||||
Tmatrix matrix;
|
||||
matrix.resize( n + 1 );
|
||||
|
||||
// Size the vectors in the 2.nd dimension. Unfortunately C++ doesn't
|
||||
// allow for allocation on declaration of 2.nd dimension of vec of vec
|
||||
for ( int i = 0; i <= n; i++ )
|
||||
{
|
||||
QVector<int> tmp;
|
||||
tmp.resize( m + 1 );
|
||||
matrix.insert( i, tmp );
|
||||
}
|
||||
|
||||
// Step 2
|
||||
for ( int i = 0; i <= n; i++ )
|
||||
matrix[i][0] = i;
|
||||
for ( int j = 0; j <= m; j++ )
|
||||
matrix[0][j] = j;
|
||||
|
||||
// Step 3
|
||||
for ( int i = 1; i <= n; i++ )
|
||||
{
|
||||
const QChar s_i = source[i - 1];
|
||||
|
||||
// Step 4
|
||||
for ( int j = 1; j <= m; j++ )
|
||||
{
|
||||
const QChar t_j = target[j - 1];
|
||||
|
||||
// Step 5
|
||||
int cost;
|
||||
if ( s_i == t_j )
|
||||
cost = 0;
|
||||
else
|
||||
cost = 1;
|
||||
|
||||
// Step 6
|
||||
const int above = matrix[i - 1][j];
|
||||
const int left = matrix[i][j - 1];
|
||||
const int diag = matrix[i - 1][j - 1];
|
||||
|
||||
int cell = ( ( ( left + 1 ) > ( diag + cost ) ) ? diag + cost : left + 1 );
|
||||
if ( above + 1 < cell )
|
||||
cell = above + 1;
|
||||
|
||||
// Step 6A: Cover transposition, in addition to deletion,
|
||||
// insertion and substitution. This step is taken from:
|
||||
// Berghel, Hal ; Roach, David : "An Extension of Ukkonen's
|
||||
// Enhanced Dynamic Programming ASM Algorithm"
|
||||
// (http://www.acm.org/~hlb/publications/asm/asm.html)
|
||||
if ( i > 2 && j > 2 )
|
||||
{
|
||||
int trans = matrix[i - 2][j - 2] + 1;
|
||||
|
||||
if ( source[ i - 2 ] != t_j ) trans++;
|
||||
if ( s_i != target[ j - 2 ] ) trans++;
|
||||
if ( cell > trans ) cell = trans;
|
||||
}
|
||||
matrix[i][j] = cell;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 7
|
||||
return matrix[n][m];
|
||||
}
|
||||
|
@@ -97,7 +97,7 @@ public:
|
||||
QID id() const;
|
||||
|
||||
/// sorter for list of results
|
||||
static bool resultSorter( const result_ptr &left, const result_ptr& right );
|
||||
static bool resultSorter( const result_ptr& left, const result_ptr& right );
|
||||
|
||||
/// true when a perfect result has been found (score of 1.0)
|
||||
bool solved() const { return m_solved; }
|
||||
@@ -129,6 +129,7 @@ public:
|
||||
|
||||
QString resultHint() const { return m_resultHint; }
|
||||
QString artistSortname() const { return m_artistSortname; }
|
||||
QString composerSortname() const { return m_composerSortname; }
|
||||
QString albumSortname() const { return m_albumSortname; }
|
||||
QString trackSortname() const { return m_trackSortname; }
|
||||
|
||||
@@ -139,7 +140,7 @@ public:
|
||||
int duration() const { return m_duration; }
|
||||
unsigned int albumpos() const { return m_albumpos; }
|
||||
unsigned int discnumber() const { return m_discnumber; }
|
||||
|
||||
|
||||
query_ptr displayQuery() const;
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
@@ -220,7 +221,6 @@ private:
|
||||
void checkResults();
|
||||
|
||||
void updateSortNames();
|
||||
static int levenshtein( const QString& source, const QString& target );
|
||||
|
||||
void parseSocialActions();
|
||||
|
||||
@@ -233,7 +233,7 @@ private:
|
||||
mutable QID m_qid;
|
||||
|
||||
QString m_artistSortname;
|
||||
QString m_composerSortName;
|
||||
QString m_composerSortname;
|
||||
QString m_albumSortname;
|
||||
QString m_trackSortname;
|
||||
|
||||
@@ -266,10 +266,10 @@ private:
|
||||
|
||||
bool m_simTracksLoaded;
|
||||
QList<Tomahawk::query_ptr> m_similarTracks;
|
||||
|
||||
|
||||
bool m_lyricsLoaded;
|
||||
QStringList m_lyrics;
|
||||
|
||||
|
||||
mutable int m_infoJobs;
|
||||
};
|
||||
|
||||
|
@@ -36,6 +36,7 @@ class DatabaseCommand_LogPlayback;
|
||||
class DatabaseCommand_SocialAction;
|
||||
class DatabaseCommand_UpdateSearchIndex;
|
||||
class DatabaseCommand_DeleteFiles;
|
||||
class MusicScanner;
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
@@ -50,6 +51,7 @@ friend class ::DatabaseCommand_LogPlayback;
|
||||
friend class ::DatabaseCommand_SocialAction;
|
||||
friend class ::DatabaseCommand_AddFiles;
|
||||
friend class ::DatabaseCommand_DeleteFiles;
|
||||
friend class ::MusicScanner;
|
||||
|
||||
public:
|
||||
enum AvatarStyle { Original, FancyStyle };
|
||||
|
@@ -305,7 +305,7 @@ ViewManager::show( const Tomahawk::collection_ptr& collection )
|
||||
view = new TreeView();
|
||||
TreeModel* model = new TreeModel();
|
||||
view->setTreeModel( model );
|
||||
|
||||
|
||||
if ( collection && collection->source()->isLocal() )
|
||||
view->setEmptyTip( tr( "After you have scanned your music collection you will find your tracks right here." ) );
|
||||
else
|
||||
@@ -483,7 +483,7 @@ ViewManager::showRecentPlaysPage()
|
||||
{
|
||||
PlaylistView* pv = new PlaylistView( m_widget );
|
||||
|
||||
RecentlyPlayedModel* raModel = new RecentlyPlayedModel( source_ptr(), pv );
|
||||
RecentlyPlayedModel* raModel = new RecentlyPlayedModel( pv );
|
||||
raModel->setTitle( tr( "Recently Played Tracks" ) );
|
||||
raModel->setDescription( tr( "Recently played tracks from all your friends" ) );
|
||||
raModel->setStyle( PlayableModel::Large );
|
||||
@@ -493,6 +493,7 @@ ViewManager::showRecentPlaysPage()
|
||||
pv->setItemDelegate( del );
|
||||
|
||||
pv->setPlaylistModel( raModel );
|
||||
raModel->setSource( source_ptr() );
|
||||
|
||||
m_recentPlaysWidget = pv;
|
||||
}
|
||||
@@ -570,7 +571,7 @@ ViewManager::historyBack()
|
||||
return;
|
||||
|
||||
ViewPage* page = m_pageHistoryBack.takeLast();
|
||||
|
||||
|
||||
if ( m_currentPage )
|
||||
{
|
||||
m_pageHistoryFwd << m_currentPage;
|
||||
@@ -589,7 +590,7 @@ ViewManager::historyForward()
|
||||
return;
|
||||
|
||||
ViewPage* page = m_pageHistoryFwd.takeLast();
|
||||
|
||||
|
||||
if ( m_currentPage )
|
||||
{
|
||||
m_pageHistoryBack << m_currentPage;
|
||||
@@ -615,14 +616,7 @@ ViewManager::destroyPage( ViewPage* page )
|
||||
return;
|
||||
|
||||
tDebug() << Q_FUNC_INFO << "Deleting page:" << page->title();
|
||||
if ( m_currentPage == page )
|
||||
{
|
||||
delete page;
|
||||
m_currentPage = 0;
|
||||
|
||||
historyBack();
|
||||
}
|
||||
else if ( historyPages().contains( page ) )
|
||||
if ( historyPages().contains( page ) )
|
||||
{
|
||||
m_pageHistoryBack.removeAll( page );
|
||||
m_pageHistoryFwd.removeAll( page );
|
||||
@@ -632,6 +626,13 @@ ViewManager::destroyPage( ViewPage* page )
|
||||
|
||||
delete page;
|
||||
}
|
||||
|
||||
if ( m_currentPage == page )
|
||||
{
|
||||
m_currentPage = 0;
|
||||
|
||||
historyBack();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -640,6 +641,8 @@ ViewManager::setPage( ViewPage* page, bool trackHistory )
|
||||
{
|
||||
if ( !page )
|
||||
return;
|
||||
if ( page == m_currentPage )
|
||||
return;
|
||||
|
||||
// save the old playlist shuffle state in config before we change playlists
|
||||
saveCurrentPlaylistSettings();
|
||||
@@ -865,7 +868,7 @@ ViewManager::onWidgetDestroyed( QWidget* widget )
|
||||
{
|
||||
m_dynamicWidgets.remove( dynamicPlaylistForInterface( page->playlistInterface() ) );
|
||||
}
|
||||
|
||||
|
||||
m_pageHistoryBack.removeAll( page );
|
||||
m_pageHistoryFwd.removeAll( page );
|
||||
}
|
||||
|
@@ -132,7 +132,7 @@ LastFmConfig::onHistoryLoaded()
|
||||
uint total = 0;
|
||||
bool finished = false;
|
||||
QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
lastfm::XmlQuery lfm;
|
||||
@@ -140,24 +140,27 @@ LastFmConfig::onHistoryLoaded()
|
||||
|
||||
foreach ( lastfm::XmlQuery e, lfm.children( "track" ) )
|
||||
{
|
||||
// tDebug() << "Found:" << e["artist"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt();
|
||||
Tomahawk::query_ptr query = Query::get( e["artist"].text(), e["name"].text(), QString(), QString(), false );
|
||||
// tDebug() << "Found:" << e.children( "artist" ).first()["name"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt();
|
||||
Tomahawk::query_ptr query = Query::get( e.children( "artist" ).first()["name"].text(), e["name"].text(), QString(), QString(), false );
|
||||
if ( query.isNull() )
|
||||
continue;
|
||||
|
||||
m_lastTimeStamp = e["date"].attribute( "uts" ).toUInt();
|
||||
|
||||
|
||||
DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( query, DatabaseCommand_LogPlayback::Finished, m_lastTimeStamp );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
|
||||
}
|
||||
|
||||
|
||||
if ( !lfm.children( "recenttracks" ).isEmpty() )
|
||||
{
|
||||
lastfm::XmlQuery stats = lfm.children( "recenttracks" ).first();
|
||||
|
||||
|
||||
uint page = stats.attribute( "page" ).toUInt();
|
||||
total = stats.attribute( "totalPages" ).toUInt();
|
||||
|
||||
|
||||
m_ui->progressBar->setMaximum( total );
|
||||
m_ui->progressBar->setValue( page );
|
||||
|
||||
|
||||
if ( page < total )
|
||||
{
|
||||
m_page = page + 1;
|
||||
@@ -174,7 +177,7 @@ LastFmConfig::onHistoryLoaded()
|
||||
tDebug() << "XmlQuery error:" << e.message();
|
||||
finished = true;
|
||||
}
|
||||
|
||||
|
||||
if ( finished )
|
||||
{
|
||||
if ( m_page != total )
|
||||
|
@@ -212,7 +212,7 @@ LastFmInfoPlugin::scrobble()
|
||||
return;
|
||||
|
||||
tLog() << Q_FUNC_INFO << "Scrobbling now:" << m_track.toString();
|
||||
|
||||
|
||||
// FIXME: workaround for the duration-less dilandau (and others) tracks
|
||||
if ( m_track.duration() == 0 )
|
||||
m_track.setDuration( 31 );
|
||||
@@ -525,7 +525,7 @@ LastFmInfoPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::In
|
||||
imgurl.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artistName, "", "+" ) );
|
||||
imgurl.addEncodedQueryItem( "album", QUrl::toPercentEncoding( albumName, "", "+" ) );
|
||||
imgurl.addQueryItem( "autocorrect", QString::number( 1 ) );
|
||||
imgurl.addQueryItem( "size", "largesquare" );
|
||||
imgurl.addQueryItem( "size", "large" );
|
||||
imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" );
|
||||
|
||||
QNetworkRequest req( imgurl );
|
||||
|
@@ -29,6 +29,8 @@
|
||||
#include "Pipeline.h"
|
||||
#include "accounts/AccountManager.h"
|
||||
#include "utils/Closure.h"
|
||||
#include "SpotifyInfoPlugin.h"
|
||||
#include "infosystem/InfoSystem.h"
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
#include "jobview/JobStatusView.h"
|
||||
@@ -106,6 +108,12 @@ SpotifyAccount::init()
|
||||
AtticaManager::instance()->registerCustomAccount( s_resolverId, this );
|
||||
qRegisterMetaType< Tomahawk::Accounts::SpotifyPlaylistInfo* >( "Tomahawk::Accounts::SpotifyPlaylist*" );
|
||||
|
||||
if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() )
|
||||
{
|
||||
infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() );
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() );
|
||||
}
|
||||
|
||||
if ( !AtticaManager::instance()->resolversLoaded() )
|
||||
{
|
||||
// If we're still waiting to load, wait for the attica resolvers to come down the pipe
|
||||
@@ -121,7 +129,6 @@ SpotifyAccount::init()
|
||||
void
|
||||
SpotifyAccount::delayedInit()
|
||||
{
|
||||
|
||||
connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( resolverInstalled( QString ) ) );
|
||||
|
||||
const Attica::Content res = AtticaManager::instance()->resolverForId( s_resolverId );
|
||||
@@ -131,6 +138,11 @@ SpotifyAccount::delayedInit()
|
||||
if ( !checkForResolver() && state != AtticaManager::Uninstalled )
|
||||
{
|
||||
// If the user manually deleted the resolver, mark it as uninstalled, so we re-fetch for the user
|
||||
QVariantHash conf = configuration();
|
||||
conf.remove( "path" );
|
||||
setConfiguration( conf );
|
||||
sync();
|
||||
|
||||
AtticaManager::instance()->uninstallResolver( res );
|
||||
}
|
||||
else if ( state == AtticaManager::Installed || !path.isEmpty() )
|
||||
@@ -138,9 +150,15 @@ SpotifyAccount::delayedInit()
|
||||
if ( !path.isEmpty() )
|
||||
{
|
||||
QFileInfo info( path );
|
||||
// Resolver was deleted, so abort.
|
||||
// Resolver was deleted, so abort and remove our manual override, as it's no longer valid
|
||||
if ( !info.exists() )
|
||||
{
|
||||
QVariantHash conf = configuration();
|
||||
conf.remove( "path" );
|
||||
setConfiguration( conf );
|
||||
sync();
|
||||
return;
|
||||
}
|
||||
}
|
||||
hookupResolver();
|
||||
}
|
||||
@@ -165,6 +183,21 @@ SpotifyAccount::hookupResolver()
|
||||
}
|
||||
|
||||
qDebug() << "Starting spotify resolver with path:" << path;
|
||||
if ( !m_spotifyResolver.isNull() )
|
||||
{
|
||||
delete m_spotifyResolver.data();
|
||||
}
|
||||
|
||||
if ( !QFile::exists( path ) )
|
||||
{
|
||||
qWarning() << "Asked to hook up spotify resolver but it doesn't exist, ignoring";
|
||||
return;
|
||||
}
|
||||
|
||||
// HACK
|
||||
// Since the resolver in 0.4.x used an incompatible version of kdsingleappguard, we can't auto-kill old resolvers on the
|
||||
// 0.4.x->0.5.x upgrade. So we do it manually for a while
|
||||
killExistingResolvers();
|
||||
m_spotifyResolver = QWeakPointer< ScriptResolver >( qobject_cast< ScriptResolver* >( Pipeline::instance()->addScriptResolver( path ) ) );
|
||||
|
||||
connect( m_spotifyResolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) );
|
||||
@@ -182,6 +215,20 @@ SpotifyAccount::hookupResolver()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::killExistingResolvers()
|
||||
{
|
||||
QProcess p;
|
||||
#if defined(Q_OS_UNIX)
|
||||
const int ret = p.execute( "killall -9 spotify_tomahawkresolver" );
|
||||
qDebug() << "Tried to killall -9 spotify_tomahawkresolver with return code:" << ret;
|
||||
#elif defined(Q_OS_WIN)
|
||||
const int ret = p.execute( "taskkill.exe /F /im spotify_tomahawkresolver.exe" );
|
||||
qDebug() << "Tried to taskkill.exe /F /im spotify_tomahawkresolver.exe with return code:" << ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SpotifyAccount::checkForResolver()
|
||||
{
|
||||
@@ -228,13 +275,18 @@ SpotifyAccount::authenticate()
|
||||
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
|
||||
|
||||
qDebug() << "Spotify account authenticating...";
|
||||
|
||||
const QString path = configuration().value( "path" ).toString();
|
||||
const QFileInfo info( path );
|
||||
const bool manualResolverRemoved = !path.isEmpty() && !info.exists();
|
||||
|
||||
if ( m_spotifyResolver.isNull() && state == AtticaManager::Installed )
|
||||
{
|
||||
// We don;t have the resolver but it has been installed via attica already, so lets just turn it on
|
||||
qDebug() << "No valid spotify resolver running, but attica reports it is installed, so start it up";
|
||||
hookupResolver();
|
||||
}
|
||||
else if ( m_spotifyResolver.isNull() )
|
||||
else if ( m_spotifyResolver.isNull() || manualResolverRemoved )
|
||||
{
|
||||
qDebug() << "Got null resolver but asked to authenticate, so installing if we have one from attica:" << res.isValid() << res.id();
|
||||
if ( res.isValid() && !res.id().isEmpty() )
|
||||
@@ -284,6 +336,18 @@ SpotifyAccount::connectionState() const
|
||||
}
|
||||
|
||||
|
||||
InfoSystem::InfoPluginPtr
|
||||
SpotifyAccount::infoPlugin()
|
||||
{
|
||||
if ( m_infoPlugin.isNull() )
|
||||
{
|
||||
m_infoPlugin = QWeakPointer< InfoSystem::SpotifyInfoPlugin >( new InfoSystem::SpotifyInfoPlugin( this ) );
|
||||
}
|
||||
|
||||
return InfoSystem::InfoPluginPtr( m_infoPlugin.data() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::resolverInstalled(const QString& resolverId)
|
||||
{
|
||||
@@ -318,6 +382,11 @@ SpotifyAccount::setManualResolverPath( const QString &resolverPath )
|
||||
setConfiguration( conf );
|
||||
sync();
|
||||
|
||||
// uninstall
|
||||
const Attica::Content res = AtticaManager::instance()->resolverForId( s_resolverId );
|
||||
if ( AtticaManager::instance()->resolverState( res ) != AtticaManager::Uninstalled )
|
||||
AtticaManager::instance()->uninstallResolver( res );
|
||||
|
||||
m_preventEnabling = false;
|
||||
|
||||
if ( !m_spotifyResolver.isNull() )
|
||||
@@ -335,6 +404,14 @@ SpotifyAccount::setManualResolverPath( const QString &resolverPath )
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SpotifyAccount::loggedIn() const
|
||||
{
|
||||
// TODO pending newconfigui branch
|
||||
return enabled() && !m_spotifyResolver.isNull() && m_spotifyResolver.data()->running();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::hookupAfterDeletion( bool autoEnable )
|
||||
{
|
||||
|
@@ -35,6 +35,12 @@ class QTimer;
|
||||
class ScriptResolver;
|
||||
|
||||
namespace Tomahawk {
|
||||
|
||||
namespace InfoSystem
|
||||
{
|
||||
class SpotifyInfoPlugin;
|
||||
}
|
||||
|
||||
namespace Accounts {
|
||||
|
||||
class SpotifyAccountConfig;
|
||||
@@ -89,7 +95,7 @@ public:
|
||||
virtual void deauthenticate();
|
||||
|
||||
virtual QWidget* aclWidget() { return 0; }
|
||||
virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin() { return Tomahawk::InfoSystem::InfoPluginPtr(); }
|
||||
virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin();
|
||||
virtual SipPlugin* sipPlugin() { return 0; }
|
||||
virtual bool preventEnabling() const { return m_preventEnabling; }
|
||||
|
||||
@@ -102,6 +108,8 @@ public:
|
||||
|
||||
void setManualResolverPath( const QString& resolverPath );
|
||||
|
||||
bool loggedIn() const;
|
||||
|
||||
public slots:
|
||||
void aboutToShow( QAction* action, const Tomahawk::playlist_ptr& playlist );
|
||||
void syncActionTriggered( bool );
|
||||
@@ -126,6 +134,7 @@ private:
|
||||
void init();
|
||||
bool checkForResolver();
|
||||
void hookupResolver();
|
||||
void killExistingResolvers();
|
||||
|
||||
void loadPlaylists();
|
||||
void clearUser( bool permanentlyDelete = false );
|
||||
@@ -142,6 +151,7 @@ private:
|
||||
QWeakPointer<SpotifyAccountConfig> m_configWidget;
|
||||
QWeakPointer<QWidget> m_aboutWidget;
|
||||
QWeakPointer<ScriptResolver> m_spotifyResolver;
|
||||
QWeakPointer< InfoSystem::SpotifyInfoPlugin > m_infoPlugin;
|
||||
|
||||
QMap<QString, QPair<QObject*, QString> > m_qidToSlotMap;
|
||||
|
||||
|
263
src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.cpp
Normal file
263
src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
/* === This file is part of Tomahawk Player - <http://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
|
||||
* 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 "SpotifyInfoPlugin.h"
|
||||
|
||||
#include "SpotifyAccount.h"
|
||||
#include "utils/Closure.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
using namespace Tomahawk::InfoSystem;
|
||||
|
||||
|
||||
SpotifyInfoPlugin::SpotifyInfoPlugin( Accounts::SpotifyAccount* account )
|
||||
: InfoPlugin()
|
||||
, m_account( QWeakPointer< Accounts::SpotifyAccount >( account ) )
|
||||
{
|
||||
if ( !m_account.isNull() )
|
||||
m_supportedGetTypes << InfoAlbumSongs;
|
||||
}
|
||||
|
||||
|
||||
SpotifyInfoPlugin::~SpotifyInfoPlugin()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyInfoPlugin::getInfo( InfoRequestData requestData )
|
||||
{
|
||||
switch ( requestData.type )
|
||||
{
|
||||
case InfoAlbumSongs:
|
||||
{
|
||||
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
|
||||
{
|
||||
dataError( requestData );
|
||||
return;
|
||||
}
|
||||
|
||||
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
|
||||
if ( !hash.contains( "album" ) )
|
||||
{
|
||||
dataError( requestData );
|
||||
return;
|
||||
}
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
criteria[ "album" ] = hash[ "album" ];
|
||||
if ( hash.contains( "artist" ) )
|
||||
criteria["artist"] = hash["artist"];
|
||||
|
||||
emit getCachedInfo( criteria, 2419200000, requestData );
|
||||
|
||||
return;
|
||||
}
|
||||
default:
|
||||
dataError( requestData );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyInfoPlugin::notInCacheSlot( InfoStringHash criteria, InfoRequestData requestData )
|
||||
{
|
||||
switch ( requestData.type )
|
||||
{
|
||||
case InfoAlbumSongs:
|
||||
{
|
||||
const QString album = criteria[ "album" ];
|
||||
const QString artist = criteria[ "artist" ];
|
||||
|
||||
if ( m_account.isNull() || !m_account.data()->loggedIn() )
|
||||
{
|
||||
// No running spotify account, use our webservice
|
||||
QUrl lookupUrl( "http://ws.spotify.com/search/1/album.json" );
|
||||
lookupUrl.addQueryItem( "q", QString( "%1 %2" ).arg( album ).arg( album ) );
|
||||
|
||||
QNetworkReply * reply = TomahawkUtils::nam()->get( QNetworkRequest( lookupUrl ) );
|
||||
NewClosure( reply, SIGNAL( finished() ), this, SLOT( albumIdLookupFinished( QNetworkReply*, Tomahawk::InfoSystem::InfoRequestData ) ), reply, requestData );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Running resolver, so do the lookup through that
|
||||
qDebug() << Q_FUNC_INFO << "Doing album lookup through spotify:" << album << artist;
|
||||
QVariantMap message;
|
||||
message[ "_msgtype" ] = "albumListing";
|
||||
message[ "artist" ] = artist;
|
||||
message[ "album" ] = album;
|
||||
|
||||
const QString qid = m_account.data()->sendMessage( message, this, "albumListingResult" );
|
||||
|
||||
m_waitingForResults[ qid ] = requestData;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Q_ASSERT( false );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyInfoPlugin::albumListingResult( const QString& msgType, const QVariantMap& msg )
|
||||
{
|
||||
Q_ASSERT( msg.contains( "qid" ) );
|
||||
Q_ASSERT( m_waitingForResults.contains( msg.value( "qid" ).toString() ) );
|
||||
|
||||
if ( !msg.contains( "qid" ) || !m_waitingForResults.contains( msg.value( "qid" ).toString() ) )
|
||||
return;
|
||||
|
||||
const InfoRequestData requestData = m_waitingForResults.take( msg.value( "qid" ).toString() );
|
||||
|
||||
QVariantList tracks = msg.value( "tracks" ).toList();
|
||||
QStringList trackNameList;
|
||||
|
||||
foreach ( const QVariant track, tracks )
|
||||
{
|
||||
const QVariantMap trackData = track.toMap();
|
||||
if ( trackData.contains( "track" ) && !trackData[ "track" ].toString().isEmpty() )
|
||||
trackNameList << trackData[ "track" ].toString();
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "Successfully got album listing from spotify resolver";
|
||||
trackListResult( trackNameList, requestData );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyInfoPlugin::albumIdLookupFinished( QNetworkReply* reply, const InfoRequestData& requestData )
|
||||
{
|
||||
Q_ASSERT( reply );
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
if ( reply->error() == QNetworkReply::NoError )
|
||||
{
|
||||
QJson::Parser p;
|
||||
const QVariantMap response = p.parse( reply ).toMap();
|
||||
if ( !response.contains( "albums" ) )
|
||||
{
|
||||
dataError( requestData );
|
||||
return;
|
||||
}
|
||||
|
||||
const QVariantList albums = response.value( "albums" ).toList();
|
||||
if ( albums.isEmpty() )
|
||||
{
|
||||
dataError( requestData );
|
||||
return;
|
||||
}
|
||||
|
||||
const QVariantMap album = albums.first().toMap();
|
||||
const QString id = album.value( "href" ).toString();
|
||||
if ( id.isEmpty() || !id.contains( "spotify:album" ) )
|
||||
{
|
||||
qDebug() << "Empty or malformed spotify album ID from json:" << id << response;
|
||||
dataError( requestData );
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Doing spotify album lookup via webservice with ID:" << id;
|
||||
|
||||
QUrl lookupUrl( QString( "http://spotikea.tomahawk-player.org/browse/%1" ).arg( id ) );
|
||||
|
||||
|
||||
QNetworkReply * reply = TomahawkUtils::nam()->get( QNetworkRequest( lookupUrl ) );
|
||||
NewClosure( reply, SIGNAL( finished() ), this, SLOT( albumContentsLookupFinished( QNetworkReply*, Tomahawk::InfoSystem::InfoRequestData ) ), reply, requestData );
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Network Error retrieving ID from spotify metadata service:" << reply->error() << reply->errorString() << reply->url();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyInfoPlugin::albumContentsLookupFinished( QNetworkReply* reply, const InfoRequestData& requestData )
|
||||
{
|
||||
Q_ASSERT( reply );
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
if ( reply->error() == QNetworkReply::NoError )
|
||||
{
|
||||
QJson::Parser p;
|
||||
const QVariantMap response = p.parse( reply ).toMap();
|
||||
|
||||
if ( !response.contains( "album" ) )
|
||||
{
|
||||
dataError( requestData );
|
||||
return;
|
||||
}
|
||||
|
||||
const QVariantMap album = response.value( "album" ).toMap();
|
||||
if ( !album.contains( "result" ) || album.value( "result" ).toList().isEmpty() )
|
||||
{
|
||||
dataError( requestData );
|
||||
return;
|
||||
}
|
||||
|
||||
const QVariantList albumTracks = album.value( "result" ).toList();
|
||||
QStringList trackNameList;
|
||||
|
||||
foreach ( const QVariant& track, albumTracks )
|
||||
{
|
||||
const QVariantMap trackMap = track.toMap();
|
||||
if ( trackMap.contains( "title" ) )
|
||||
trackNameList << trackMap.value( "title" ).toString();
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "Successfully got album listing from spotikea service!";
|
||||
|
||||
if ( trackNameList.isEmpty() )
|
||||
dataError( requestData );
|
||||
else
|
||||
trackListResult( trackNameList, requestData );
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Network Error retrieving ID from spotify metadata service:" << reply->error() << reply->errorString() << reply->url();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpotifyInfoPlugin::dataError( InfoRequestData requestData )
|
||||
{
|
||||
emit info( requestData, QVariant() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyInfoPlugin::trackListResult( const QStringList& trackNameList, const InfoRequestData& requestData )
|
||||
{
|
||||
QVariantMap returnedData;
|
||||
returnedData["tracks"] = trackNameList;
|
||||
|
||||
emit info( requestData, returnedData );
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash criteria;
|
||||
criteria["artist"] = requestData.input.value< InfoStringHash>()["artist"];
|
||||
criteria["album"] = requestData.input.value< InfoStringHash>()["album"];
|
||||
|
||||
emit updateCache( criteria, 0, requestData.type, returnedData );
|
||||
}
|
74
src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.h
Normal file
74
src/libtomahawk/accounts/spotify/SpotifyInfoPlugin.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* === This file is part of Tomahawk Player - <http://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
|
||||
* 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 SPOTIFYINFOPLUGIN_H
|
||||
#define SPOTIFYINFOPLUGIN_H
|
||||
|
||||
#include "infosystem/InfoSystem.h"
|
||||
#include "DllMacro.h"
|
||||
|
||||
#include <QWeakPointer>
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
namespace Accounts
|
||||
{
|
||||
class SpotifyAccount;
|
||||
}
|
||||
|
||||
namespace InfoSystem
|
||||
{
|
||||
|
||||
class DLLEXPORT SpotifyInfoPlugin : public InfoPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SpotifyInfoPlugin( Accounts::SpotifyAccount* account );
|
||||
virtual ~SpotifyInfoPlugin();
|
||||
|
||||
public slots:
|
||||
void albumListingResult( const QString& msgType, const QVariantMap& msg );
|
||||
|
||||
protected slots:
|
||||
virtual void init() {}
|
||||
virtual void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
virtual void pushInfo( Tomahawk::InfoSystem::InfoPushData ) {}
|
||||
|
||||
private slots:
|
||||
void albumIdLookupFinished( QNetworkReply* reply, const Tomahawk::InfoSystem::InfoRequestData& requestData );
|
||||
void albumContentsLookupFinished( QNetworkReply* reply, const Tomahawk::InfoSystem::InfoRequestData& requestData );
|
||||
|
||||
private:
|
||||
void dataError( InfoRequestData );
|
||||
void trackListResult( const QStringList& trackNameList, const Tomahawk::InfoSystem::InfoRequestData& requestData );
|
||||
|
||||
QHash< QString, InfoRequestData > m_waitingForResults;
|
||||
|
||||
QWeakPointer< Tomahawk::Accounts::SpotifyAccount > m_account;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // SPOTIFYINFOPLUGIN_H
|
@@ -674,6 +674,9 @@ SpotifyPlaylistUpdater::variantToQueries( const QVariantList& list )
|
||||
{
|
||||
QVariantMap trackMap = blob.toMap();
|
||||
const query_ptr q = Query::get( trackMap.value( "artist" ).toString(), trackMap.value( "track" ).toString(), trackMap.value( "album" ).toString(), uuid(), false );
|
||||
if ( q.isNull() )
|
||||
continue;
|
||||
|
||||
if ( trackMap.contains( "id" ) )
|
||||
q->setProperty( "annotation", trackMap.value( "id" ) );
|
||||
|
||||
|
@@ -37,6 +37,9 @@
|
||||
#include "infosystem/InfoSystem.h"
|
||||
#include "Album.h"
|
||||
#include "Pipeline.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#include "jobview/ErrorStatusMessage.h"
|
||||
|
||||
#include "utils/Logger.h"
|
||||
|
||||
@@ -94,12 +97,9 @@ AudioEngine::AudioEngine()
|
||||
AudioEngine::~AudioEngine()
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
|
||||
|
||||
m_mediaObject->stop();
|
||||
TomahawkSettings::instance()->setVolume( volume() );
|
||||
|
||||
delete m_audioOutput;
|
||||
delete m_mediaObject;
|
||||
}
|
||||
|
||||
|
||||
@@ -604,8 +604,17 @@ AudioEngine::playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk:
|
||||
{
|
||||
if ( query->resolvingFinished() )
|
||||
{
|
||||
if ( query->numResults() )
|
||||
if ( query->numResults() && query->results().first()->isOnline() )
|
||||
{
|
||||
playItem( playlist, query->results().first() );
|
||||
return;
|
||||
}
|
||||
|
||||
JobStatusView::instance()->model()->addJob(
|
||||
new ErrorStatusMessage( tr( "Sorry, Tomahawk couldn't find the track '%1' by %2" ).arg( query->track() ).arg( query->artist() ), 15 ) );
|
||||
|
||||
if ( isStopped() )
|
||||
emit stopped(); // we do this so the original caller knows we couldn't find this track
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -621,9 +630,18 @@ void
|
||||
AudioEngine::playItem( const Tomahawk::artist_ptr& artist )
|
||||
{
|
||||
playlistinterface_ptr pli = artist->playlistInterface( Mixed );
|
||||
if ( pli->trackCount() )
|
||||
if ( pli->isFinished() )
|
||||
{
|
||||
playItem( pli, pli->tracks().first() );
|
||||
if ( !pli->tracks().count() )
|
||||
{
|
||||
JobStatusView::instance()->model()->addJob(
|
||||
new ErrorStatusMessage( tr( "Sorry, Tomahawk couldn't find the artist '%1'" ).arg( artist->name() ), 15 ) );
|
||||
|
||||
if ( isStopped() )
|
||||
emit stopped(); // we do this so the original caller knows we couldn't find this track
|
||||
}
|
||||
else
|
||||
playItem( pli, pli->tracks().first() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -638,9 +656,18 @@ void
|
||||
AudioEngine::playItem( const Tomahawk::album_ptr& album )
|
||||
{
|
||||
playlistinterface_ptr pli = album->playlistInterface( Mixed );
|
||||
if ( pli->trackCount() )
|
||||
if ( pli->isFinished() )
|
||||
{
|
||||
playItem( pli, pli->tracks().first() );
|
||||
if ( !pli->tracks().count() )
|
||||
{
|
||||
JobStatusView::instance()->model()->addJob(
|
||||
new ErrorStatusMessage( tr( "Sorry, Tomahawk couldn't find the album '%1' by %2" ).arg( album->name() ).arg( album->artist()->name() ), 15 ) );
|
||||
|
||||
if ( isStopped() )
|
||||
emit stopped(); // we do this so the original caller knows we couldn't find this track
|
||||
}
|
||||
else
|
||||
playItem( pli, pli->tracks().first() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -734,7 +761,7 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( newState == Phonon::PausedState || newState == Phonon::PlayingState || newState == Phonon::ErrorState )
|
||||
{
|
||||
tDebug() << "Phonon state now:" << newState;
|
||||
@@ -860,10 +887,10 @@ AudioEngine::checkStateQueue()
|
||||
m_mediaObject->play();
|
||||
if ( paused )
|
||||
setVolume( m_volume );
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case Paused:
|
||||
{
|
||||
m_volume = volume();
|
||||
|
@@ -138,7 +138,7 @@ private slots:
|
||||
|
||||
void sendNowPlayingNotification( const Tomahawk::InfoSystem::InfoType type );
|
||||
void sendWaitingNotification() const;
|
||||
|
||||
|
||||
void queueStateSafety();
|
||||
|
||||
private:
|
||||
|
@@ -100,7 +100,7 @@ TopTracksContext::onTracksFound( const QList<Tomahawk::query_ptr>& queries, Mode
|
||||
{
|
||||
Q_UNUSED( mode );
|
||||
|
||||
m_topHitsModel->append( queries );
|
||||
m_topHitsModel->appendQueries( queries );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -162,11 +162,9 @@ DatabaseCommand_AddFiles::exec( DatabaseImpl* dbi )
|
||||
m_ids << fileid;
|
||||
added++;
|
||||
}
|
||||
|
||||
qDebug() << "Inserted" << added << "tracks to database";
|
||||
|
||||
if ( added )
|
||||
source()->updateIndexWhenSynced();
|
||||
|
||||
tDebug() << "Committing" << added << "tracks...";
|
||||
|
||||
emit done( m_files, source()->collection() );
|
||||
}
|
||||
|
@@ -62,10 +62,13 @@ DatabaseCommand_DeleteDynamicPlaylist::postCommitHook()
|
||||
if( playlist.isNull() )
|
||||
playlist = source()->collection()->station( m_playlistguid );
|
||||
|
||||
qDebug() << "Just tried to load playlist for deletion:" << m_playlistguid << "Did we get a null one?" << playlist.isNull() << "is it a station?" << (playlist->mode() == OnDemand);
|
||||
tLog( LOGVERBOSE ) << "Just tried to load playlist for deletion:" << m_playlistguid << "Did we get a null one?" << playlist.isNull();
|
||||
Q_ASSERT( !playlist.isNull() );
|
||||
|
||||
playlist->reportDeleted( playlist );
|
||||
if ( !playlist.isNull() )
|
||||
{
|
||||
tLog( LOGVERBOSE ) << "is it a station?" << ( playlist->mode() == OnDemand );
|
||||
playlist->reportDeleted( playlist );
|
||||
}
|
||||
|
||||
if( source()->isLocal() )
|
||||
Servent::instance()->triggerDBSync();
|
||||
|
@@ -91,6 +91,8 @@ DatabaseCommand_GenericSelect::exec( DatabaseImpl* dbi )
|
||||
artist = query.value( 1 ).toString();
|
||||
|
||||
qry = Tomahawk::Query::get( artist, track, QString() );
|
||||
if ( qry.isNull() )
|
||||
continue;
|
||||
}
|
||||
else if ( m_queryType == Artist )
|
||||
{
|
||||
|
@@ -77,6 +77,9 @@ DatabaseCommand_LoadPlaylistEntries::generateEntries( DatabaseImpl* dbi )
|
||||
e->setResultHint( query.value( 8 ).toString() );
|
||||
|
||||
Tomahawk::query_ptr q = Tomahawk::Query::get( query.value( 2 ).toString(), query.value( 1 ).toString(), query.value( 3 ).toString() );
|
||||
if ( q.isNull() )
|
||||
continue;
|
||||
|
||||
q->setResultHint( query.value( 8 ).toString() );
|
||||
q->setProperty( "annotation", e->annotation() );
|
||||
e->setQuery( q );
|
||||
|
@@ -54,6 +54,10 @@ DatabaseCommand_LogPlayback::postCommitHook()
|
||||
// do not auto resolve this track
|
||||
m_query = Tomahawk::Query::get( m_artist, m_track, QString() );
|
||||
}
|
||||
|
||||
if ( m_query.isNull() )
|
||||
return;
|
||||
|
||||
m_query->setPlayedBy( source(), m_playtime );
|
||||
|
||||
if ( m_action == Finished )
|
||||
|
@@ -111,11 +111,18 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook()
|
||||
if( playlist.isNull() ) // if it's neither an auto or station, it must not be auto-loaded, so we MUST have been told about it directly
|
||||
rawPl = m_playlist;
|
||||
|
||||
if ( rawPl == 0 )
|
||||
{
|
||||
tLog() <<"Got null playlist with guid:" << playlistguid() << "from source and collection:" << source()->friendlyName() << source()->collection()->name() << "and mode is static?:" << (m_mode == Static);
|
||||
Q_ASSERT( false );
|
||||
return;
|
||||
}
|
||||
|
||||
// workaround a bug in pre-0.1.0 tomahawks. they created dynamic playlists in OnDemand mode *always*, and then set the mode to the real one.
|
||||
// now that we separate them, if we get them as one and then get a changed mode, the playlist ends up in the wrong bucket in Collection.
|
||||
// so here we fix it if we have to.
|
||||
// HACK
|
||||
tDebug() << "Does this need the 0.3->0.1 playlist category hack fix?" << ( rawPl->mode() == Static && source()->collection()->autoPlaylist( playlistguid() ).isNull() )
|
||||
tDebug() << "Does this need the 0.3->0.1 playlist category hack fix?" << ( rawPl->mode() == Static && source()->collection()->autoPlaylist( playlistguid() ).isNull() )
|
||||
<< ( rawPl->mode() == OnDemand && source()->collection()->station( playlistguid() ).isNull() )
|
||||
<< rawPl->mode() << source()->collection()->autoPlaylist( playlistguid() ).isNull() << source()->collection()->station( playlistguid() ).isNull();
|
||||
if( rawPl->mode() == Static && source()->collection()->autoPlaylist( playlistguid() ).isNull() ) // should be here
|
||||
@@ -123,13 +130,7 @@ DatabaseCommand_SetDynamicPlaylistRevision::postCommitHook()
|
||||
else if ( rawPl->mode() == OnDemand && source()->collection()->station( playlistguid() ).isNull() ) // should be here
|
||||
source()->collection()->moveAutoToStation( playlistguid() );
|
||||
|
||||
if ( rawPl == 0 )
|
||||
{
|
||||
tLog() <<"Got null playlist with guid:" << playlistguid() << "from source and collection:" << source()->friendlyName() << source()->collection()->name() << "and mode is static?:" << (m_mode == Static);
|
||||
Q_ASSERT( false );
|
||||
return;
|
||||
}
|
||||
if ( !m_controlsV.isEmpty() && m_controls.isEmpty() )
|
||||
if ( !m_controlsV.isEmpty() && m_controls.isEmpty() )
|
||||
{
|
||||
QList<QVariantMap> controlMap;
|
||||
foreach( const QVariant& v, m_controlsV )
|
||||
|
@@ -80,7 +80,6 @@ DatabaseCommand_SetPlaylistRevision::DatabaseCommand_SetPlaylistRevision(
|
||||
tmp << s;
|
||||
|
||||
setOrderedguids( tmp );
|
||||
|
||||
setPlaylistguid( playlistguid );
|
||||
}
|
||||
|
||||
@@ -100,7 +99,6 @@ DatabaseCommand_SetPlaylistRevision::postCommitHook()
|
||||
playlist_ptr playlist = source()->collection()->playlist( m_playlistguid );
|
||||
if ( playlist.isNull() )
|
||||
{
|
||||
qDebug() << m_playlistguid;
|
||||
Q_ASSERT( !playlist.isNull() );
|
||||
return;
|
||||
}
|
||||
@@ -150,7 +148,9 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib )
|
||||
|
||||
foreach( const plentry_ptr& e, m_entries )
|
||||
{
|
||||
if ( e->query()->results().isEmpty() )
|
||||
if ( !e->isValid() )
|
||||
continue;
|
||||
if ( !e->query()->numResults() )
|
||||
continue;
|
||||
|
||||
adde.bindValue( 0, e->query()->results().first()->url() );
|
||||
@@ -167,6 +167,9 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib )
|
||||
|
||||
foreach( const plentry_ptr& e, m_entries )
|
||||
{
|
||||
if ( !e->isValid() )
|
||||
continue;
|
||||
|
||||
adde.bindValue( 0, e->query()->track() );
|
||||
adde.bindValue( 1, e->query()->artist() );
|
||||
adde.bindValue( 2, e->query()->album() );
|
||||
@@ -189,6 +192,9 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib )
|
||||
qDebug() << "Num new playlist_items to add:" << m_addedentries.length();
|
||||
foreach( const plentry_ptr& e, m_addedentries )
|
||||
{
|
||||
if ( !e->isValid() )
|
||||
continue;
|
||||
|
||||
// qDebug() << "Adding:" << e->guid() << e->query()->track() << e->query()->artist();
|
||||
|
||||
m_addedmap.insert( e->guid(), e ); // needed in postcommithook
|
||||
|
@@ -77,9 +77,11 @@ public:
|
||||
m_addedentries.clear();
|
||||
foreach( const QVariant& v, vlist )
|
||||
{
|
||||
PlaylistEntry * pep = new PlaylistEntry;
|
||||
PlaylistEntry* pep = new PlaylistEntry;
|
||||
QJson::QObjectHelper::qvariant2qobject( v.toMap(), pep );
|
||||
m_addedentries << plentry_ptr(pep);
|
||||
|
||||
if ( pep->isValid() )
|
||||
m_addedentries << plentry_ptr( pep );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +90,9 @@ public:
|
||||
QVariantList vlist;
|
||||
foreach( const plentry_ptr& pe, m_addedentries )
|
||||
{
|
||||
if ( !pe->isValid() )
|
||||
continue;
|
||||
|
||||
QVariant v = QJson::QObjectHelper::qobject2qvariant( pe.data() );
|
||||
vlist << v;
|
||||
}
|
||||
|
@@ -328,9 +328,10 @@ DatabaseImpl::artistId( const QString& name_orig, bool autoCreate )
|
||||
int id = 0;
|
||||
QString sortname = DatabaseImpl::sortname( name_orig );
|
||||
|
||||
QString queryString = QString( "SELECT id FROM artist WHERE sortname = '%1'" ).arg( TomahawkSqlQuery::escape( sortname ) );
|
||||
TomahawkSqlQuery query = newquery();
|
||||
query.exec( queryString );
|
||||
query.prepare( "SELECT id FROM artist WHERE sortname = ?" );
|
||||
query.addBindValue( sortname );
|
||||
query.exec();
|
||||
if ( query.next() )
|
||||
{
|
||||
id = query.value( 0 ).toInt();
|
||||
|
@@ -49,15 +49,24 @@ FuzzyIndex::FuzzyIndex( QObject* parent, bool wipe )
|
||||
QByteArray path = m_lucenePath.toUtf8();
|
||||
const char* cPath = path.constData();
|
||||
|
||||
bool failed = false;
|
||||
tDebug() << "Opening Lucene directory:" << path;
|
||||
try
|
||||
{
|
||||
m_luceneDir = FSDirectory::getDirectory( cPath );
|
||||
m_analyzer = _CLNEW SimpleAnalyzer();
|
||||
m_luceneDir = FSDirectory::getDirectory( cPath );
|
||||
}
|
||||
catch ( CLuceneError& error )
|
||||
{
|
||||
tDebug() << "Caught CLucene error:" << error.what();
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if ( failed )
|
||||
{
|
||||
tDebug() << "Initializing RAM directory instead.";
|
||||
|
||||
m_luceneDir = _CLNEW RAMDirectory();
|
||||
wipe = true;
|
||||
}
|
||||
|
||||
@@ -83,7 +92,7 @@ FuzzyIndex::wipeIndex()
|
||||
endIndexing();
|
||||
|
||||
QTimer::singleShot( 0, this, SLOT( updateIndex() ) );
|
||||
|
||||
|
||||
return true; // FIXME
|
||||
}
|
||||
|
||||
@@ -189,8 +198,8 @@ FuzzyIndex::appendFields( const QMap< unsigned int, QMap< QString, QString > >&
|
||||
catch( CLuceneError& error )
|
||||
{
|
||||
tDebug() << "Caught CLucene error:" << error.what();
|
||||
|
||||
wipeIndex();
|
||||
|
||||
QTimer::singleShot( 0, this, SLOT( wipeIndex() ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,9 +291,9 @@ FuzzyIndex::search( const Tomahawk::query_ptr& query )
|
||||
}
|
||||
catch( CLuceneError& error )
|
||||
{
|
||||
tDebug() << "Caught CLucene error:" << error.what();
|
||||
|
||||
wipeIndex();
|
||||
tDebug() << "Caught CLucene error:" << error.what() << query->toString();
|
||||
|
||||
QTimer::singleShot( 0, this, SLOT( wipeIndex() ) );
|
||||
}
|
||||
|
||||
return resultsmap;
|
||||
@@ -338,8 +347,8 @@ FuzzyIndex::searchAlbum( const Tomahawk::query_ptr& query )
|
||||
catch( CLuceneError& error )
|
||||
{
|
||||
tDebug() << "Caught CLucene error:" << error.what();
|
||||
|
||||
wipeIndex();
|
||||
|
||||
QTimer::singleShot( 0, this, SLOT( wipeIndex() ) );
|
||||
}
|
||||
|
||||
return resultsmap;
|
||||
|
@@ -61,7 +61,7 @@ public:
|
||||
void beginIndexing();
|
||||
void endIndexing();
|
||||
void appendFields( const QMap< unsigned int, QMap< QString, QString > >& trackData );
|
||||
|
||||
|
||||
signals:
|
||||
void indexReady();
|
||||
|
||||
@@ -73,10 +73,9 @@ public slots:
|
||||
|
||||
private slots:
|
||||
void updateIndex();
|
||||
|
||||
private:
|
||||
bool wipeIndex();
|
||||
|
||||
private:
|
||||
QMutex m_mutex;
|
||||
QString m_lucenePath;
|
||||
|
||||
|
@@ -51,6 +51,14 @@ TomahawkSqlQuery::escape( QString identifier )
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TomahawkSqlQuery::prepare( const QString& query )
|
||||
{
|
||||
m_query = query;
|
||||
return QSqlQuery::prepare( query );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TomahawkSqlQuery::exec( const QString& query )
|
||||
{
|
||||
@@ -76,6 +84,21 @@ TomahawkSqlQuery::exec()
|
||||
unsigned int retries = 0;
|
||||
while ( !QSqlQuery::exec() && ++retries < 10 )
|
||||
{
|
||||
if ( lastError().text().toLower().contains( "no query" ) ||
|
||||
lastError().text().toLower().contains( "parameter count mismatch" ) )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "Re-preparing query!";
|
||||
|
||||
QMap< QString, QVariant > bv = boundValues();
|
||||
prepare( m_query );
|
||||
|
||||
foreach ( const QString& key, bv.keys() )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "Rebinding key" << key << "with value" << bv.value( key );
|
||||
bindValue( key, bv.value( key ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isBusyError( lastError() ) )
|
||||
retries = 0;
|
||||
|
||||
@@ -104,7 +127,7 @@ TomahawkSqlQuery::commitTransaction()
|
||||
#endif
|
||||
if ( log )
|
||||
tLog( LOGSQL ) << "TomahawkSqlQuery::commitTransaction running in thread " << QThread::currentThread();
|
||||
|
||||
|
||||
unsigned int retries = 0;
|
||||
while ( !m_db.commit() && ++retries < 10 )
|
||||
{
|
||||
@@ -114,7 +137,7 @@ TomahawkSqlQuery::commitTransaction()
|
||||
tDebug() << "INFO: Retrying failed commit:" << retries << lastError().text();
|
||||
TomahawkUtils::msleep( 10 );
|
||||
}
|
||||
|
||||
|
||||
return ( retries < 10 );
|
||||
}
|
||||
|
||||
@@ -136,5 +159,5 @@ TomahawkSqlQuery::isBusyError( const QSqlError& error ) const
|
||||
{
|
||||
const QString text = error.text().trimmed().toLower();
|
||||
|
||||
return ( text.contains( "no query" ) || text.contains( "locked" ) || text.contains( "busy" ) || text.isEmpty() );
|
||||
return ( text.contains( "locked" ) || text.contains( "busy" ) || text.isEmpty() );
|
||||
}
|
||||
|
@@ -35,17 +35,19 @@ public:
|
||||
|
||||
static QString escape( QString identifier );
|
||||
|
||||
bool prepare( const QString& query );
|
||||
bool exec( const QString& query );
|
||||
bool exec();
|
||||
|
||||
|
||||
bool commitTransaction();
|
||||
|
||||
private:
|
||||
bool isBusyError( const QSqlError& error ) const;
|
||||
|
||||
void showError();
|
||||
|
||||
|
||||
QSqlDatabase m_db;
|
||||
QString m_query;
|
||||
};
|
||||
|
||||
#endif // TOMAHAWKSQLQUERY_H
|
||||
|
@@ -132,10 +132,11 @@ InfoBar::setDescription( const QString& s )
|
||||
ui->descriptionLabel->setText( s );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InfoBar::setDescription( const artist_ptr& artist )
|
||||
{
|
||||
m_queryLabel->setQuery( Query::get( artist->name(), QString(), QString() ) );
|
||||
m_queryLabel->setArtist( artist );
|
||||
m_queryLabel->setExtraContentsMargins( 4, 0, 0, 0 );
|
||||
|
||||
if ( !m_queryLabel->isVisible() )
|
||||
@@ -151,16 +152,17 @@ InfoBar::setDescription( const artist_ptr& artist )
|
||||
}
|
||||
|
||||
void
|
||||
InfoBar::setDescription( const album_ptr& )
|
||||
InfoBar::setDescription( const album_ptr& )
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InfoBar::artistClicked()
|
||||
{
|
||||
if ( m_queryLabel && !m_queryLabel->query().isNull() )
|
||||
ViewManager::instance()->show( Artist::get( m_queryLabel->artist() ) );
|
||||
if ( m_queryLabel && !m_queryLabel->artist().isNull() )
|
||||
ViewManager::instance()->show( m_queryLabel->artist() );
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +214,6 @@ InfoBar::setUpdaters( const QList<PlaylistUpdaterInterface*>& updaters )
|
||||
newUpdaterWidgets << updater->configurationWidget();
|
||||
}
|
||||
|
||||
|
||||
foreach ( QWidget* updaterWidget, m_updaterConfigurations )
|
||||
{
|
||||
updaterWidget->hide();
|
||||
|
@@ -26,8 +26,10 @@
|
||||
#include <QListView>
|
||||
|
||||
#define ROW_HEIGHT 20
|
||||
#define ICON_PADDING 1
|
||||
#define ICON_PADDING 2
|
||||
#define PADDING 2
|
||||
|
||||
|
||||
JobStatusDelegate::JobStatusDelegate( QObject* parent )
|
||||
: QStyledItemDelegate ( parent )
|
||||
, m_parentView( qobject_cast< QListView* >( parent ) )
|
||||
@@ -35,6 +37,7 @@ JobStatusDelegate::JobStatusDelegate( QObject* parent )
|
||||
Q_ASSERT( m_parentView );
|
||||
}
|
||||
|
||||
|
||||
JobStatusDelegate::~JobStatusDelegate()
|
||||
{
|
||||
|
||||
@@ -55,7 +58,7 @@ JobStatusDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
// painter->drawLine( opt.rect.topLeft(), opt.rect.topRight() );
|
||||
|
||||
painter->setRenderHint( QPainter::Antialiasing );
|
||||
QRect iconRect( ICON_PADDING, ICON_PADDING + opt.rect.y(), ROW_HEIGHT - 2*ICON_PADDING, ROW_HEIGHT - 2*ICON_PADDING );
|
||||
QRect iconRect( ICON_PADDING, ICON_PADDING + opt.rect.y(), ROW_HEIGHT - 2 * ICON_PADDING, ROW_HEIGHT - 2 * ICON_PADDING );
|
||||
if ( allowMultiLine )
|
||||
iconRect.moveTop( opt.rect.top() + opt.rect.height() / 2 - iconRect.height() / 2);
|
||||
QPixmap p = index.data( Qt::DecorationRole ).value< QPixmap >();
|
||||
@@ -71,22 +74,24 @@ JobStatusDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
if ( !rCol.isEmpty() )
|
||||
{
|
||||
const int w = fm.width( rCol );
|
||||
const QRect rRect( opt.rect.right() - PADDING - w, PADDING + opt.rect.y(), w, opt.rect.height() - 2*PADDING );
|
||||
const QRect rRect( opt.rect.right() - PADDING - w, PADDING + opt.rect.y(), w, opt.rect.height() - 2 * PADDING );
|
||||
painter->drawText( rRect, Qt::AlignCenter, rCol );
|
||||
|
||||
rightEdge = rRect.left();
|
||||
}
|
||||
|
||||
const int mainW = rightEdge - 3*PADDING - iconRect.right();
|
||||
const int mainW = rightEdge - 4 * PADDING - iconRect.right();
|
||||
QString mainText = index.data( Qt::DisplayRole ).toString();
|
||||
QTextOption to( Qt::AlignLeft | Qt::AlignVCenter );
|
||||
if ( !allowMultiLine )
|
||||
mainText = fm.elidedText( mainText, Qt::ElideRight, mainW );
|
||||
mainText = fm.elidedText( mainText, Qt::ElideRight, mainW );
|
||||
else
|
||||
to.setWrapMode( QTextOption::WrapAtWordBoundaryOrAnywhere );
|
||||
painter->drawText( QRect( iconRect.right() + 2*PADDING, PADDING + opt.rect.y(), mainW, opt.rect.height() - 2*PADDING ), mainText, to );
|
||||
|
||||
painter->drawText( QRect( iconRect.right() + 4 * PADDING, PADDING + opt.rect.y(), mainW, opt.rect.height() - 2 * PADDING ), mainText, to );
|
||||
}
|
||||
|
||||
|
||||
QSize
|
||||
JobStatusDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
@@ -102,11 +107,11 @@ JobStatusDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelInd
|
||||
initStyleOption( &opt, index );
|
||||
|
||||
const QString text = index.data( Qt::DisplayRole ).toString();
|
||||
const int leftEdge = ICON_PADDING + ROW_HEIGHT + 2*PADDING;
|
||||
const int leftEdge = ICON_PADDING + ROW_HEIGHT + 2 * PADDING;
|
||||
const QRect rect = opt.fontMetrics.boundingRect( leftEdge, opt.rect.top(), m_parentView->width() - leftEdge, 200, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, text );
|
||||
|
||||
m_cachedMultiLineHeights.insert( index, rect.height() + 4*PADDING );
|
||||
m_cachedMultiLineHeights.insert( index, rect.height() + 4 * PADDING );
|
||||
|
||||
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), rect.height() + 4*PADDING );
|
||||
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), rect.height() + 4 * PADDING );
|
||||
}
|
||||
|
||||
|
@@ -101,13 +101,12 @@ JobStatusView::setModel( JobStatusModel* m )
|
||||
void
|
||||
JobStatusView::customDelegateJobInserted( int row, JobStatusItem* item )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "item is " << item << ", row is " << row;
|
||||
tLog() << Q_FUNC_INFO << "item is" << item << ", row is" << row;
|
||||
if ( !item )
|
||||
return;
|
||||
|
||||
tLog() << Q_FUNC_INFO << "telling item to create delegate";
|
||||
item->createDelegate( m_view );
|
||||
tLog() << Q_FUNC_INFO << "item delegate is " << item->customDelegate();
|
||||
tLog() << Q_FUNC_INFO << "item delegate is" << item->customDelegate();
|
||||
m_view->setItemDelegateForRow( row, item->customDelegate() );
|
||||
AclJobDelegate* delegate = qobject_cast< AclJobDelegate* >( item->customDelegate() );
|
||||
if ( delegate )
|
||||
@@ -127,7 +126,7 @@ JobStatusView::customDelegateJobInserted( int row, JobStatusItem* item )
|
||||
void
|
||||
JobStatusView::customDelegateJobRemoved( int row )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "row is " << row;
|
||||
tLog() << Q_FUNC_INFO << "row is" << row;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,12 +137,12 @@ JobStatusView::refreshDelegates()
|
||||
int count = m_model->rowCount();
|
||||
for ( int i = 0; i < count; i++ )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "checking row " << i;
|
||||
tLog() << Q_FUNC_INFO << "checking row" << i;
|
||||
QModelIndex index = m_model->index( i );
|
||||
QVariant itemVar = index.data( JobStatusModel::JobDataRole );
|
||||
if ( !itemVar.canConvert< JobStatusItem* >() || !itemVar.value< JobStatusItem* >() )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "unable to fetch JobStatusItem* at row " << i;
|
||||
tLog() << Q_FUNC_INFO << "unable to fetch JobStatusItem* at row" << i;
|
||||
continue;
|
||||
}
|
||||
JobStatusItem* item = itemVar.value< JobStatusItem* >();
|
||||
|
@@ -30,7 +30,7 @@ LatchedStatusItem::LatchedStatusItem( const Tomahawk::source_ptr& from, const To
|
||||
, m_to( to )
|
||||
, m_parent( parent )
|
||||
{
|
||||
m_text = tr( "%1 is listening along to you!" ).arg( from->friendlyName() );
|
||||
m_text = tr( "%1 is listening along with you!" ).arg( from->friendlyName() );
|
||||
}
|
||||
|
||||
LatchedStatusItem::~LatchedStatusItem()
|
||||
|
@@ -29,11 +29,14 @@
|
||||
|
||||
QPixmap* PipelineStatusItem::s_pixmap = 0;
|
||||
|
||||
PipelineStatusItem::PipelineStatusItem()
|
||||
PipelineStatusItem::PipelineStatusItem( const Tomahawk::query_ptr& q )
|
||||
: JobStatusItem()
|
||||
{
|
||||
connect( Tomahawk::Pipeline::instance(), SIGNAL( resolving( Tomahawk::query_ptr ) ), this, SLOT( resolving( Tomahawk::query_ptr ) ) );
|
||||
connect( Tomahawk::Pipeline::instance(), SIGNAL( idle() ), this, SLOT( idle() ) );
|
||||
|
||||
if ( !q.isNull() )
|
||||
resolving( q );
|
||||
}
|
||||
|
||||
|
||||
@@ -102,11 +105,10 @@ PipelineStatusManager::PipelineStatusManager( QObject* parent )
|
||||
void
|
||||
PipelineStatusManager::resolving( const Tomahawk::query_ptr& p )
|
||||
{
|
||||
Q_UNUSED( p );
|
||||
if ( m_curItem.isNull() )
|
||||
{
|
||||
// No current query item and we're resolving something, so show it
|
||||
m_curItem = QWeakPointer< PipelineStatusItem >( new PipelineStatusItem );
|
||||
m_curItem = QWeakPointer< PipelineStatusItem >( new PipelineStatusItem( p ) );
|
||||
JobStatusView::instance()->model()->addJob( m_curItem.data() );
|
||||
}
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ class PipelineStatusItem : public JobStatusItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PipelineStatusItem();
|
||||
explicit PipelineStatusItem( const Tomahawk::query_ptr& q );
|
||||
virtual ~PipelineStatusItem();
|
||||
|
||||
virtual QString rightColumnText() const;
|
||||
|
@@ -107,16 +107,17 @@ void
|
||||
DBSyncConnection::check()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << this << m_source->id();
|
||||
if ( m_state != UNKNOWN && m_state != SYNCED )
|
||||
{
|
||||
qDebug() << "Syncing in progress already.";
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_state == SHUTDOWN )
|
||||
{
|
||||
qDebug() << "Aborting sync due to shutdown.";
|
||||
return;
|
||||
}
|
||||
if ( m_state != UNKNOWN && m_state != SYNCED )
|
||||
{
|
||||
qDebug() << "Syncing in progress already.";
|
||||
return;
|
||||
}
|
||||
|
||||
m_uscache.clear();
|
||||
changeState( CHECKING );
|
||||
|
@@ -112,7 +112,7 @@ CustomPlaylistView::tracksGenerated( QList< query_ptr > tracks )
|
||||
return;
|
||||
|
||||
m_model->clear();
|
||||
m_model->append( newTracks );
|
||||
m_model->appendQueries( newTracks );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -56,7 +56,10 @@ GridItemDelegate::GridItemDelegate( QAbstractItemView* parent, PlayableProxyMode
|
||||
if ( m_view && m_view->metaObject()->indexOfSignal( "modelChanged()" ) > -1 )
|
||||
connect( m_view, SIGNAL( modelChanged() ), this, SLOT( modelChanged() ) );
|
||||
|
||||
connect( m_view, SIGNAL( scrolledContents( int, int ) ), SLOT( onScrolled( int, int ) ) );
|
||||
connect( proxy, SIGNAL( rowsAboutToBeInserted( QModelIndex, int, int ) ), SLOT( modelChanged() ) );
|
||||
connect( proxy, SIGNAL( rowsAboutToBeRemoved( QModelIndex, int, int ) ), SLOT( modelChanged() ) );
|
||||
connect( m_view, SIGNAL( scrolledContents( int, int ) ), SLOT( onViewChanged() ) );
|
||||
connect( m_view, SIGNAL( resized() ), SLOT( onViewChanged() ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -116,8 +119,8 @@ GridItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
m_covers.insert( index, QSharedPointer< Tomahawk::PixmapDelegateFader >( new Tomahawk::PixmapDelegateFader( item->query(), r.size(), TomahawkUtils::Grid ) ) );
|
||||
}
|
||||
|
||||
_detail::Closure* closure = NewClosure( m_covers[ index ], SIGNAL( repaintRequest() ), const_cast<GridItemDelegate*>(this), SLOT( doUpdateIndex( QPersistentModelIndex ) ), QPersistentModelIndex( index ) );
|
||||
closure->setAutoDelete( false );
|
||||
NewClosure( m_covers[ index ], SIGNAL( repaintRequest() ),
|
||||
const_cast<GridItemDelegate*>(this), SLOT( doUpdateIndex( QPersistentModelIndex ) ), QPersistentModelIndex( index ) )->setAutoDelete( false );
|
||||
}
|
||||
|
||||
QSharedPointer< Tomahawk::PixmapDelegateFader > fader = m_covers[ index ];
|
||||
@@ -237,14 +240,18 @@ GridItemDelegate::onPlayClicked( const QPersistentModelIndex& index )
|
||||
PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) );
|
||||
if ( item )
|
||||
{
|
||||
_detail::Closure* closure;
|
||||
NewClosure( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ),
|
||||
const_cast<GridItemDelegate*>(this), SLOT( onPlaybackStarted( QPersistentModelIndex ) ), QPersistentModelIndex( index ) );
|
||||
|
||||
closure = NewClosure( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ),
|
||||
const_cast<GridItemDelegate*>(this), SLOT( onPlaybackStarted( QPersistentModelIndex ) ), QPersistentModelIndex( index ) );
|
||||
m_closures.remove( index );
|
||||
|
||||
closure = NewClosure( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ),
|
||||
const_cast<GridItemDelegate*>(this), SLOT( onPlaylistChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) );
|
||||
closure->setAutoDelete( false );
|
||||
m_closures.insertMulti( index, NewClosure( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ),
|
||||
const_cast<GridItemDelegate*>(this), SLOT( onPlaylistChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ) );
|
||||
m_closures.insertMulti( index, NewClosure( AudioEngine::instance(), SIGNAL( stopped() ),
|
||||
const_cast<GridItemDelegate*>(this), SLOT( onPlaylistChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ) );
|
||||
|
||||
foreach ( _detail::Closure* closure, m_closures.values( index ) )
|
||||
closure->setAutoDelete( false );
|
||||
|
||||
connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackFinished() ) );
|
||||
|
||||
@@ -421,19 +428,22 @@ GridItemDelegate::doUpdateIndex( const QPersistentModelIndex& idx )
|
||||
|
||||
|
||||
void
|
||||
GridItemDelegate::onScrolled( int dx, int dy )
|
||||
GridItemDelegate::onViewChanged()
|
||||
{
|
||||
foreach ( QWidget* widget, m_spinner.values() )
|
||||
foreach ( const QPersistentModelIndex& index, m_spinner.keys() )
|
||||
{
|
||||
widget->move( widget->pos() + QPoint( dx, dy ) );
|
||||
QRect rect = m_view->visualRect( index );
|
||||
m_spinner.value( index )->move( rect.center() - QPoint( 23, 23 ) );
|
||||
}
|
||||
foreach ( ImageButton* button, m_playButton.values() )
|
||||
foreach ( const QPersistentModelIndex& index, m_playButton.keys() )
|
||||
{
|
||||
button->move( button->pos() + QPoint( dx, dy ) );
|
||||
QRect rect = m_view->visualRect( index );
|
||||
m_playButton.value( index )->move( rect.center() - QPoint( 23, 23 ) );
|
||||
}
|
||||
foreach ( ImageButton* button, m_pauseButton.values() )
|
||||
foreach ( const QPersistentModelIndex& index, m_pauseButton.keys() )
|
||||
{
|
||||
button->move( button->pos() + QPoint( dx, dy ) );
|
||||
QRect rect = m_view->visualRect( index );
|
||||
m_pauseButton.value( index )->move( rect.center() - QPoint( 23, 23 ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,11 +483,19 @@ GridItemDelegate::onPlaylistChanged( const QPersistentModelIndex& index )
|
||||
|
||||
if ( finished )
|
||||
{
|
||||
foreach ( _detail::Closure* closure, m_closures.values( index ) )
|
||||
closure->deleteLater();
|
||||
|
||||
if ( m_pauseButton.contains( index ) )
|
||||
{
|
||||
m_pauseButton[ index ]->deleteLater();
|
||||
m_pauseButton.remove( index );
|
||||
}
|
||||
if ( m_spinner.contains( index ) )
|
||||
{
|
||||
m_spinner[ index ]->deleteLater();
|
||||
m_spinner.remove( index );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,6 +29,10 @@ namespace Tomahawk {
|
||||
class PixmapDelegateFader;
|
||||
}
|
||||
|
||||
namespace _detail {
|
||||
class Closure;
|
||||
}
|
||||
|
||||
class QEvent;
|
||||
class QTimeLine;
|
||||
class PlayableProxyModel;
|
||||
@@ -55,7 +59,7 @@ private slots:
|
||||
void modelChanged();
|
||||
void doUpdateIndex( const QPersistentModelIndex& idx );
|
||||
|
||||
void onScrolled( int dx, int dy );
|
||||
void onViewChanged();
|
||||
void onPlaybackStarted( const QPersistentModelIndex& index );
|
||||
void onPlaybackFinished();
|
||||
|
||||
@@ -64,6 +68,7 @@ private slots:
|
||||
|
||||
void fadingFrameChanged( const QPersistentModelIndex& );
|
||||
void fadingFrameFinished( const QPersistentModelIndex& );
|
||||
|
||||
private:
|
||||
QTimeLine* createTimeline( QTimeLine::Direction direction );
|
||||
|
||||
@@ -81,8 +86,8 @@ private:
|
||||
mutable QHash< QPersistentModelIndex, QWidget* > m_spinner;
|
||||
mutable QHash< QPersistentModelIndex, ImageButton* > m_playButton;
|
||||
mutable QHash< QPersistentModelIndex, ImageButton* > m_pauseButton;
|
||||
|
||||
mutable QHash< QPersistentModelIndex, QTimeLine* > m_hoverFaders;
|
||||
mutable QHash< QPersistentModelIndex, _detail::Closure* > m_closures;
|
||||
};
|
||||
|
||||
#endif // GRIDITEMDELEGATE_H
|
||||
|
@@ -77,9 +77,6 @@ GridView::GridView( QWidget* parent )
|
||||
setAutoResize( false );
|
||||
setProxyModel( new PlayableProxyModel( this ) );
|
||||
|
||||
/* m_overlay->setText( tr( "After you have scanned your music collection you will find your latest album additions right here." ) );
|
||||
m_overlay->setText( tr( "This collection doesn't have any recent albums." ) );*/
|
||||
|
||||
connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) );
|
||||
connect( this, SIGNAL( customContextMenuRequested( QPoint ) ), SLOT( onCustomContextMenu( QPoint ) ) );
|
||||
|
||||
@@ -208,6 +205,8 @@ GridView::resizeEvent( QResizeEvent* event )
|
||||
{
|
||||
QListView::resizeEvent( event );
|
||||
layoutItems();
|
||||
|
||||
emit resized();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -78,6 +78,7 @@ public slots:
|
||||
signals:
|
||||
void modelChanged();
|
||||
void scrolledContents( int dx, int dy );
|
||||
void resized();
|
||||
|
||||
protected:
|
||||
virtual void startDrag( Qt::DropActions supportedActions );
|
||||
|
@@ -89,12 +89,6 @@ PlayableItem::PlayableItem( const Tomahawk::query_ptr& query, PlayableItem* pare
|
||||
connect( query.data(), SIGNAL( updated() ),
|
||||
SIGNAL( dataChanged() ) );
|
||||
|
||||
connect( query.data(), SIGNAL( resultsAdded( QList<Tomahawk::result_ptr> ) ),
|
||||
SLOT( onResultsChanged() ) );
|
||||
|
||||
connect( query.data(), SIGNAL( resultsRemoved( Tomahawk::result_ptr ) ),
|
||||
SLOT( onResultsChanged() ) );
|
||||
|
||||
connect( query.data(), SIGNAL( resultsChanged() ),
|
||||
SLOT( onResultsChanged() ) );
|
||||
}
|
||||
@@ -113,12 +107,6 @@ PlayableItem::PlayableItem( const Tomahawk::plentry_ptr& entry, PlayableItem* pa
|
||||
connect( m_query.data(), SIGNAL( updated() ),
|
||||
SIGNAL( dataChanged() ) );
|
||||
|
||||
connect( m_query.data(), SIGNAL( resultsAdded( QList<Tomahawk::result_ptr> ) ),
|
||||
SLOT( onResultsChanged() ) );
|
||||
|
||||
connect( m_query.data(), SIGNAL( resultsRemoved( Tomahawk::result_ptr ) ),
|
||||
SLOT( onResultsChanged() ) );
|
||||
|
||||
connect( m_query.data(), SIGNAL( resultsChanged() ),
|
||||
SLOT( onResultsChanged() ) );
|
||||
}
|
||||
@@ -130,7 +118,7 @@ PlayableItem::init( PlayableItem* parent, int row )
|
||||
m_fetchingMore = false;
|
||||
m_isPlaying = false;
|
||||
m_parent = parent;
|
||||
|
||||
|
||||
if ( parent )
|
||||
{
|
||||
if ( row < 0 )
|
||||
@@ -145,7 +133,7 @@ PlayableItem::init( PlayableItem* parent, int row )
|
||||
|
||||
this->model = parent->model;
|
||||
}
|
||||
|
||||
|
||||
if ( !m_query.isNull() )
|
||||
{
|
||||
onResultsChanged();
|
||||
|
@@ -46,7 +46,7 @@ PlayableModel::PlayableModel( QObject* parent, bool loading )
|
||||
{
|
||||
connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection );
|
||||
connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection );
|
||||
|
||||
|
||||
m_header << tr( "Artist" ) << tr( "Title" ) << tr( "Composer" ) << tr( "Album" ) << tr( "Track" ) << tr( "Duration" )
|
||||
<< tr( "Bitrate" ) << tr( "Age" ) << tr( "Year" ) << tr( "Size" ) << tr( "Origin" ) << tr( "Score" ) << tr( "Name" );
|
||||
|
||||
@@ -200,11 +200,11 @@ PlayableModel::queryData( const query_ptr& query, int column, int role ) const
|
||||
case Album:
|
||||
return query->album();
|
||||
break;
|
||||
|
||||
|
||||
case Composer:
|
||||
return query->composer();
|
||||
break;
|
||||
|
||||
|
||||
case Duration:
|
||||
return TomahawkUtils::timeToString( query->duration() );
|
||||
break;
|
||||
@@ -223,7 +223,7 @@ PlayableModel::queryData( const query_ptr& query, int column, int role ) const
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -256,7 +256,7 @@ PlayableModel::queryData( const query_ptr& query, int column, int role ) const
|
||||
case Score:
|
||||
return query->results().first()->score();
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -305,7 +305,7 @@ PlayableModel::data( const QModelIndex& index, int role ) const
|
||||
{
|
||||
return albumData( entry->album(), role );
|
||||
}
|
||||
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
@@ -576,20 +576,6 @@ PlayableModel::queries() const
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
PlayableModel::insertInternal( const T& item, int row )
|
||||
{
|
||||
if ( item.isNull() )
|
||||
return;
|
||||
|
||||
QList< T > list;
|
||||
list << item;
|
||||
|
||||
insert( list, row );
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
PlayableModel::insertInternal( const QList< T >& items, int row )
|
||||
@@ -598,7 +584,7 @@ PlayableModel::insertInternal( const QList< T >& items, int row )
|
||||
{
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
emit itemCountChanged( rowCount( QModelIndex() ) );
|
||||
|
||||
|
||||
finishLoading();
|
||||
return;
|
||||
}
|
||||
@@ -633,12 +619,12 @@ PlayableModel::insertInternal( const QList< T >& items, int row )
|
||||
void
|
||||
PlayableModel::remove( int row, bool moreToCome )
|
||||
{
|
||||
remove( index( row, 0, QModelIndex() ), moreToCome );
|
||||
removeIndex( index( row, 0, QModelIndex() ), moreToCome );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::remove( const QModelIndex& index, bool moreToCome )
|
||||
PlayableModel::removeIndex( const QModelIndex& index, bool moreToCome )
|
||||
{
|
||||
if ( QThread::currentThread() != thread() )
|
||||
{
|
||||
@@ -666,7 +652,7 @@ PlayableModel::remove( const QModelIndex& index, bool moreToCome )
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::remove( const QList<QModelIndex>& indexes )
|
||||
PlayableModel::removeIndexes( const QList<QModelIndex>& indexes )
|
||||
{
|
||||
QList<QPersistentModelIndex> pil;
|
||||
foreach ( const QModelIndex& idx, indexes )
|
||||
@@ -674,12 +660,12 @@ PlayableModel::remove( const QList<QModelIndex>& indexes )
|
||||
pil << idx;
|
||||
}
|
||||
|
||||
remove( pil );
|
||||
removeIndexes( pil );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::remove( const QList<QPersistentModelIndex>& indexes )
|
||||
PlayableModel::removeIndexes( const QList<QPersistentModelIndex>& indexes )
|
||||
{
|
||||
QList<QPersistentModelIndex> finalIndexes;
|
||||
foreach ( const QPersistentModelIndex index, indexes )
|
||||
@@ -691,7 +677,7 @@ PlayableModel::remove( const QList<QPersistentModelIndex>& indexes )
|
||||
|
||||
for ( int i = 0; i < finalIndexes.count(); i++ )
|
||||
{
|
||||
remove( finalIndexes.at( i ), i + 1 != finalIndexes.count() );
|
||||
removeIndex( finalIndexes.at( i ), i + 1 != finalIndexes.count() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -828,84 +814,102 @@ PlayableModel::itemFromIndex( const QModelIndex& index ) const
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::append( const Tomahawk::artist_ptr& artist )
|
||||
PlayableModel::appendArtist( const Tomahawk::artist_ptr& artist )
|
||||
{
|
||||
insert( artist, rowCount( QModelIndex() ) );
|
||||
QList< artist_ptr > artists;
|
||||
artists << artist;
|
||||
|
||||
appendArtists( artists );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::append( const Tomahawk::album_ptr& album )
|
||||
PlayableModel::appendAlbum( const Tomahawk::album_ptr& album )
|
||||
{
|
||||
insert( album, rowCount( QModelIndex() ) );
|
||||
QList< album_ptr > albums;
|
||||
albums << album;
|
||||
|
||||
appendAlbums( albums );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::append( const Tomahawk::query_ptr& query )
|
||||
PlayableModel::appendQuery( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
insert( query, rowCount( QModelIndex() ) );
|
||||
QList< query_ptr > queries;
|
||||
queries << query;
|
||||
|
||||
appendQueries( queries );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::append( const QList< Tomahawk::artist_ptr >& artists )
|
||||
PlayableModel::appendArtists( const QList< Tomahawk::artist_ptr >& artists )
|
||||
{
|
||||
insert( artists, rowCount( QModelIndex() ) );
|
||||
insertArtists( artists, rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::append( const QList< Tomahawk::album_ptr >& albums )
|
||||
PlayableModel::appendAlbums( const QList< Tomahawk::album_ptr >& albums )
|
||||
{
|
||||
insert( albums, rowCount( QModelIndex() ) );
|
||||
insertAlbums( albums, rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::append( const QList< Tomahawk::query_ptr >& queries )
|
||||
PlayableModel::appendQueries( const QList< Tomahawk::query_ptr >& queries )
|
||||
{
|
||||
insert( queries, rowCount( QModelIndex() ) );
|
||||
insertQueries( queries, rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::insert( const Tomahawk::artist_ptr& artist, int row )
|
||||
PlayableModel::insertArtist( const Tomahawk::artist_ptr& artist, int row )
|
||||
{
|
||||
insertInternal( artist, row );
|
||||
QList< artist_ptr > artists;
|
||||
artists << artist;
|
||||
|
||||
insertArtists( artists, row );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::insert( const Tomahawk::album_ptr& album, int row )
|
||||
PlayableModel::insertAlbum( const Tomahawk::album_ptr& album, int row )
|
||||
{
|
||||
insertInternal( album, row );
|
||||
QList< album_ptr > albums;
|
||||
albums << album;
|
||||
|
||||
insertAlbums( albums, row );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::insert( const Tomahawk::query_ptr& query, int row )
|
||||
PlayableModel::insertQuery( const Tomahawk::query_ptr& query, int row )
|
||||
{
|
||||
insertInternal( query, row );
|
||||
QList< query_ptr > queries;
|
||||
queries << query;
|
||||
|
||||
insertQueries( queries, row );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::insert( const QList< Tomahawk::artist_ptr >& artists, int row )
|
||||
PlayableModel::insertArtists( const QList< Tomahawk::artist_ptr >& artists, int row )
|
||||
{
|
||||
insertInternal( artists, row );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::insert( const QList< Tomahawk::album_ptr >& albums, int row )
|
||||
PlayableModel::insertAlbums( const QList< Tomahawk::album_ptr >& albums, int row )
|
||||
{
|
||||
insertInternal( albums, row );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableModel::insert( const QList< Tomahawk::query_ptr >& queries, int row )
|
||||
PlayableModel::insertQueries( const QList< Tomahawk::query_ptr >& queries, int row )
|
||||
{
|
||||
insertInternal( queries, row );
|
||||
}
|
||||
|
@@ -91,7 +91,7 @@ public:
|
||||
|
||||
virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
|
||||
virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const;
|
||||
|
||||
|
||||
virtual QVariant artistData( const Tomahawk::artist_ptr& artist, int role = Qt::DisplayRole ) const;
|
||||
virtual QVariant albumData( const Tomahawk::album_ptr& album, int role = Qt::DisplayRole ) const;
|
||||
virtual QVariant queryData( const Tomahawk::query_ptr&, int column, int role = Qt::DisplayRole ) const;
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
QList< Tomahawk::query_ptr > queries() const;
|
||||
|
||||
void updateDetailedInfo( const QModelIndex& index );
|
||||
|
||||
|
||||
QSize itemSize() const { return m_itemSize; }
|
||||
void setItemSize( const QSize& size ) { m_itemSize = size; }
|
||||
|
||||
@@ -136,24 +136,24 @@ public slots:
|
||||
|
||||
virtual void clear();
|
||||
|
||||
virtual void append( const QList< Tomahawk::query_ptr >& queries );
|
||||
virtual void append( const QList< Tomahawk::artist_ptr >& artists );
|
||||
virtual void append( const QList< Tomahawk::album_ptr >& albums );
|
||||
virtual void append( const Tomahawk::query_ptr& query );
|
||||
virtual void append( const Tomahawk::artist_ptr& artist );
|
||||
virtual void append( const Tomahawk::album_ptr& album );
|
||||
virtual void appendQueries( const QList< Tomahawk::query_ptr >& queries );
|
||||
virtual void appendArtists( const QList< Tomahawk::artist_ptr >& artists );
|
||||
virtual void appendAlbums( const QList< Tomahawk::album_ptr >& albums );
|
||||
virtual void appendQuery( const Tomahawk::query_ptr& query );
|
||||
virtual void appendArtist( const Tomahawk::artist_ptr& artist );
|
||||
virtual void appendAlbum( const Tomahawk::album_ptr& album );
|
||||
|
||||
virtual void insert( const QList< Tomahawk::query_ptr >& queries, int row = 0 );
|
||||
virtual void insert( const QList< Tomahawk::artist_ptr >& artists, int row = 0 );
|
||||
virtual void insert( const QList< Tomahawk::album_ptr >& albums, int row = 0 );
|
||||
virtual void insert( const Tomahawk::query_ptr& query, int row = 0 );
|
||||
virtual void insert( const Tomahawk::artist_ptr& artist, int row = 0 );
|
||||
virtual void insert( const Tomahawk::album_ptr& album, int row = 0 );
|
||||
virtual void insertQueries( const QList< Tomahawk::query_ptr >& queries, int row = 0 );
|
||||
virtual void insertArtists( const QList< Tomahawk::artist_ptr >& artists, int row = 0 );
|
||||
virtual void insertAlbums( const QList< Tomahawk::album_ptr >& albums, int row = 0 );
|
||||
virtual void insertQuery( const Tomahawk::query_ptr& query, int row = 0 );
|
||||
virtual void insertArtist( const Tomahawk::artist_ptr& artist, int row = 0 );
|
||||
virtual void insertAlbum( const Tomahawk::album_ptr& album, int row = 0 );
|
||||
|
||||
virtual void remove( int row, bool moreToCome = false );
|
||||
virtual void remove( const QModelIndex& index, bool moreToCome = false );
|
||||
virtual void remove( const QList<QModelIndex>& indexes );
|
||||
virtual void remove( const QList<QPersistentModelIndex>& indexes );
|
||||
virtual void removeIndex( const QModelIndex& index, bool moreToCome = false );
|
||||
virtual void removeIndexes( const QList<QModelIndex>& indexes );
|
||||
virtual void removeIndexes( const QList<QPersistentModelIndex>& indexes );
|
||||
|
||||
virtual void setRepeatMode( Tomahawk::PlaylistModes::RepeatMode /*mode*/ ) {}
|
||||
virtual void setShuffled( bool /*shuffled*/ ) {}
|
||||
@@ -170,8 +170,6 @@ private slots:
|
||||
private:
|
||||
template <typename T>
|
||||
void insertInternal( const QList< T >& items, int row );
|
||||
template <typename T>
|
||||
void insertInternal( const T& item, int row );
|
||||
|
||||
Qt::Alignment columnAlignment( int column ) const;
|
||||
|
||||
|
@@ -84,7 +84,7 @@ PlayableProxyModel::setSourcePlayableModel( PlayableModel* sourceModel )
|
||||
{
|
||||
if ( m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 )
|
||||
connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), playlistInterface().data(), SIGNAL( sourceTrackCountChanged( unsigned int ) ) );
|
||||
|
||||
|
||||
connect( m_model, SIGNAL( loadingStarted() ), SIGNAL( loadingStarted() ) );
|
||||
connect( m_model, SIGNAL( loadingFinished() ), SIGNAL( loadingFinished() ) );
|
||||
}
|
||||
@@ -99,10 +99,10 @@ PlayableProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourcePa
|
||||
PlayableItem* pi = itemFromIndex( sourceModel()->index( sourceRow, 0, sourceParent ) );
|
||||
if ( !pi )
|
||||
return false;
|
||||
|
||||
|
||||
if ( m_maxVisibleItems >= 0 && sourceRow > m_maxVisibleItems - 1 )
|
||||
return false;
|
||||
|
||||
|
||||
if ( m_hideDupeItems )
|
||||
{
|
||||
for ( int i = 0; i < sourceRow; i++ )
|
||||
@@ -132,10 +132,10 @@ PlayableProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourcePa
|
||||
|
||||
if ( !m_showOfflineResults && !r.isNull() && !r->isOnline() )
|
||||
return false;
|
||||
|
||||
|
||||
if ( filterRegExp().isEmpty() )
|
||||
return true;
|
||||
|
||||
|
||||
QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts );
|
||||
foreach( QString s, sl )
|
||||
{
|
||||
@@ -188,19 +188,19 @@ PlayableProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourcePa
|
||||
|
||||
|
||||
void
|
||||
PlayableProxyModel::remove( const QModelIndex& index )
|
||||
PlayableProxyModel::removeIndex( const QModelIndex& index )
|
||||
{
|
||||
if ( !sourceModel() )
|
||||
return;
|
||||
if ( !index.isValid() )
|
||||
return;
|
||||
|
||||
sourceModel()->remove( mapToSource( index ) );
|
||||
sourceModel()->removeIndex( mapToSource( index ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableProxyModel::remove( const QModelIndexList& indexes )
|
||||
PlayableProxyModel::removeIndexes( const QModelIndexList& indexes )
|
||||
{
|
||||
if ( !sourceModel() )
|
||||
return;
|
||||
@@ -212,12 +212,12 @@ PlayableProxyModel::remove( const QModelIndexList& indexes )
|
||||
pil << mapToSource( idx );
|
||||
}
|
||||
|
||||
sourceModel()->remove( pil );
|
||||
sourceModel()->removeIndexes( pil );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlayableProxyModel::remove( const QList< QPersistentModelIndex >& indexes )
|
||||
PlayableProxyModel::removeIndexes( const QList< QPersistentModelIndex >& indexes )
|
||||
{
|
||||
if ( !sourceModel() )
|
||||
return;
|
||||
@@ -229,7 +229,7 @@ PlayableProxyModel::remove( const QList< QPersistentModelIndex >& indexes )
|
||||
pil << mapToSource( idx );
|
||||
}
|
||||
|
||||
sourceModel()->remove( pil );
|
||||
sourceModel()->removeIndexes( pil );
|
||||
}
|
||||
|
||||
|
||||
@@ -269,6 +269,8 @@ PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const T
|
||||
const QString album2 = q2->albumSortname();
|
||||
const QString track1 = q1->trackSortname();
|
||||
const QString track2 = q2->trackSortname();
|
||||
const QString composer1 = q1->composerSortname();
|
||||
const QString composer2 = q2->composerSortname();
|
||||
const unsigned int albumpos1 = q1->albumpos();
|
||||
const unsigned int albumpos2 = q2->albumpos();
|
||||
const unsigned int discnumber1 = q1->discnumber();
|
||||
@@ -277,6 +279,8 @@ PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const T
|
||||
unsigned int mtime1 = 0, mtime2 = 0;
|
||||
unsigned int size1 = 0, size2 = 0;
|
||||
float score1 = 0, score2 = 0;
|
||||
QString origin1;
|
||||
QString origin2;
|
||||
qint64 id1 = 0, id2 = 0;
|
||||
|
||||
if ( q1->numResults() )
|
||||
@@ -286,6 +290,7 @@ PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const T
|
||||
mtime1 = r->modificationTime();
|
||||
size1 = r->size();
|
||||
score1 = r->score();
|
||||
origin1 = r->friendlySource().toLower();
|
||||
id1 = (qint64)&r;
|
||||
}
|
||||
if ( q2->numResults() )
|
||||
@@ -295,6 +300,7 @@ PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const T
|
||||
mtime2 = r->modificationTime();
|
||||
size2 = r->size();
|
||||
score2 = r->score();
|
||||
origin2 = r->friendlySource().toLower();
|
||||
id2 = (qint64)&r;
|
||||
}
|
||||
|
||||
@@ -327,6 +333,28 @@ PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const T
|
||||
|
||||
return QString::localeAwareCompare( artist1, artist2 ) < 0;
|
||||
}
|
||||
else if ( column == PlayableModel::Composer ) // sort by composer
|
||||
{
|
||||
if ( composer1 == composer2 )
|
||||
{
|
||||
if ( album1 == album2 )
|
||||
{
|
||||
if ( discnumber1 == discnumber2 )
|
||||
{
|
||||
if ( albumpos1 == albumpos2 )
|
||||
return id1 < id2;
|
||||
|
||||
return albumpos1 < albumpos2;
|
||||
}
|
||||
|
||||
return discnumber1 < discnumber2;
|
||||
}
|
||||
|
||||
return QString::localeAwareCompare( album1, album2 ) < 0;
|
||||
}
|
||||
|
||||
return QString::localeAwareCompare( composer1, composer2 ) < 0;
|
||||
}
|
||||
else if ( column == PlayableModel::Album ) // sort by album
|
||||
{
|
||||
if ( album1 == album2 )
|
||||
@@ -372,6 +400,13 @@ PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const T
|
||||
|
||||
return score1 < score2;
|
||||
}
|
||||
else if ( column == PlayableModel::Origin ) // sort by file origin
|
||||
{
|
||||
if ( origin1 == origin2 )
|
||||
return id1 < id2;
|
||||
|
||||
return origin1 < origin2;
|
||||
}
|
||||
else if ( column == PlayableModel::AlbumPos ) // sort by album pos
|
||||
{
|
||||
if ( discnumber1 != discnumber2 )
|
||||
@@ -384,7 +419,7 @@ PlayableProxyModel::lessThan( int column, const Tomahawk::query_ptr& q1, const T
|
||||
return albumpos1 < albumpos2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const QString& lefts = q1->track();
|
||||
const QString& rights = q2->track();
|
||||
if ( lefts == rights )
|
||||
|
@@ -44,9 +44,9 @@ public:
|
||||
virtual QPersistentModelIndex currentIndex() const { return mapFromSource( m_model->currentItem() ); }
|
||||
virtual void setCurrentIndex( const QModelIndex& index ) { m_model->setCurrentItem( mapToSource( index ) ); }
|
||||
|
||||
virtual void remove( const QModelIndex& index );
|
||||
virtual void remove( const QModelIndexList& indexes );
|
||||
virtual void remove( const QList< QPersistentModelIndex >& indexes );
|
||||
virtual void removeIndex( const QModelIndex& index );
|
||||
virtual void removeIndexes( const QModelIndexList& indexes );
|
||||
virtual void removeIndexes( const QList< QPersistentModelIndex >& indexes );
|
||||
|
||||
virtual bool showOfflineResults() const { return m_showOfflineResults; }
|
||||
virtual void setShowOfflineResults( bool b );
|
||||
|
@@ -227,7 +227,7 @@ PlaylistItemDelegate::paintDetailed( QPainter* painter, const QStyleOptionViewIt
|
||||
opt.text.clear();
|
||||
qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter );
|
||||
|
||||
if ( m_view->hoveredIndex().row() == index.row() && m_view->hoveredIndex().column() == index.column() &&
|
||||
if ( m_view->hoveredIndex().row() == index.row() && m_view->hoveredIndex().column() == index.column() && !index.data().toString().isEmpty() &&
|
||||
( index.column() == PlayableModel::Artist || index.column() == PlayableModel::Album || index.column() == PlayableModel::Track ) )
|
||||
{
|
||||
opt.rect.setWidth( opt.rect.width() - 16 );
|
||||
|
@@ -93,10 +93,10 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist, bool loadEn
|
||||
}
|
||||
|
||||
QList<plentry_ptr> entries = playlist->entries();
|
||||
foreach( const plentry_ptr& p, entries )
|
||||
qDebug() << p->guid() << p->query()->track() << p->query()->artist();
|
||||
/* foreach ( const plentry_ptr& p, entries )
|
||||
qDebug() << p->guid() << p->query()->track() << p->query()->artist();*/
|
||||
|
||||
append( entries );
|
||||
appendEntries( entries );
|
||||
|
||||
m_isLoading = false;
|
||||
}
|
||||
@@ -112,78 +112,67 @@ PlaylistModel::clear()
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::append( const QList< plentry_ptr >& entries )
|
||||
PlaylistModel::appendEntries( const QList< plentry_ptr >& entries )
|
||||
{
|
||||
insert( entries, rowCount( QModelIndex() ) );
|
||||
insertEntries( entries, rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::append( const QList< query_ptr >& queries )
|
||||
PlaylistModel::insertAlbums( const QList< Tomahawk::album_ptr >& albums, int row )
|
||||
{
|
||||
insert( queries, rowCount( QModelIndex() ) );
|
||||
}
|
||||
// FIXME: This currently appends, not inserts!
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::append( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
insert( query, rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::append( const Tomahawk::album_ptr& album )
|
||||
{
|
||||
if ( album.isNull() )
|
||||
return;
|
||||
|
||||
connect( album.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
|
||||
SLOT( append( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
if ( rowCount( QModelIndex() ) == 0 )
|
||||
foreach ( const album_ptr& album, albums )
|
||||
{
|
||||
setTitle( album->name() );
|
||||
setDescription( tr( "All tracks by %1 on album %2" ).arg( album->artist()->name() ).arg( album->name() ) );
|
||||
m_isTemporary = true;
|
||||
if ( album.isNull() )
|
||||
return;
|
||||
|
||||
connect( album.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
|
||||
SLOT( appendQueries( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
appendQueries( album->playlistInterface( Mixed )->tracks() );
|
||||
}
|
||||
|
||||
append( album->playlistInterface( Mixed )->tracks() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::append( const Tomahawk::artist_ptr& artist )
|
||||
{
|
||||
if ( artist.isNull() )
|
||||
return;
|
||||
|
||||
connect( artist.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
|
||||
SLOT( append( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
if ( rowCount( QModelIndex() ) == 0 )
|
||||
if ( rowCount( QModelIndex() ) == 0 && albums.count() == 1 )
|
||||
{
|
||||
setTitle( artist->name() );
|
||||
setDescription( tr( "All tracks by %1" ).arg( artist->name() ) );
|
||||
setTitle( albums.first()->name() );
|
||||
setDescription( tr( "All tracks by %1 on album %2" ).arg( albums.first()->artist()->name() ).arg( albums.first()->name() ) );
|
||||
m_isTemporary = true;
|
||||
}
|
||||
|
||||
append( artist->playlistInterface( Mixed )->tracks() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::insert( const Tomahawk::query_ptr& query, int row )
|
||||
PlaylistModel::insertArtists( const QList< Tomahawk::artist_ptr >& artists, int row )
|
||||
{
|
||||
PlayableModel::insert( query, row );
|
||||
// FIXME: This currently appends, not inserts!
|
||||
|
||||
foreach ( const artist_ptr& artist, artists )
|
||||
{
|
||||
if ( artist.isNull() )
|
||||
return;
|
||||
|
||||
connect( artist.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
|
||||
SLOT( appendQueries( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
appendQueries( artist->playlistInterface( Mixed )->tracks() );
|
||||
}
|
||||
|
||||
if ( rowCount( QModelIndex() ) == 0 && artists.count() == 1 )
|
||||
{
|
||||
setTitle( artists.first()->name() );
|
||||
setDescription( tr( "All tracks by %1" ).arg( artists.first()->name() ) );
|
||||
m_isTemporary = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::insert( const QList< Tomahawk::query_ptr >& queries, int row )
|
||||
PlaylistModel::insertQueries( const QList< Tomahawk::query_ptr >& queries, int row )
|
||||
{
|
||||
QList< Tomahawk::plentry_ptr > entries;
|
||||
foreach( const query_ptr& query, queries )
|
||||
foreach ( const query_ptr& query, queries )
|
||||
{
|
||||
plentry_ptr entry = plentry_ptr( new PlaylistEntry() );
|
||||
|
||||
@@ -200,12 +189,12 @@ PlaylistModel::insert( const QList< Tomahawk::query_ptr >& queries, int row )
|
||||
entries << entry;
|
||||
}
|
||||
|
||||
insert( entries, row );
|
||||
insertEntries( entries, row );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::insert( const QList< Tomahawk::plentry_ptr >& entries, int row )
|
||||
PlaylistModel::insertEntries( const QList< Tomahawk::plentry_ptr >& entries, int row )
|
||||
{
|
||||
if ( !entries.count() )
|
||||
{
|
||||
@@ -368,7 +357,7 @@ PlaylistModel::parsedDroppedTracks( QList< query_ptr > tracks )
|
||||
if ( update )
|
||||
beginPlaylistChanges();
|
||||
|
||||
insert( tracks, beginRow );
|
||||
insertQueries( tracks, beginRow );
|
||||
|
||||
if ( update && m_dropStorage.action & Qt::CopyAction )
|
||||
endPlaylistChanges();
|
||||
@@ -488,14 +477,7 @@ PlaylistModel::playlistEntries() const
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::remove( int row, bool moreToCome )
|
||||
{
|
||||
PlayableModel::remove( row, moreToCome );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::remove( const QModelIndex& index, bool moreToCome )
|
||||
PlaylistModel::removeIndex( const QModelIndex& index, bool moreToCome )
|
||||
{
|
||||
PlayableItem* item = itemFromIndex( index );
|
||||
|
||||
@@ -513,27 +495,13 @@ PlaylistModel::remove( const QModelIndex& index, bool moreToCome )
|
||||
if ( item && !m_isLoading )
|
||||
m_savedRemoveTracks << item->query();
|
||||
|
||||
PlayableModel::remove( index, moreToCome );
|
||||
PlayableModel::removeIndex( index, moreToCome );
|
||||
|
||||
if ( !moreToCome )
|
||||
endPlaylistChanges();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::remove( const QList<QModelIndex>& indexes )
|
||||
{
|
||||
PlayableModel::remove( indexes );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistModel::remove( const QList<QPersistentModelIndex>& indexes )
|
||||
{
|
||||
PlayableModel::remove( indexes );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PlaylistModel::isTemporary() const
|
||||
{
|
||||
|
@@ -58,20 +58,14 @@ public:
|
||||
public slots:
|
||||
virtual void clear();
|
||||
|
||||
virtual void append( const Tomahawk::query_ptr& query );
|
||||
virtual void append( const Tomahawk::album_ptr& album );
|
||||
virtual void append( const Tomahawk::artist_ptr& artist );
|
||||
virtual void append( const QList< Tomahawk::query_ptr >& queries );
|
||||
virtual void append( const QList< Tomahawk::plentry_ptr >& entries );
|
||||
virtual void appendEntries( const QList< Tomahawk::plentry_ptr >& entries );
|
||||
|
||||
virtual void insert( const Tomahawk::query_ptr& query, int row = 0 );
|
||||
virtual void insert( const QList< Tomahawk::query_ptr >& queries, int row = 0 );
|
||||
virtual void insert( const QList< Tomahawk::plentry_ptr >& entries, int row = 0 );
|
||||
virtual void insertAlbums( const QList< Tomahawk::album_ptr >& album, int row = 0 );
|
||||
virtual void insertArtists( const QList< Tomahawk::artist_ptr >& artist, int row = 0 );
|
||||
virtual void insertQueries( const QList< Tomahawk::query_ptr >& queries, int row = 0 );
|
||||
virtual void insertEntries( const QList< Tomahawk::plentry_ptr >& entries, int row = 0 );
|
||||
|
||||
virtual void remove( int row, bool moreToCome = false );
|
||||
virtual void remove( const QModelIndex& index, bool moreToCome = false );
|
||||
virtual void remove( const QList<QModelIndex>& indexes );
|
||||
virtual void remove( const QList<QPersistentModelIndex>& indexes );
|
||||
virtual void removeIndex( const QModelIndex& index, bool moreToCome = false );
|
||||
|
||||
signals:
|
||||
void repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode mode );
|
||||
|
@@ -92,7 +92,7 @@ PlaylistView::keyPressEvent( QKeyEvent* event )
|
||||
if ( ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace ) && !model()->isReadOnly() )
|
||||
{
|
||||
qDebug() << "Removing selected items";
|
||||
proxyModel()->remove( selectedIndexes() );
|
||||
deleteItems();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ PlaylistView::eventFilter( QObject* obj, QEvent* event )
|
||||
void
|
||||
PlaylistView::deleteItems()
|
||||
{
|
||||
proxyModel()->remove( selectedIndexes() );
|
||||
proxyModel()->removeIndexes( selectedIndexes() );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -52,7 +52,7 @@ QueueProxyModel::onPlaybackStarted( const Tomahawk::result_ptr& result )
|
||||
PlayableItem* item = itemFromIndex( mapToSource( idx ) );
|
||||
if ( item && item->query() && ( item->query()->results().contains( result ) ||
|
||||
item->query()->equals( result->toQuery() ) ) )
|
||||
remove( idx );
|
||||
removeIndex( idx );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ void
|
||||
QueueProxyModel::onIndexActivated( const QModelIndex& index )
|
||||
{
|
||||
setCurrentIndex( QModelIndex() );
|
||||
remove( index );
|
||||
removeIndex( index );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -33,21 +33,10 @@
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
RecentlyAddedModel::RecentlyAddedModel( const source_ptr& source, QObject* parent )
|
||||
RecentlyAddedModel::RecentlyAddedModel( QObject* parent )
|
||||
: PlayableModel( parent )
|
||||
, m_source( source )
|
||||
, m_limit( LATEST_TRACK_ITEMS )
|
||||
{
|
||||
if ( source.isNull() )
|
||||
{
|
||||
connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) );
|
||||
connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
onSourceAdded( source );
|
||||
loadHistory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +52,7 @@ RecentlyAddedModel::loadHistory()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
startLoading();
|
||||
|
||||
DatabaseCommand_AllTracks* cmd = new DatabaseCommand_AllTracks( m_source->collection() );
|
||||
cmd->setLimit( m_limit );
|
||||
@@ -70,7 +60,7 @@ RecentlyAddedModel::loadHistory()
|
||||
cmd->setSortDescending( true );
|
||||
|
||||
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
|
||||
SLOT( append( QList<Tomahawk::query_ptr> ) ), Qt::QueuedConnection );
|
||||
SLOT( appendQueries( QList<Tomahawk::query_ptr> ) ), Qt::QueuedConnection );
|
||||
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
|
||||
}
|
||||
@@ -88,6 +78,28 @@ RecentlyAddedModel::onSourcesReady()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RecentlyAddedModel::setSource( const Tomahawk::source_ptr& source )
|
||||
{
|
||||
m_source = source;
|
||||
|
||||
if ( source.isNull() )
|
||||
{
|
||||
if ( SourceList::instance()->isReady() )
|
||||
onSourcesReady();
|
||||
else
|
||||
connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) );
|
||||
|
||||
connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
onSourceAdded( source );
|
||||
loadHistory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RecentlyAddedModel::onSourceAdded( const Tomahawk::source_ptr& source )
|
||||
{
|
||||
|
@@ -32,7 +32,7 @@ class DLLEXPORT RecentlyAddedModel : public PlayableModel
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RecentlyAddedModel( const Tomahawk::source_ptr& source, QObject* parent = 0 );
|
||||
explicit RecentlyAddedModel( QObject* parent = 0 );
|
||||
~RecentlyAddedModel();
|
||||
|
||||
unsigned int limit() const { return m_limit; }
|
||||
@@ -40,6 +40,9 @@ public:
|
||||
|
||||
bool isTemporary() const;
|
||||
|
||||
public slots:
|
||||
void setSource( const Tomahawk::source_ptr& source );
|
||||
|
||||
private slots:
|
||||
void onSourcesReady();
|
||||
void onSourceAdded( const Tomahawk::source_ptr& source );
|
||||
|
@@ -34,25 +34,10 @@
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
RecentlyPlayedModel::RecentlyPlayedModel( const source_ptr& source, QObject* parent )
|
||||
RecentlyPlayedModel::RecentlyPlayedModel( QObject* parent )
|
||||
: PlaylistModel( parent )
|
||||
, m_source( source )
|
||||
, m_limit( HISTORY_TRACK_ITEMS )
|
||||
{
|
||||
if ( source.isNull() )
|
||||
{
|
||||
if ( SourceList::instance()->isReady() )
|
||||
onSourcesReady();
|
||||
else
|
||||
connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) );
|
||||
|
||||
connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
onSourceAdded( source );
|
||||
loadHistory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,13 +53,13 @@ RecentlyPlayedModel::loadHistory()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
loadingStarted();
|
||||
startLoading();
|
||||
|
||||
DatabaseCommand_PlaybackHistory* cmd = new DatabaseCommand_PlaybackHistory( m_source );
|
||||
cmd->setLimit( m_limit );
|
||||
|
||||
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ),
|
||||
SLOT( append( QList<Tomahawk::query_ptr> ) ), Qt::QueuedConnection );
|
||||
SLOT( appendQueries( QList<Tomahawk::query_ptr> ) ), Qt::QueuedConnection );
|
||||
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
|
||||
}
|
||||
@@ -92,6 +77,27 @@ RecentlyPlayedModel::onSourcesReady()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RecentlyPlayedModel::setSource( const Tomahawk::source_ptr& source )
|
||||
{
|
||||
m_source = source;
|
||||
if ( source.isNull() )
|
||||
{
|
||||
if ( SourceList::instance()->isReady() )
|
||||
onSourcesReady();
|
||||
else
|
||||
connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) );
|
||||
|
||||
connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
onSourceAdded( source );
|
||||
loadHistory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RecentlyPlayedModel::onSourceAdded( const Tomahawk::source_ptr& source )
|
||||
{
|
||||
@@ -113,7 +119,7 @@ RecentlyPlayedModel::onPlaybackFinished( const Tomahawk::query_ptr& query )
|
||||
|
||||
PlayableItem* youngestItem = itemFromIndex( index( 0, 0, QModelIndex() ) );
|
||||
if ( youngestItem->query()->playedBy().second <= playtime )
|
||||
insert( query, 0 );
|
||||
insertQuery( query, 0 );
|
||||
else
|
||||
{
|
||||
for ( int i = 0; i < count - 1; i++ )
|
||||
@@ -123,14 +129,14 @@ RecentlyPlayedModel::onPlaybackFinished( const Tomahawk::query_ptr& query )
|
||||
|
||||
if ( item1->query()->playedBy().second >= playtime && item2->query()->playedBy().second <= playtime )
|
||||
{
|
||||
insert( query, i + 1 );
|
||||
insertQuery( query, i + 1 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
insert( query, 0 );
|
||||
insertQuery( query, 0 );
|
||||
|
||||
if ( trackCount() > (int)m_limit )
|
||||
remove( m_limit );
|
||||
|
@@ -32,7 +32,7 @@ class DLLEXPORT RecentlyPlayedModel : public PlaylistModel
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RecentlyPlayedModel( const Tomahawk::source_ptr& source, QObject* parent = 0 );
|
||||
explicit RecentlyPlayedModel( QObject* parent = 0 );
|
||||
~RecentlyPlayedModel();
|
||||
|
||||
unsigned int limit() const { return m_limit; }
|
||||
@@ -40,6 +40,9 @@ public:
|
||||
|
||||
bool isTemporary() const;
|
||||
|
||||
public slots:
|
||||
void setSource( const Tomahawk::source_ptr& source );
|
||||
|
||||
private slots:
|
||||
void onSourcesReady();
|
||||
void onSourceAdded( const Tomahawk::source_ptr& source );
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user