Compare commits
116 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e3a43e8ca6 | ||
|
c401ea0d91 | ||
|
2d03b8aea0 | ||
|
178aed9174 | ||
|
6552deca61 | ||
|
89009c09be | ||
|
34672c7bed | ||
|
3caeb4642a | ||
|
80b0eacfed | ||
|
aa078e86e5 | ||
|
9daf0a6089 | ||
|
6dead5e7e1 | ||
|
335868ea95 | ||
|
fc45646205 | ||
|
dbd466d3ed | ||
|
292d8c9530 | ||
|
6b68598d1d | ||
|
0d9e248dac | ||
|
46a86fe6a5 | ||
|
a56ca4ddfc | ||
|
6483c55749 | ||
|
5a56a3e060 | ||
|
585f32c4d8 | ||
|
9ea311526c | ||
|
1342fdb9a7 | ||
|
2cc4fccd66 | ||
|
a2d0899285 | ||
|
06cc52744d | ||
|
df758aa3f8 | ||
|
f79ed86b57 | ||
|
c9b0c92450 | ||
|
57d1c29d35 | ||
|
cdf7c11b29 | ||
|
be7b5babe9 | ||
|
f7f2c51d4e | ||
|
4889ed6a33 | ||
|
3557686681 | ||
|
58dfc54e00 | ||
|
bddbc7a194 | ||
|
33e0116e4b | ||
|
b07f498516 | ||
|
c77be81e5b | ||
|
11cf2c78d8 | ||
|
77bcc7c7aa | ||
|
5b97802104 | ||
|
25ec5cb432 | ||
|
8b4b4a8f0c | ||
|
6448cebec6 | ||
|
191ee259d4 | ||
|
dc364726c0 | ||
|
6ac0f68224 | ||
|
3c3078f9f8 | ||
|
b994befc58 | ||
|
56cf0239da | ||
|
69d75362b3 | ||
|
8db9c79e57 | ||
|
e9ee617d94 | ||
|
c9c6534af5 | ||
|
1b9767995b | ||
|
1c561ba7a9 | ||
|
52baebc899 | ||
|
63c029554a | ||
|
3900dd27d2 | ||
|
e9fb17dadb | ||
|
56c2f86381 | ||
|
a8440c72e4 | ||
|
cbb5bac075 | ||
|
b7f1f56f77 | ||
|
9fe17cf6f5 | ||
|
d641f06e6d | ||
|
7668f04c0c | ||
|
a73d1cd342 | ||
|
35c4a29cbe | ||
|
f6e00fbb86 | ||
|
3f9503364c | ||
|
36b2a585f9 | ||
|
42220a8c95 | ||
|
1ac4efa88a | ||
|
cfe42d10ea | ||
|
6ad9e820e3 | ||
|
47a403a9c8 | ||
|
b2fc0935a4 | ||
|
a04d384ac4 | ||
|
325bb0bf8f | ||
|
c2a79d4cbf | ||
|
b17b8356ad | ||
|
a41b174851 | ||
|
458d32ed7c | ||
|
a0383b6664 | ||
|
9b1fc4cd24 | ||
|
2a27ef88f6 | ||
|
d1ecf6d748 | ||
|
396b5cd6e0 | ||
|
55e7d6383b | ||
|
dbcbffb6c4 | ||
|
6b51872c3e | ||
|
79d8b081d7 | ||
|
165276912f | ||
|
413052bf8e | ||
|
46fd72920c | ||
|
399b835436 | ||
|
9f76cdf486 | ||
|
881bf5dd9d | ||
|
8bb9661960 | ||
|
a1c69b0b43 | ||
|
5083849514 | ||
|
8d75ba4d64 | ||
|
b54b7f6455 | ||
|
488eb387cb | ||
|
99143f6148 | ||
|
1d4320afea | ||
|
d9c3162146 | ||
|
4a1b021753 | ||
|
3418d5295b | ||
|
bf30dc37a2 | ||
|
6ed4902e00 |
@@ -15,11 +15,13 @@ SET( TOMAHAWK_APPLICATION_NAME "Tomahawk" )
|
||||
SET( TOMAHAWK_DESCRIPTION_SUMMARY "The social media player" )
|
||||
|
||||
SET( TOMAHAWK_VERSION_MAJOR 0 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 3 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 99 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 4 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 0 )
|
||||
|
||||
#SET( TOMAHAWK_VERSION_RC 0 )
|
||||
|
||||
# enforce proper symbol exporting on all platforms
|
||||
add_definitions( "-fvisibility=hidden" )
|
||||
|
||||
# build options
|
||||
option(BUILD_GUI "Build Tomahawk with GUI" ON)
|
||||
@@ -72,7 +74,7 @@ IF( NOT BUILD_GUI )
|
||||
MESSAGE( STATUS "Building Tomahawk ${TOMAHAWK_VERSION} in HEADLESS mode ***" )
|
||||
ELSE()
|
||||
MESSAGE( STATUS "Building Tomahawk ${TOMAHAWK_VERSION} full GUI version ***" )
|
||||
LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" )
|
||||
LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" "QtUiTools" )
|
||||
ENDIF()
|
||||
|
||||
IF( BUILD_GUI AND UNIX AND NOT APPLE )
|
||||
@@ -80,7 +82,7 @@ IF( BUILD_GUI AND UNIX AND NOT APPLE )
|
||||
ENDIF()
|
||||
|
||||
macro_optional_find_package(Qt4 4.7.0 COMPONENTS ${NEEDED_QT4_COMPONENTS} )
|
||||
macro_log_feature(QT4_FOUND "Qt" "A cross-platform application and UI framework" "http://qt.nokia.com" TRUE "" "If you see this, although libqt4-devel is installed, check whether \n the qtwebkit-devel package is installed as well")
|
||||
macro_log_feature(QT4_FOUND "Qt" "A cross-platform application and UI framework" "http://qt.nokia.com" TRUE "" "If you see this, although libqt4-devel is installed, check whether the \n qtwebkit-devel package and whatever contains QtUiTools is installed too")
|
||||
|
||||
macro_optional_find_package(Phonon 4.5.0)
|
||||
macro_log_feature(PHONON_FOUND "Phonon" "The Phonon multimedia library" "http://phonon.kde.org" TRUE "" "")
|
||||
|
@@ -56,7 +56,7 @@ ELSE()
|
||||
include(FindLibraryWithDebug)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_path(TAGLIB_CFLAGS
|
||||
find_path(TAGLIB_INCLUDES
|
||||
NAMES
|
||||
tag.h
|
||||
PATH_SUFFIXES taglib
|
||||
|
@@ -28,8 +28,8 @@
|
||||
|
||||
; We use official release plugins
|
||||
; mingw32-vlc from obs misses a lot and has even broken ones probably
|
||||
!define VLC_PATH "${SOURCE_PATH}\admin\win\vlc\prefix" ; SIC! ^
|
||||
!define VLC_BIN "${VLC_PATH}\bin"
|
||||
!define VLC_PATH "${SOURCE_PATH}\admin\win\vlc\" ; SIC! ^
|
||||
!define VLC_BIN "${VLC_PATH}"
|
||||
!define VLC_PLUGIN_PATH "${VLC_BIN}\plugins"
|
||||
|
||||
!define NSI_PATH "${SOURCE_PATH}/admin/win/nsi"
|
||||
@@ -279,7 +279,6 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
File "${INSTALL_PATH}\bin\libqxtweb-standalone.dll"
|
||||
File "${INSTALL_PATH}\bin\libtomahawk_portfwd.dll"
|
||||
File "${INSTALL_PATH}\bin\libtomahawk_lastfm2.dll"
|
||||
File "${INSTALL_PATH}\bin\libquazip.dll"
|
||||
File "${INSTALL_PATH}\bin\libtomahawklib.dll"
|
||||
File "${INSTALL_PATH}\lib\libtomahawk_sip*.dll"
|
||||
!endif
|
||||
@@ -294,7 +293,6 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
File "${BUILD_PATH}\libqxtweb-standalone.dll"
|
||||
File "${BUILD_PATH}\libtomahawk_portfwd.dll"
|
||||
File "${BUILD_PATH}\libtomahawk_lastfm2.dll"
|
||||
File "${BUILD_PATH}\libquazip.dll"
|
||||
File "${BUILD_PATH}\libtomahawk_sip*.dll"
|
||||
!endif
|
||||
|
||||
@@ -307,8 +305,10 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
File "${QT_DLL_PATH}\QtGui4.dll"
|
||||
File "${QT_DLL_PATH}\QtNetwork4.dll"
|
||||
File "${QT_DLL_PATH}\QtSql4.dll"
|
||||
File "${QT_DLL_PATH}\QtXml4.dll"
|
||||
File "${QT_DLL_PATH}\QtScript4.dll"
|
||||
File "${QT_DLL_PATH}\QtUiTools4.dll"
|
||||
File "${QT_DLL_PATH}\QtWebKit4.dll"
|
||||
File "${QT_DLL_PATH}\QtXml4.dll"
|
||||
|
||||
;SQLite driver
|
||||
SetOutPath "$INSTDIR\sqldrivers"
|
||||
@@ -329,13 +329,12 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
File "${MING_BIN}\libstdc++-6.dll"
|
||||
|
||||
;Phonon stuff
|
||||
File "${VLC_BIN}\libphonon.dll"
|
||||
File "${MING_BIN}\libphonon.dll"
|
||||
SetOutPath "$INSTDIR\phonon_backend"
|
||||
File "${VLC_BIN}\phonon_backend\phonon_vlc.dll"
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
;VLC
|
||||
;SetOutPath "$INSTDIR\phonon_backend"
|
||||
File "${VLC_BIN}\libvlc.dll"
|
||||
File "${VLC_BIN}\libvlccore.dll"
|
||||
SetOutPath "$INSTDIR\plugins"
|
||||
@@ -351,6 +350,7 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
|
||||
File "${MING_BIN}\libechonest.dll"
|
||||
File "${MING_BIN}\libQTweetLib.dll"
|
||||
File "${MING_BIN}\libquazip.dll"
|
||||
|
||||
; Jabber
|
||||
File "${MING_BIN}\libjreen.dll"
|
||||
|
36
ChangeLog
@@ -1,3 +1,39 @@
|
||||
Version 0.4.0:
|
||||
* Added visual notification for database indexing job.
|
||||
* Fixed icons not appearing in resolvers list.
|
||||
* Fixed various UI glitches and stray error messages in stations.
|
||||
* Fixed bug where album page would resolve bottom-to-top.
|
||||
* Fixed bug where Footnotes would not update when changing selected album in Album View.
|
||||
* Fixed dragging albums and artists from charts, album, and artist views.
|
||||
* Fixed bug where filter text would be one step behind filter value.
|
||||
* Fixed bug where resolvers would enable themselves after auto-updating.
|
||||
* Fixed occasional crash when dropping tracks onto New Station item.
|
||||
* Added jump-to-current-track support for search results page.
|
||||
* Fixed out of sync Show/Hide menu items on OS X when hidden with cmd-h.
|
||||
* Fixed non-resolving tracks when dragging from album view.
|
||||
* Fixed /Volumes directory not showing up on OS X.
|
||||
* Fixed fetching album covers for albums with special characters.
|
||||
* Show errors and continue gracefully when resolved audio is not available.
|
||||
* Fixed various crashes on exit.
|
||||
* Added basic command-line options for playback control.
|
||||
* Bumped up web api timeouts to allow web clients to finish resolving.
|
||||
* Added filename suggestion when exporting a playlist.
|
||||
* Cleaned up highlighting of artist names in album view.
|
||||
* Cleaned up alignment of playlist items.
|
||||
* Fixed potential crash when searching.
|
||||
* Added support for disc number.
|
||||
* Added SoundCloudWall.com charts.
|
||||
* Added ability to "lock on" to a user when listening along, to skip along.
|
||||
* Fixed bug where loved tracks would be refreshed much too often.
|
||||
* Fixed startup crash on OS X.
|
||||
* Fixed some font size issues.
|
||||
* Sped up Tomahawk startup by moving chart loading into a separate thread.
|
||||
* Added support for parsing Grooveshark and Tinysong tracks and playlists.
|
||||
* Reorganized sidebar to follow more logical item groupings.
|
||||
* Added artist and album results to global searches.
|
||||
* Fixed style and contrast issues when using GTK styles.
|
||||
* Fixed paths to artwork when using MPRIS2 interface.
|
||||
|
||||
Version 0.3.3:
|
||||
* Automatically load Super Collection tracks when no official release
|
||||
information is available.
|
||||
|
@@ -491,7 +491,7 @@ def FindVLCPlugin(name):
|
||||
FixBinary(binary)
|
||||
|
||||
for plugin in VLC_PLUGINS:
|
||||
FixVLCPlugin(FindVLCPlugin(plugin), '.')
|
||||
FixVLCPlugin(FindVLCPlugin(plugin), '../Frameworks/vlc/plugins')
|
||||
|
||||
for plugin in TOMAHAWK_PLUGINS:
|
||||
FixPlugin(plugin, '../MacOS')
|
||||
|
@@ -3,9 +3,12 @@ SET(MINGW_PREFIX "i686-w64-mingw32")
|
||||
# this one is important
|
||||
SET(CMAKE_SYSTEM_NAME Windows)
|
||||
|
||||
|
||||
# specify the cross compiler
|
||||
SET(CMAKE_C_COMPILER ccache ${MINGW_PREFIX}-gcc)
|
||||
SET(CMAKE_C_FLAGS "-fno-keep-inline-dllexport")
|
||||
SET(CMAKE_CXX_COMPILER ccache ${MINGW_PREFIX}-g++)
|
||||
SET(CMAKE_CXX_FLAGS ${CMAKE_C_FLAGS})
|
||||
SET(CMAKE_RC_COMPILER /usr/bin/${MINGW_PREFIX}-windres)
|
||||
|
||||
# where is the target environment containing libraries
|
||||
@@ -15,13 +18,6 @@ SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
|
||||
|
||||
|
||||
# libs with broken find modules
|
||||
SET(TAGLIB_FOUND true)
|
||||
SET(TAGLIB_LIBRARIES ${CMAKE_FIND_ROOT_PATH}/lib/libtag.dll.a)
|
||||
SET(TAGLIB_INCLUDES ${CMAKE_FIND_ROOT_PATH}/include/taglib)
|
||||
|
||||
# configure qt variables
|
||||
SET(QT_LIBRARY_DIR /usr/${MINGW_PREFIX}/bin)
|
||||
SET(QT_PLUGINS_DIR ${CMAKE_FIND_ROOT_PATH}/lib/qt4/plugins/)
|
||||
SET(QT_QTUITOOLS_LIBRARY_RELEASE ${CMAKE_FIND_ROOT_PATH}/lib/libQtUiTools.a)
|
||||
SET(QT_QTUITOOLS_LIBRARY_DEBUG ${CMAKE_FIND_ROOT_PATH}/lib/libQtUiToolsd.a)
|
||||
SET(QT_QTUITOOLS_LIBRARY ${QT_QTUITOOLS_LIBRARY_RELEASE})
|
@@ -1,51 +1,52 @@
|
||||
#!/bin/bash
|
||||
mkdir -p vlc/
|
||||
|
||||
if [ "$1" = "-c" ] ; then
|
||||
echo "Continuing last download.."
|
||||
rm -rvf vlc/prefix/
|
||||
rm -rvf vlc/
|
||||
else
|
||||
echo "Remove old vlc dir..."
|
||||
rm -rvf vlc/*
|
||||
echo "Update archive..."
|
||||
fi
|
||||
|
||||
cd vlc/
|
||||
rm -rvf vlc/
|
||||
|
||||
|
||||
echo "Download phonon archive..."
|
||||
#wget -c "http://downloads.sourceforge.net/project/vlc/1.1.9/win32/vlc-1.1.9-win32.7z?r=http%3A%2F%2Fwww.videolan.org%2Fvlc%2Fdownload-windows.html&ts=1306272584&use_mirror=leaseweb"
|
||||
#wget -c "http://download.tomahawk-player.org/tomahawk-vlc-0.1.zip"
|
||||
#wget -c http://people.videolan.org/~jb/phonon/phonon-vlc-last.7z
|
||||
wget -c http://people.videolan.org/~jb/phonon/phonon_phonon-vlc_20111128.7z
|
||||
# wget -c "http://downloads.sourceforge.net/project/vlc/1.1.9/win32/vlc-1.1.9-win32.7z?r=http%3A%2F%2Fwww.videolan.org%2Fvlc%2Fdownload-windows.html&ts=1306272584&use_mirror=leaseweb"
|
||||
# wget -c "http://download.tomahawk-player.org/tomahawk-vlc-0.1.zip"
|
||||
# wget -c http://people.videolan.org/~jb/phonon/phonon-vlc-last.7z
|
||||
# wget -c http://people.videolan.org/~jb/phonon/phonon_phonon-vlc_20111128.7z
|
||||
wget -c http://download.tomahawk-player.org/test/pvlc.tar.bz2
|
||||
|
||||
echo "Extract binary..."
|
||||
7z x phonon*.7z
|
||||
#mv -v vlc-*/ vlc/
|
||||
#unzip tomahawk-vlc-0.1.zip
|
||||
# 7z x phonon*.7z
|
||||
# mv -v vlc-*/ vlc/
|
||||
# unzip tomahawk-vlc-0.1.zip
|
||||
tar xvjf pvlc.tar.bz2
|
||||
|
||||
echo "Download phonon_vlc_no_video.dll..."
|
||||
wget -c http://people.videolan.org/~jb/phonon/phonon_vlc_no_video.dll
|
||||
cp -v phonon_vlc_no_video.dll prefix/bin/phonon_backend/phonon_vlc.dll
|
||||
# echo "Download phonon_vlc_no_video.dll..."
|
||||
# wget -c http://people.videolan.org/~jb/phonon/phonon_vlc_no_video.dll
|
||||
# cp -v phonon_vlc_no_video.dll prefix/bin/phonon_backend/phonon_vlc.dll
|
||||
|
||||
echo "Strip unneeded plugins from vlc/plugins..."
|
||||
cd prefix/bin/plugins
|
||||
rm -rvf libold* libvcd* libdvd* liblibass* libx264* libschroe* liblibmpeg2* \
|
||||
libstream_out_* libmjpeg_plugin* libh264_plugin* libzvbi_plugin* lib*sub* \
|
||||
*qt4* *skins2* libaccess_bd_plugin.dll \
|
||||
libaudiobargraph_* libball_plugin.dll \
|
||||
libdirac_plugin.dll \
|
||||
libgnutls_plugin.dll \
|
||||
libcaca_plugin.dll \
|
||||
libfreetype_plugin.dll \
|
||||
libaccess_output_shout_plugin.dll \
|
||||
libremoteosd_plugin.dll \
|
||||
libsdl_image_plugin.dll \
|
||||
libvout_sdl_plugin.dll \
|
||||
libpng_plugin.dll \
|
||||
libgoom_plugin.dll \
|
||||
libatmo_plugin.dll \
|
||||
libmux_ts_plugin.dll \
|
||||
libkate_plugin.dll \
|
||||
libtaglib_plugin.dll
|
||||
# echo "Strip unneeded plugins from vlc/plugins..."
|
||||
# cd prefix/bin/plugins
|
||||
# rm -rvf libold* libvcd* libdvd* liblibass* libx264* libschroe* liblibmpeg2* \
|
||||
# libstream_out_* libmjpeg_plugin* libh264_plugin* libzvbi_plugin* lib*sub* \
|
||||
# *qt4* *skins2* libaccess_bd_plugin.dll \
|
||||
# libaudiobargraph_* libball_plugin.dll \
|
||||
# libdirac_plugin.dll \
|
||||
# libgnutls_plugin.dll \
|
||||
# libcaca_plugin.dll \
|
||||
# libfreetype_plugin.dll \
|
||||
# libaccess_output_shout_plugin.dll \
|
||||
# libremoteosd_plugin.dll \
|
||||
# libsdl_image_plugin.dll \
|
||||
# libvout_sdl_plugin.dll \
|
||||
# libpng_plugin.dll \
|
||||
# libgoom_plugin.dll \
|
||||
# libatmo_plugin.dll \
|
||||
# libmux_ts_plugin.dll \
|
||||
# libkate_plugin.dll \
|
||||
# libtaglib_plugin.dll
|
||||
|
||||
|
||||
# this is for vlc-1.2
|
||||
|
BIN
data/images/grooveshark.png
Normal file
After Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 12 KiB |
BIN
data/images/process-stop.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
@@ -133,6 +133,8 @@
|
||||
<file>data/images/headphones-bigger.png</file>
|
||||
<file>data/images/no-album-no-case.png</file>
|
||||
<file>data/images/rdio.png</file>
|
||||
<file>data/images/grooveshark.png</file>
|
||||
<file>data/sql/dbmigrate-27_to_28.sql</file>
|
||||
<file>data/images/process-stop.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -58,4 +58,7 @@ if (APPLE)
|
||||
FILE(COPY ${CMAKE_SOURCE_DIR}/admin/mac/sparkle_pub.pem
|
||||
DESTINATION "${CMAKE_BINARY_DIR}/tomahawk.app/Contents/Resources")
|
||||
|
||||
FILE(COPY /usr/bin/SetFile DESTINATION "${CMAKE_BINARY_DIR}/tomahawk.app/Contents/MacOS")
|
||||
FILE(COPY /usr/bin/GetFileInfo DESTINATION "${CMAKE_BINARY_DIR}/tomahawk.app/Contents/MacOS")
|
||||
|
||||
endif (APPLE)
|
||||
|
@@ -100,8 +100,6 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
m_sliderTimeLine.setCurveShape( QTimeLine::LinearCurve );
|
||||
ui->seekSlider->setTimeLine( &m_sliderTimeLine );
|
||||
|
||||
m_defaultCover = QPixmap( RESPATH "images/no-album-no-case.png" ).scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
connect( &m_phononTickCheckTimer, SIGNAL( timeout() ), SLOT( phononTickCheckTimeout() ) );
|
||||
connect( &m_sliderTimeLine, SIGNAL( frameChanged( int ) ), ui->seekSlider, SLOT( setValue( int ) ) );
|
||||
|
||||
@@ -264,14 +262,14 @@ AudioControls::onAlbumCoverUpdated()
|
||||
void
|
||||
AudioControls::setAlbumCover()
|
||||
{
|
||||
if ( !m_currentTrack->album()->cover().isNull() )
|
||||
if ( !m_currentTrack->album()->cover( ui->coverImage->size() ).isNull() )
|
||||
{
|
||||
QPixmap cover;
|
||||
cover.loadFromData( m_currentTrack->album()->cover() );
|
||||
ui->coverImage->setPixmap( cover.scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
|
||||
cover = m_currentTrack->album()->cover( ui->coverImage->size() );
|
||||
ui->coverImage->setPixmap( cover );
|
||||
}
|
||||
else
|
||||
ui->coverImage->setPixmap( m_defaultCover );
|
||||
ui->coverImage->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, ui->coverImage->size() ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -279,10 +277,16 @@ void
|
||||
AudioControls::onSocialActionsLoaded()
|
||||
{
|
||||
Query* query = qobject_cast< Query* >( sender() );
|
||||
if ( !query || query != m_currentTrack->toQuery().data() )
|
||||
if ( !query )
|
||||
return;
|
||||
|
||||
setSocialActions();
|
||||
query_ptr currentQuery = m_currentTrack->toQuery();
|
||||
if ( query->artist() == currentQuery->artist() &&
|
||||
query->track() == currentQuery->track() &&
|
||||
query->album() == currentQuery->album() )
|
||||
{
|
||||
setSocialActions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -91,8 +91,6 @@ private:
|
||||
|
||||
Ui::AudioControls *ui;
|
||||
|
||||
QPixmap m_defaultCover;
|
||||
|
||||
Tomahawk::result_ptr m_currentTrack;
|
||||
Tomahawk::PlaylistInterface::RepeatMode m_repeatMode;
|
||||
bool m_shuffled;
|
||||
|
@@ -21,5 +21,4 @@ ADD_DEFINITIONS( ${QT_DEFINITIONS} )
|
||||
ADD_EXECUTABLE( tomahawk_crash_reporter WIN32 ${crashreporter_SOURCES} ${crashreporter_HEADERS_MOC} ${crashreporter_UI_HEADERS} ${crashreporter_RC_RCC} )
|
||||
TARGET_LINK_LIBRARIES( tomahawk_crash_reporter ${QT_LIBRARIES} tomahawklib )
|
||||
|
||||
INCLUDE(GNUInstallDirs)
|
||||
install(TARGETS tomahawk_crash_reporter RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_LIBEXECDIR})
|
||||
install(TARGETS tomahawk_crash_reporter RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR})
|
||||
|
@@ -76,7 +76,10 @@ AtticaManager::loadPixmapsFromCache()
|
||||
}
|
||||
|
||||
QPixmap* icon = new QPixmap( cacheDir.absoluteFilePath( file ) );
|
||||
m_resolverStates[ info.baseName() ].pixmap = icon;
|
||||
if ( !icon->isNull() )
|
||||
{
|
||||
m_resolverStates[ info.baseName() ].pixmap = icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,14 +96,21 @@ AtticaManager::savePixmapsToCache()
|
||||
|
||||
foreach( const QString& id, m_resolverStates.keys() )
|
||||
{
|
||||
if ( !m_resolverStates[ id ].pixmap )
|
||||
if ( !m_resolverStates[ id ].pixmap || !m_resolverStates[ id ].pixmapDirty )
|
||||
continue;
|
||||
|
||||
const QString filename = cacheDir.absoluteFilePath( QString( "%1.png" ).arg( id ) );
|
||||
if ( !m_resolverStates[ id ].pixmap->save( filename ) )
|
||||
QFile f( filename );
|
||||
if ( !f.open( QIODevice::WriteOnly ) )
|
||||
{
|
||||
tLog() << "Failed to open cache file for writing:" << filename;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !m_resolverStates[ id ].pixmap->save( &f ) )
|
||||
{
|
||||
tLog() << "Failed to save pixmap into opened file for writing:" << filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,6 +257,7 @@ AtticaManager::resolverIconFetched()
|
||||
QPixmap* icon = new QPixmap;
|
||||
icon->loadFromData( data );
|
||||
m_resolverStates[ resolverId ].pixmap = icon;
|
||||
m_resolverStates[ resolverId ].pixmapDirty = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -288,7 +299,7 @@ AtticaManager::syncServerData()
|
||||
|
||||
|
||||
void
|
||||
AtticaManager::installResolver( const Content& resolver )
|
||||
AtticaManager::installResolver( const Content& resolver, bool autoEnable )
|
||||
{
|
||||
Q_ASSERT( !resolver.id().isNull() );
|
||||
|
||||
@@ -302,6 +313,7 @@ AtticaManager::installResolver( const Content& resolver )
|
||||
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( "autoEnable", autoEnable );
|
||||
|
||||
job->start();
|
||||
}
|
||||
@@ -316,11 +328,12 @@ AtticaManager::upgradeResolver( const Content& resolver )
|
||||
if ( !m_resolverStates.contains( resolver.id() ) || m_resolverStates[ resolver.id() ].state != NeedsUpgrade )
|
||||
return;
|
||||
|
||||
const bool enabled = TomahawkSettings::instance()->enabledScriptResolvers().contains( m_resolverStates[ resolver.id() ].scriptPath );
|
||||
m_resolverStates[ resolver.id() ].state = Upgrading;
|
||||
emit resolverStateChanged( resolver.id() );
|
||||
|
||||
uninstallResolver( resolver );
|
||||
installResolver( resolver );
|
||||
installResolver( resolver, enabled );
|
||||
}
|
||||
|
||||
|
||||
@@ -337,6 +350,7 @@ AtticaManager::resolverDownloadFinished ( BaseJob* j )
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
|
||||
connect( reply, SIGNAL( finished() ), this, SLOT( payloadFetched() ) );
|
||||
reply->setProperty( "resolverId", job->property( "resolverId" ) );
|
||||
reply->setProperty( "autoEnable", job->property( "autoEnable" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -372,8 +386,10 @@ AtticaManager::payloadFetched()
|
||||
// update with absolute, not relative, path
|
||||
m_resolverStates[ resolverId ].scriptPath = resolverPath;
|
||||
|
||||
const bool autoEnable = reply->property( "autoEnable" ).toBool();
|
||||
|
||||
// Do the install / add to tomahawk
|
||||
Tomahawk::Pipeline::instance()->addScriptResolver( resolverPath, true );
|
||||
Tomahawk::Pipeline::instance()->addScriptResolver( resolverPath, autoEnable );
|
||||
m_resolverStates[ resolverId ].state = Installed;
|
||||
TomahawkSettingsGui::instanceGui()->setAtticaResolverStates( m_resolverStates );
|
||||
emit resolverInstalled( resolverId );
|
||||
|
@@ -52,9 +52,12 @@ public:
|
||||
ResolverState state;
|
||||
QPixmap* pixmap;
|
||||
|
||||
// internal
|
||||
bool pixmapDirty;
|
||||
|
||||
Resolver( const QString& v, const QString& path, int userR, ResolverState s )
|
||||
: version( v ), scriptPath( path ), userRating( userR ), state( s ), pixmap( 0 ) {}
|
||||
Resolver() : userRating( -1 ), state( Uninstalled ), pixmap( 0 ) {}
|
||||
: version( v ), scriptPath( path ), userRating( userR ), state( s ), pixmap( 0 ), pixmapDirty( false ) {}
|
||||
Resolver() : userRating( -1 ), state( Uninstalled ), pixmap( 0 ), pixmapDirty( false ) {}
|
||||
};
|
||||
|
||||
typedef QHash< QString, AtticaManager::Resolver > StateHash;
|
||||
@@ -91,7 +94,7 @@ public:
|
||||
bool userHasRated( const Attica::Content& c ) const;
|
||||
|
||||
public slots:
|
||||
void installResolver( const Attica::Content& resolver );
|
||||
void installResolver( const Attica::Content& resolver, bool autoEnable = true );
|
||||
void upgradeResolver( const Attica::Content& resolver );
|
||||
|
||||
signals:
|
||||
|
@@ -38,6 +38,8 @@ set( libGuiSources
|
||||
jobview/PipelineStatusItem.cpp
|
||||
jobview/TransferStatusItem.cpp
|
||||
jobview/LatchedStatusItem.cpp
|
||||
jobview/ErrorStatusMessage.cpp
|
||||
jobview/IndexingJobItem.cpp
|
||||
|
||||
infobar/infobar.cpp
|
||||
|
||||
@@ -276,6 +278,8 @@ set( libGuiHeaders
|
||||
jobview/PipelineStatusItem.h
|
||||
jobview/TransferStatusItem.h
|
||||
jobview/LatchedStatusItem.h
|
||||
jobview/ErrorStatusMessage.h
|
||||
jobview/IndexingJobItem.h
|
||||
|
||||
thirdparty/Qocoa/qsearchfield.h
|
||||
)
|
||||
@@ -648,6 +652,8 @@ IF( APPLE )
|
||||
utils/tomahawkutils_mac.mm
|
||||
thirdparty/Qocoa/qsearchfield_mac.mm )
|
||||
|
||||
SET_SOURCE_FILES_PROPERTIES(utils/tomahawkutils_mac.mm PROPERTIES COMPILE_FLAGS "-fvisibility=default")
|
||||
|
||||
SET( libHeaders ${libHeaders}
|
||||
infosystem/infoplugins/mac/adium.h
|
||||
infosystem/infoplugins/mac/adiumplugin.h )
|
||||
@@ -703,6 +709,7 @@ TARGET_LINK_LIBRARIES( tomahawklib
|
||||
${QT_QTSQL_LIBRARY}
|
||||
${QT_QTUITOOLS_LIBRARY}
|
||||
${QT_QTGUI_LIBRARY}
|
||||
${QT_QTSCRIPT_LIBRARY}
|
||||
${OS_SPECIFIC_LINK_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${LINK_LIBRARIES}
|
||||
|
@@ -22,7 +22,6 @@
|
||||
#include "albumplaylistinterface.h"
|
||||
#include "database/database.h"
|
||||
#include "database/databaseimpl.h"
|
||||
#include "database/databasecommand_alltracks.h"
|
||||
#include "query.h"
|
||||
|
||||
#include "utils/logger.h"
|
||||
@@ -32,12 +31,16 @@ using namespace Tomahawk;
|
||||
|
||||
Album::~Album()
|
||||
{
|
||||
delete m_cover;
|
||||
}
|
||||
|
||||
|
||||
album_ptr
|
||||
Album::get( const Tomahawk::artist_ptr& artist, const QString& name, bool autoCreate )
|
||||
{
|
||||
if ( !Database::instance() || !Database::instance()->impl() )
|
||||
return album_ptr();
|
||||
|
||||
int albid = Database::instance()->impl()->albumId( artist->id(), name, autoCreate );
|
||||
if ( albid < 1 && autoCreate )
|
||||
return album_ptr();
|
||||
@@ -71,6 +74,7 @@ Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr&
|
||||
, m_id( id )
|
||||
, m_name( name )
|
||||
, m_artist( artist )
|
||||
, m_cover( 0 )
|
||||
, m_infoLoaded( false )
|
||||
{
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
@@ -97,11 +101,14 @@ Album::artist() const
|
||||
}
|
||||
|
||||
|
||||
QByteArray
|
||||
Album::cover() const
|
||||
#ifndef ENABLE_HEADLESS
|
||||
QPixmap
|
||||
Album::cover( const QSize& size, bool forceLoad ) const
|
||||
{
|
||||
if ( !m_infoLoaded )
|
||||
{
|
||||
if ( !forceLoad )
|
||||
return QPixmap();
|
||||
m_uuid = uuid();
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash trackInfo;
|
||||
@@ -117,8 +124,31 @@ Album::cover() const
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
|
||||
}
|
||||
|
||||
return m_cover;
|
||||
if ( !m_cover && !m_coverBuffer.isEmpty() )
|
||||
{
|
||||
m_cover = new QPixmap();
|
||||
m_cover->loadFromData( m_coverBuffer );
|
||||
}
|
||||
|
||||
if ( m_cover && !m_cover->isNull() && !size.isEmpty() )
|
||||
{
|
||||
if ( m_coverCache.contains( size.width() ) )
|
||||
{
|
||||
return m_coverCache.value( size.width() );
|
||||
}
|
||||
|
||||
QPixmap scaledCover;
|
||||
scaledCover = m_cover->scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_coverCache.insert( size.width(), scaledCover );
|
||||
return scaledCover;
|
||||
}
|
||||
|
||||
if ( m_cover )
|
||||
return *m_cover;
|
||||
else
|
||||
return QPixmap();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
@@ -137,7 +167,7 @@ Album::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVaria
|
||||
const QByteArray ba = returnedData["imgbytes"].toByteArray();
|
||||
if ( ba.length() )
|
||||
{
|
||||
m_cover = ba;
|
||||
m_coverBuffer = ba;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,8 +19,13 @@
|
||||
#ifndef TOMAHAWKALBUM_H
|
||||
#define TOMAHAWKALBUM_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#ifndef ENABLE_HEADLESS
|
||||
#include <QtGui/QPixmap>
|
||||
#endif
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "playlistinterface.h"
|
||||
@@ -44,7 +49,9 @@ public:
|
||||
unsigned int id() const { return m_id; }
|
||||
QString name() const { return m_name; }
|
||||
artist_ptr artist() const;
|
||||
QByteArray cover() const;
|
||||
#ifndef ENABLE_HEADLESS
|
||||
QPixmap cover( const QSize& size, bool forceLoad = true ) const;
|
||||
#endif
|
||||
bool infoLoaded() const { return m_infoLoaded; }
|
||||
|
||||
Tomahawk::playlistinterface_ptr playlistInterface();
|
||||
@@ -64,10 +71,13 @@ private:
|
||||
unsigned int m_id;
|
||||
QString m_name;
|
||||
artist_ptr m_artist;
|
||||
QByteArray m_cover;
|
||||
QByteArray m_coverBuffer;
|
||||
mutable QPixmap* m_cover;
|
||||
bool m_infoLoaded;
|
||||
mutable QString m_uuid;
|
||||
|
||||
mutable QHash< int, QPixmap > m_coverCache;
|
||||
|
||||
Tomahawk::playlistinterface_ptr m_playlistInterface;
|
||||
};
|
||||
|
||||
|
@@ -68,7 +68,6 @@ signals:
|
||||
void nextTrackReady();
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY( AlbumPlaylistInterface )
|
||||
AlbumPlaylistInterface();
|
||||
|
||||
QList< Tomahawk::query_ptr > m_queries;
|
||||
|
@@ -31,12 +31,16 @@ using namespace Tomahawk;
|
||||
|
||||
Artist::~Artist()
|
||||
{
|
||||
delete m_cover;
|
||||
}
|
||||
|
||||
|
||||
artist_ptr
|
||||
Artist::get( const QString& name, bool autoCreate )
|
||||
{
|
||||
if ( !Database::instance() || !Database::instance()->impl() )
|
||||
return artist_ptr();
|
||||
|
||||
int artid = Database::instance()->impl()->artistId( name, autoCreate );
|
||||
if ( artid < 1 && autoCreate )
|
||||
return artist_ptr();
|
||||
@@ -69,6 +73,7 @@ Artist::Artist( unsigned int id, const QString& name )
|
||||
: QObject()
|
||||
, m_id( id )
|
||||
, m_name( name )
|
||||
, m_cover( 0 )
|
||||
, m_infoLoaded( false )
|
||||
{
|
||||
m_sortname = DatabaseImpl::sortname( name, true );
|
||||
@@ -89,11 +94,14 @@ Artist::onTracksAdded( const QList<Tomahawk::query_ptr>& tracks )
|
||||
}
|
||||
|
||||
|
||||
QByteArray
|
||||
Artist::cover() const
|
||||
#ifndef ENABLE_HEADLESS
|
||||
QPixmap
|
||||
Artist::cover( const QSize& size, bool forceLoad ) const
|
||||
{
|
||||
if ( !m_infoLoaded )
|
||||
{
|
||||
if ( !forceLoad )
|
||||
return QPixmap();
|
||||
m_uuid = uuid();
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash trackInfo;
|
||||
@@ -108,8 +116,31 @@ Artist::cover() const
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
|
||||
}
|
||||
|
||||
return m_cover;
|
||||
if ( !m_cover && !m_coverBuffer.isEmpty() )
|
||||
{
|
||||
m_cover = new QPixmap();
|
||||
m_cover->loadFromData( m_coverBuffer );
|
||||
}
|
||||
|
||||
if ( m_cover && !m_cover->isNull() && !size.isEmpty() )
|
||||
{
|
||||
if ( m_coverCache.contains( size.width() ) )
|
||||
{
|
||||
return m_coverCache.value( size.width() );
|
||||
}
|
||||
|
||||
QPixmap scaledCover;
|
||||
scaledCover = m_cover->scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_coverCache.insert( size.width(), scaledCover );
|
||||
return scaledCover;
|
||||
}
|
||||
|
||||
if ( m_cover )
|
||||
return *m_cover;
|
||||
else
|
||||
return QPixmap();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
@@ -128,7 +159,7 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari
|
||||
const QByteArray ba = returnedData["imgbytes"].toByteArray();
|
||||
if ( ba.length() )
|
||||
{
|
||||
m_cover = ba;
|
||||
m_coverBuffer = ba;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,8 +19,13 @@
|
||||
#ifndef TOMAHAWKARTIST_H
|
||||
#define TOMAHAWKARTIST_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#ifndef ENABLE_HEADLESS
|
||||
#include <QtGui/QPixmap>
|
||||
#endif
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "dllmacro.h"
|
||||
@@ -43,7 +48,9 @@ public:
|
||||
unsigned int id() const { return m_id; }
|
||||
QString name() const { return m_name; }
|
||||
QString sortname() const { return m_sortname; }
|
||||
QByteArray cover() const;
|
||||
#ifndef ENABLE_HEADLESS
|
||||
QPixmap cover( const QSize& size, bool forceLoad = true ) const;
|
||||
#endif
|
||||
bool infoLoaded() const { return m_infoLoaded; }
|
||||
|
||||
Tomahawk::playlistinterface_ptr playlistInterface();
|
||||
@@ -63,10 +70,13 @@ private:
|
||||
unsigned int m_id;
|
||||
QString m_name;
|
||||
QString m_sortname;
|
||||
QByteArray m_cover;
|
||||
QByteArray m_coverBuffer;
|
||||
mutable QPixmap* m_cover;
|
||||
bool m_infoLoaded;
|
||||
mutable QString m_uuid;
|
||||
|
||||
mutable QHash< int, QPixmap > m_coverCache;
|
||||
|
||||
Tomahawk::playlistinterface_ptr m_playlistInterface;
|
||||
};
|
||||
|
||||
|
@@ -89,8 +89,8 @@ ArtistPlaylistInterface::tracks()
|
||||
cmd->setArtist( m_artist );
|
||||
cmd->setSortOrder( DatabaseCommand_AllTracks::Album );
|
||||
|
||||
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
|
||||
SLOT( onTracksAdded( QList<Tomahawk::query_ptr> ) ) );
|
||||
connect( cmd, SIGNAL( tracks( QList<Tomahawk::query_ptr>, QVariant ) ),
|
||||
m_artist.data(), SLOT( onTracksAdded( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
|
||||
}
|
||||
|
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "audioengine.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
@@ -328,13 +330,15 @@ AudioEngine::sendWaitingNotificationSlot() const
|
||||
void
|
||||
AudioEngine::sendNowPlayingNotification()
|
||||
{
|
||||
#ifndef ENABLE_HEADLESS
|
||||
if ( m_currentTrack->album().isNull() || m_currentTrack->album()->infoLoaded() )
|
||||
onNowPlayingInfoReady();
|
||||
else
|
||||
{
|
||||
connect( m_currentTrack->album().data(), SIGNAL( updated() ), SLOT( onNowPlayingInfoReady() ), Qt::UniqueConnection );
|
||||
m_currentTrack->album()->cover();
|
||||
m_currentTrack->album()->cover( QSize( 0, 0 ) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -357,9 +361,11 @@ AudioEngine::onNowPlayingInfoReady()
|
||||
|
||||
if ( !m_currentTrack->album().isNull() )
|
||||
{
|
||||
#ifndef ENABLE_HEADLESS
|
||||
QImage cover;
|
||||
cover.loadFromData( m_currentTrack->album()->cover() );
|
||||
cover = m_currentTrack->album()->cover( QSize( 0, 0 ) ).toImage();
|
||||
playInfo["image"] = QVariant( cover );
|
||||
#endif
|
||||
}
|
||||
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
|
||||
@@ -584,10 +590,10 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState )
|
||||
|
||||
if ( newState == Phonon::ErrorState )
|
||||
{
|
||||
stop();
|
||||
|
||||
tLog() << "Phonon Error:" << m_mediaObject->errorString() << m_mediaObject->errorType();
|
||||
emit error( UnknownError );
|
||||
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
if ( newState == Phonon::PlayingState )
|
||||
|
@@ -88,6 +88,7 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
|
||||
m_sigmap->setMapping( m_loveAction, ActionLove );
|
||||
|
||||
connect( queries.first().data(), SIGNAL( socialActionsLoaded() ), SLOT( onSocialActionsLoaded() ) );
|
||||
m_queries.first()->loadSocialActions();
|
||||
onSocialActionsLoaded();
|
||||
}
|
||||
|
||||
|
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "artist.h"
|
||||
#include "album.h"
|
||||
#include "pipeline.h"
|
||||
#include "sourcelist.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
@@ -30,10 +31,14 @@ DatabaseCommand_Resolve::DatabaseCommand_Resolve( const query_ptr& query )
|
||||
: DatabaseCommand()
|
||||
, m_query( query )
|
||||
{
|
||||
Q_ASSERT( Pipeline::instance()->isRunning() );
|
||||
}
|
||||
|
||||
|
||||
DatabaseCommand_Resolve::~DatabaseCommand_Resolve()
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
|
||||
@@ -76,11 +81,9 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
|
||||
typedef QPair<int, float> scorepair_t;
|
||||
|
||||
// STEP 1
|
||||
QList< QPair<int, float> > artists = lib->searchTable( "artist", m_query->artist() );
|
||||
QList< QPair<int, float> > tracks = lib->searchTable( "track", m_query->track() );
|
||||
QList< QPair<int, float> > albums = lib->searchTable( "album", m_query->album() );
|
||||
QList< QPair<int, float> > tracks = lib->search( m_query );
|
||||
|
||||
if ( artists.length() == 0 || tracks.length() == 0 )
|
||||
if ( tracks.length() == 0 )
|
||||
{
|
||||
qDebug() << "No candidates found in first pass, aborting resolve" << m_query->artist() << m_query->track();
|
||||
emit results( m_query->id(), res );
|
||||
@@ -90,13 +93,10 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
|
||||
// STEP 2
|
||||
TomahawkSqlQuery files_query = lib->newquery();
|
||||
|
||||
QStringList artsl, trksl;
|
||||
for ( int k = 0; k < artists.count(); k++ )
|
||||
artsl.append( QString::number( artists.at( k ).first ) );
|
||||
QStringList trksl;
|
||||
for ( int k = 0; k < tracks.count(); k++ )
|
||||
trksl.append( QString::number( tracks.at( k ).first ) );
|
||||
|
||||
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
|
||||
QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
|
||||
|
||||
QString sql = QString( "SELECT "
|
||||
@@ -119,8 +119,7 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
|
||||
"artist.id = file_join.artist AND "
|
||||
"track.id = file_join.track AND "
|
||||
"file.id = file_join.file AND "
|
||||
"(%1 AND %2)" )
|
||||
.arg( artsToken )
|
||||
"(%1)" )
|
||||
.arg( trksToken );
|
||||
|
||||
files_query.prepare( sql );
|
||||
@@ -196,27 +195,9 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
||||
typedef QPair<int, float> scorepair_t;
|
||||
|
||||
// STEP 1
|
||||
QList< QPair<int, float> > artistPairs = lib->searchTable( "artist", m_query->fullTextQuery(), 20 );
|
||||
QList< QPair<int, float> > trackPairs = lib->searchTable( "track", m_query->fullTextQuery(), 20 );
|
||||
QList< QPair<int, float> > albumPairs = lib->searchTable( "album", m_query->fullTextQuery(), 20 );
|
||||
QList< QPair<int, float> > trackPairs = lib->search( m_query );
|
||||
QList< QPair<int, float> > albumPairs = lib->searchAlbum( m_query, 20 );
|
||||
|
||||
foreach ( const scorepair_t& artistPair, artistPairs )
|
||||
{
|
||||
TomahawkSqlQuery query = lib->newquery();
|
||||
|
||||
QString sql = QString( "SELECT name FROM artist WHERE id = %1" ).arg( artistPair.first );
|
||||
query.prepare( sql );
|
||||
query.exec();
|
||||
|
||||
QList<Tomahawk::artist_ptr> artistList;
|
||||
while ( query.next() )
|
||||
{
|
||||
Tomahawk::artist_ptr artist = Tomahawk::Artist::get( artistPair.first, query.value( 0 ).toString() );
|
||||
artistList << artist;
|
||||
}
|
||||
|
||||
emit artists( m_query->id(), artistList );
|
||||
}
|
||||
foreach ( const scorepair_t& albumPair, albumPairs )
|
||||
{
|
||||
TomahawkSqlQuery query = lib->newquery();
|
||||
@@ -235,10 +216,10 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
||||
|
||||
emit albums( m_query->id(), albumList );
|
||||
}
|
||||
|
||||
if ( artistPairs.length() == 0 && trackPairs.length() == 0 && albumPairs.length() == 0 )
|
||||
|
||||
if ( trackPairs.length() == 0 )
|
||||
{
|
||||
qDebug() << "No candidates found in first pass, aborting resolve" << m_query->artist() << m_query->track();
|
||||
qDebug() << "No candidates found in first pass, aborting resolve" << m_query->fullTextQuery();
|
||||
emit results( m_query->id(), res );
|
||||
return;
|
||||
}
|
||||
@@ -246,18 +227,11 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
||||
// STEP 2
|
||||
TomahawkSqlQuery files_query = lib->newquery();
|
||||
|
||||
QStringList artsl, trksl, albsl;
|
||||
for ( int k = 0; k < artistPairs.count(); k++ )
|
||||
artsl.append( QString::number( artistPairs.at( k ).first ) );
|
||||
QStringList trksl;
|
||||
for ( int k = 0; k < trackPairs.count(); k++ )
|
||||
trksl.append( QString::number( trackPairs.at( k ).first ) );
|
||||
for ( int k = 0; k < albumPairs.count(); k++ )
|
||||
albsl.append( QString::number( albumPairs.at( k ).first ) );
|
||||
|
||||
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
|
||||
QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
|
||||
QString albsToken = QString( "file_join.album IN (%1)" ).arg( albsl.join( "," ) );
|
||||
|
||||
QString sql = QString( "SELECT "
|
||||
"url, mtime, size, md5, mimetype, duration, bitrate, " //0
|
||||
"file_join.artist, file_join.album, file_join.track, " //7
|
||||
@@ -279,7 +253,7 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
||||
"track.id = file_join.track AND "
|
||||
"file.id = file_join.file AND "
|
||||
"%1" )
|
||||
.arg( trackPairs.length() > 0 ? trksToken : QString( "0" ) );
|
||||
.arg( trksl.length() > 0 ? trksToken : QString( "0" ) );
|
||||
|
||||
files_query.prepare( sql );
|
||||
files_query.exec();
|
||||
|
@@ -21,32 +21,26 @@
|
||||
#include "databaseimpl.h"
|
||||
#include "tomahawksqlquery.h"
|
||||
#include "utils/logger.h"
|
||||
#include "jobview/IndexingJobItem.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
|
||||
#include <QSqlRecord>
|
||||
|
||||
|
||||
DatabaseCommand_UpdateSearchIndex::DatabaseCommand_UpdateSearchIndex()
|
||||
: DatabaseCommand()
|
||||
, m_statusJob( new IndexingJobItem )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Updating index.";
|
||||
|
||||
JobStatusView::instance()->model()->addJob( m_statusJob );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DatabaseCommand_UpdateSearchIndex::indexTable( DatabaseImpl* db, const QString& table )
|
||||
DatabaseCommand_UpdateSearchIndex::~DatabaseCommand_UpdateSearchIndex()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
TomahawkSqlQuery query = db->newquery();
|
||||
qDebug() << "Building index for" << table;
|
||||
query.exec( QString( "SELECT id, name FROM %1" ).arg( table ) );
|
||||
|
||||
QMap< unsigned int, QString > fields;
|
||||
while ( query.next() )
|
||||
{
|
||||
fields.insert( query.value( 0 ).toUInt(), query.value( 1 ).toString() );
|
||||
}
|
||||
|
||||
db->m_fuzzyIndex->appendFields( table, fields );
|
||||
qDebug() << "Building index for" << table << "finished.";
|
||||
m_statusJob->done();
|
||||
}
|
||||
|
||||
|
||||
@@ -55,9 +49,35 @@ DatabaseCommand_UpdateSearchIndex::exec( DatabaseImpl* db )
|
||||
{
|
||||
db->m_fuzzyIndex->beginIndexing();
|
||||
|
||||
indexTable( db, "artist" );
|
||||
indexTable( db, "album" );
|
||||
indexTable( db, "track" );
|
||||
QMap< unsigned int, QMap< QString, QString > > data;
|
||||
TomahawkSqlQuery q = db->newquery();
|
||||
|
||||
q.exec( "SELECT track.id, track.name, artist.name, artist.id FROM track, artist WHERE artist.id = track.artist" );
|
||||
while ( q.next() )
|
||||
{
|
||||
QMap< QString, QString > track;
|
||||
track.insert( "track", q.value( 1 ).toString() );
|
||||
track.insert( "artist", q.value( 2 ).toString() );
|
||||
track.insert( "artistid", q.value( 3 ).toString() );
|
||||
|
||||
data.insert( q.value( 0 ).toUInt(), track );
|
||||
}
|
||||
|
||||
db->m_fuzzyIndex->appendFields( data );
|
||||
data.clear();
|
||||
|
||||
q.exec( "SELECT album.id, album.name FROM album" );
|
||||
while ( q.next() )
|
||||
{
|
||||
QMap< QString, QString > album;
|
||||
album.insert( "album", q.value( 1 ).toString() );
|
||||
|
||||
data.insert( q.value( 0 ).toUInt(), album );
|
||||
}
|
||||
|
||||
db->m_fuzzyIndex->appendFields( data );
|
||||
|
||||
qDebug() << "Building index finished.";
|
||||
|
||||
db->m_fuzzyIndex->endIndexing();
|
||||
}
|
||||
|
@@ -22,23 +22,21 @@
|
||||
#include "databasecommand.h"
|
||||
#include "dllmacro.h"
|
||||
|
||||
class IndexingJobItem;
|
||||
|
||||
class DLLEXPORT DatabaseCommand_UpdateSearchIndex : public DatabaseCommand
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DatabaseCommand_UpdateSearchIndex();
|
||||
virtual ~DatabaseCommand_UpdateSearchIndex();
|
||||
|
||||
virtual QString commandname() const { return "updatesearchindex"; }
|
||||
virtual bool doesMutates() const { return true; }
|
||||
virtual void exec( DatabaseImpl* db );
|
||||
|
||||
signals:
|
||||
void indexUpdated();
|
||||
|
||||
private:
|
||||
void indexTable( DatabaseImpl* db, const QString& table );
|
||||
|
||||
QString table;
|
||||
IndexingJobItem* m_statusJob;
|
||||
};
|
||||
|
||||
#endif // DATABASECOMMAND_UPDATESEARCHINDEX_H
|
||||
|
@@ -79,6 +79,9 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
|
||||
query.exec( "UPDATE source SET isonline = 'false'" );
|
||||
|
||||
m_fuzzyIndex = new FuzzyIndex( *this, schemaUpdated );
|
||||
if ( schemaUpdated )
|
||||
QTimer::singleShot( 0, this, SLOT( updateIndex() ) );
|
||||
|
||||
tDebug( LOGVERBOSE ) << "Loaded index:" << t.elapsed();
|
||||
|
||||
if ( qApp->arguments().contains( "--dumpdb" ) )
|
||||
@@ -405,13 +408,36 @@ DatabaseImpl::albumId( int artistid, const QString& name_orig, bool autoCreate )
|
||||
|
||||
|
||||
QList< QPair<int, float> >
|
||||
DatabaseImpl::searchTable( const QString& table, const QString& name, uint limit )
|
||||
DatabaseImpl::search( const Tomahawk::query_ptr& query, uint limit )
|
||||
{
|
||||
QList< QPair<int, float> > resultslist;
|
||||
if ( table != "artist" && table != "track" && table != "album" )
|
||||
|
||||
QMap< int, float > resultsmap = m_fuzzyIndex->search( query );
|
||||
foreach ( int i, resultsmap.keys() )
|
||||
{
|
||||
resultslist << QPair<int, float>( i, (float)resultsmap.value( i ) );
|
||||
}
|
||||
qSort( resultslist.begin(), resultslist.end(), DatabaseImpl::scorepairSorter );
|
||||
|
||||
if ( !limit )
|
||||
return resultslist;
|
||||
|
||||
QMap< int, float > resultsmap = m_fuzzyIndex->search( table, name );
|
||||
QList< QPair<int, float> > resultscapped;
|
||||
for ( int i = 0; i < (int)limit && i < resultsmap.count(); i++ )
|
||||
{
|
||||
resultscapped << resultslist.at( i );
|
||||
}
|
||||
|
||||
return resultscapped;
|
||||
}
|
||||
|
||||
|
||||
QList< QPair<int, float> >
|
||||
DatabaseImpl::searchAlbum( const Tomahawk::query_ptr& query, uint limit )
|
||||
{
|
||||
QList< QPair<int, float> > resultslist;
|
||||
|
||||
QMap< int, float > resultsmap = m_fuzzyIndex->searchAlbum( query );
|
||||
foreach ( int i, resultsmap.keys() )
|
||||
{
|
||||
resultslist << QPair<int, float>( i, (float)resultsmap.value( i ) );
|
||||
@@ -696,3 +722,11 @@ DatabaseImpl::openDatabase( const QString& dbname )
|
||||
|
||||
return schemaUpdated;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DatabaseImpl::updateIndex()
|
||||
{
|
||||
DatabaseCommand* cmd = new DatabaseCommand_UpdateSearchIndex();
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
|
||||
}
|
||||
|
@@ -56,7 +56,8 @@ public:
|
||||
int trackId( int artistid, const QString& name_orig, bool autoCreate );
|
||||
int albumId( int artistid, const QString& name_orig, bool autoCreate );
|
||||
|
||||
QList< QPair<int, float> > searchTable( const QString& table, const QString& name, uint limit = 0 );
|
||||
QList< QPair<int, float> > search( const Tomahawk::query_ptr& query, uint limit = 0 );
|
||||
QList< QPair<int, float> > searchAlbum( const Tomahawk::query_ptr& query, uint limit = 0 );
|
||||
QList< int > getTrackFids( int tid );
|
||||
|
||||
static QString sortname( const QString& str, bool replaceArticle = false );
|
||||
@@ -79,7 +80,8 @@ public:
|
||||
signals:
|
||||
void indexReady();
|
||||
|
||||
public slots:
|
||||
private slots:
|
||||
void updateIndex();
|
||||
|
||||
private:
|
||||
QString cleanSql( const QString& sql );
|
||||
|
@@ -22,12 +22,14 @@
|
||||
#include <QTime>
|
||||
|
||||
#include <CLucene.h>
|
||||
#include <CLucene/queryParser/MultiFieldQueryParser.h>
|
||||
|
||||
#include "databaseimpl.h"
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
using namespace lucene::analysis;
|
||||
using namespace lucene::analysis::standard;
|
||||
using namespace lucene::document;
|
||||
using namespace lucene::store;
|
||||
using namespace lucene::index;
|
||||
@@ -83,7 +85,7 @@ FuzzyIndex::beginIndexing()
|
||||
}
|
||||
|
||||
qDebug() << "Creating new index writer.";
|
||||
IndexWriter luceneWriter = IndexWriter( m_luceneDir, m_analyzer, true );
|
||||
IndexWriter luceneWriter( m_luceneDir, m_analyzer, true );
|
||||
}
|
||||
catch( CLuceneError& error )
|
||||
{
|
||||
@@ -102,38 +104,55 @@ FuzzyIndex::endIndexing()
|
||||
|
||||
|
||||
void
|
||||
FuzzyIndex::appendFields( const QString& table, const QMap< unsigned int, QString >& fields )
|
||||
FuzzyIndex::appendFields( const QMap< unsigned int, QMap< QString, QString > >& trackData )
|
||||
{
|
||||
try
|
||||
{
|
||||
qDebug() << "Appending to index:" << fields.count();
|
||||
tDebug() << "Appending to index:" << trackData.count();
|
||||
bool create = !IndexReader::indexExists( TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ).toStdString().c_str() );
|
||||
IndexWriter luceneWriter = IndexWriter( m_luceneDir, m_analyzer, create );
|
||||
IndexWriter luceneWriter( m_luceneDir, m_analyzer, create );
|
||||
Document doc;
|
||||
|
||||
QMapIterator< unsigned int, QString > it( fields );
|
||||
QMapIterator< unsigned int, QMap< QString, QString > > it( trackData );
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
it.next();
|
||||
unsigned int id = it.key();
|
||||
QString name = it.value();
|
||||
QMap< QString, QString > values = it.value();
|
||||
|
||||
if ( values.contains( "track" ) )
|
||||
{
|
||||
Field* field = _CLNEW Field( table.toStdWString().c_str(), DatabaseImpl::sortname( name ).toStdWString().c_str(),
|
||||
Field::STORE_YES | Field::INDEX_UNTOKENIZED );
|
||||
doc.add( *field );
|
||||
}
|
||||
doc.add( *( _CLNEW Field( _T( "fulltext" ), DatabaseImpl::sortname( QString( "%1 %2" ).arg( values.value( "artist" ) ).arg( values.value( "track" ) ) ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
|
||||
{
|
||||
Field* field = _CLNEW Field( _T( "id" ), QString::number( id ).toStdWString().c_str(),
|
||||
Field::STORE_YES | Field::INDEX_NO );
|
||||
doc.add( *field );
|
||||
doc.add( *( _CLNEW Field( _T( "track" ), DatabaseImpl::sortname( values.value( "track" ) ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
|
||||
doc.add( *( _CLNEW Field( _T( "artist" ), DatabaseImpl::sortname( values.value( "artist" ) ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
|
||||
doc.add( *( _CLNEW Field( _T( "artistid" ), values.value( "artistid" ).toStdWString().c_str(),
|
||||
Field::STORE_YES | Field::INDEX_NO ) ) );
|
||||
|
||||
doc.add( *( _CLNEW Field( _T( "trackid" ), QString::number( id ).toStdWString().c_str(),
|
||||
Field::STORE_YES | Field::INDEX_NO ) ) );
|
||||
}
|
||||
else if ( values.contains( "album" ) )
|
||||
{
|
||||
doc.add( *( _CLNEW Field( _T( "album" ), DatabaseImpl::sortname( values.value( "album" ) ).toStdWString().c_str(),
|
||||
Field::STORE_NO | Field::INDEX_UNTOKENIZED ) ) );
|
||||
|
||||
doc.add( *( _CLNEW Field( _T( "albumid" ), QString::number( id ).toStdWString().c_str(),
|
||||
Field::STORE_YES | Field::INDEX_NO ) ) );
|
||||
}
|
||||
else
|
||||
Q_ASSERT( false );
|
||||
|
||||
luceneWriter.addDocument( &doc );
|
||||
doc.clear();
|
||||
}
|
||||
|
||||
luceneWriter.optimize();
|
||||
luceneWriter.close();
|
||||
}
|
||||
catch( CLuceneError& error )
|
||||
@@ -152,7 +171,7 @@ FuzzyIndex::loadLuceneIndex()
|
||||
|
||||
|
||||
QMap< int, float >
|
||||
FuzzyIndex::search( const QString& table, const QString& name )
|
||||
FuzzyIndex::search( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
QMutexLocker lock( &m_mutex );
|
||||
|
||||
@@ -171,33 +190,112 @@ FuzzyIndex::search( const QString& table, const QString& name )
|
||||
m_luceneSearcher = _CLNEW IndexSearcher( m_luceneReader );
|
||||
}
|
||||
|
||||
if ( name.isEmpty() )
|
||||
return resultsmap;
|
||||
float minScore;
|
||||
const TCHAR** fields = 0;
|
||||
MultiFieldQueryParser parser( fields, m_analyzer );
|
||||
BooleanQuery* qry = _CLNEW BooleanQuery();
|
||||
|
||||
SimpleAnalyzer analyzer;
|
||||
QueryParser parser( table.toStdWString().c_str(), m_analyzer );
|
||||
Hits* hits = 0;
|
||||
if ( query->isFullTextQuery() )
|
||||
{
|
||||
QString escapedQuery = QString::fromWCharArray( parser.escape( DatabaseImpl::sortname( query->fullTextQuery() ).toStdWString().c_str() ) );
|
||||
|
||||
Term* term = _CLNEW Term( _T( "track" ), escapedQuery.toStdWString().c_str() );
|
||||
Query* fqry = _CLNEW FuzzyQuery( term );
|
||||
qry->add( fqry, true, BooleanClause::SHOULD );
|
||||
|
||||
FuzzyQuery* qry = _CLNEW FuzzyQuery( _CLNEW Term( table.toStdWString().c_str(), DatabaseImpl::sortname( name ).toStdWString().c_str() ) );
|
||||
hits = m_luceneSearcher->search( qry );
|
||||
term = _CLNEW Term( _T( "artist" ), escapedQuery.toStdWString().c_str() );
|
||||
fqry = _CLNEW FuzzyQuery( term );
|
||||
qry->add( fqry, true, BooleanClause::SHOULD );
|
||||
|
||||
term = _CLNEW Term( _T( "fulltext" ), escapedQuery.toStdWString().c_str() );
|
||||
fqry = _CLNEW FuzzyQuery( term );
|
||||
qry->add( fqry, true, BooleanClause::SHOULD );
|
||||
|
||||
minScore = 0.00;
|
||||
}
|
||||
else
|
||||
{
|
||||
QString track = QString::fromWCharArray( parser.escape( DatabaseImpl::sortname( query->track() ).toStdWString().c_str() ) );
|
||||
QString artist = QString::fromWCharArray( parser.escape( DatabaseImpl::sortname( query->artist() ).toStdWString().c_str() ) );
|
||||
// QString album = QString::fromWCharArray( parser.escape( query->album().toStdWString().c_str() ) );
|
||||
|
||||
Term* term = _CLNEW Term( _T( "track" ), track.toStdWString().c_str() );
|
||||
Query* fqry = _CLNEW FuzzyQuery( term );
|
||||
qry->add( fqry, true, BooleanClause::MUST );
|
||||
|
||||
term = _CLNEW Term( _T( "artist" ), artist.toStdWString().c_str() );
|
||||
fqry = _CLNEW FuzzyQuery( term );
|
||||
qry->add( fqry, true, BooleanClause::MUST );
|
||||
|
||||
minScore = 0.05;
|
||||
}
|
||||
|
||||
Hits* hits = m_luceneSearcher->search( qry );
|
||||
for ( uint i = 0; i < hits->length(); i++ )
|
||||
{
|
||||
Document* d = &hits->doc( i );
|
||||
|
||||
float score = hits->score( i );
|
||||
int id = QString::fromWCharArray( d->get( _T( "id" ) ) ).toInt();
|
||||
QString result = QString::fromWCharArray( d->get( table.toStdWString().c_str() ) );
|
||||
int id = QString::fromWCharArray( d->get( _T( "trackid" ) ) ).toInt();
|
||||
|
||||
if ( DatabaseImpl::sortname( result ) == DatabaseImpl::sortname( name ) )
|
||||
score = 1.0;
|
||||
else
|
||||
score = qMin( score, (float)0.99 );
|
||||
|
||||
if ( score > 0.05 )
|
||||
if ( score > minScore )
|
||||
{
|
||||
resultsmap.insert( id, score );
|
||||
// qDebug() << "Hitres:" << result << id << score << table << name;
|
||||
// tDebug() << "Index hit:" << id << score << QString::fromWCharArray( ((Query*)qry)->toString() );
|
||||
}
|
||||
}
|
||||
|
||||
delete hits;
|
||||
delete qry;
|
||||
}
|
||||
catch( CLuceneError& error )
|
||||
{
|
||||
tDebug() << "Caught CLucene error:" << error.what();
|
||||
Q_ASSERT( false );
|
||||
}
|
||||
|
||||
return resultsmap;
|
||||
}
|
||||
|
||||
|
||||
QMap< int, float >
|
||||
FuzzyIndex::searchAlbum( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
Q_ASSERT( query->isFullTextQuery() );
|
||||
|
||||
QMutexLocker lock( &m_mutex );
|
||||
|
||||
QMap< int, float > resultsmap;
|
||||
try
|
||||
{
|
||||
if ( !m_luceneReader )
|
||||
{
|
||||
if ( !IndexReader::indexExists( TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ).toStdString().c_str() ) )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "index didn't exist.";
|
||||
return resultsmap;
|
||||
}
|
||||
|
||||
m_luceneReader = IndexReader::open( m_luceneDir );
|
||||
m_luceneSearcher = _CLNEW IndexSearcher( m_luceneReader );
|
||||
}
|
||||
|
||||
QueryParser parser( _T( "album" ), m_analyzer );
|
||||
QString escapedName = QString::fromWCharArray( parser.escape( DatabaseImpl::sortname( query->fullTextQuery() ).toStdWString().c_str() ) );
|
||||
|
||||
Query* qry = _CLNEW FuzzyQuery( _CLNEW Term( _T( "album" ), escapedName.toStdWString().c_str() ) );
|
||||
Hits* hits = m_luceneSearcher->search( qry );
|
||||
for ( uint i = 0; i < hits->length(); i++ )
|
||||
{
|
||||
Document* d = &hits->doc( i );
|
||||
|
||||
float score = hits->score( i );
|
||||
int id = QString::fromWCharArray( d->get( _T( "albumid" ) ) ).toInt();
|
||||
|
||||
if ( score > 0.30 )
|
||||
{
|
||||
resultsmap.insert( id, score );
|
||||
// tDebug() << "Index hit:" << id << score;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -25,6 +25,8 @@
|
||||
#include <QString>
|
||||
#include <QMutex>
|
||||
|
||||
#include "query.h"
|
||||
|
||||
namespace lucene
|
||||
{
|
||||
namespace analysis
|
||||
@@ -58,7 +60,7 @@ public:
|
||||
|
||||
void beginIndexing();
|
||||
void endIndexing();
|
||||
void appendFields( const QString& table, const QMap< unsigned int, QString >& fields );
|
||||
void appendFields( const QMap< unsigned int, QMap< QString, QString > >& trackData );
|
||||
|
||||
signals:
|
||||
void indexReady();
|
||||
@@ -66,7 +68,8 @@ signals:
|
||||
public slots:
|
||||
void loadLuceneIndex();
|
||||
|
||||
QMap< int, float > search( const QString& table, const QString& name );
|
||||
QMap< int, float > search( const Tomahawk::query_ptr& query );
|
||||
QMap< int, float > searchAlbum( const Tomahawk::query_ptr& query );
|
||||
|
||||
private:
|
||||
DatabaseImpl& m_db;
|
||||
|
@@ -162,6 +162,7 @@ CREATE TABLE IF NOT EXISTS file (
|
||||
);
|
||||
CREATE UNIQUE INDEX file_url_src_uniq ON file(source, url);
|
||||
CREATE INDEX file_source ON file(source);
|
||||
CREATE INDEX file_mtime ON file(mtime);
|
||||
|
||||
-- mtime of dir when last scanned.
|
||||
-- load into memory when rescanning, skip stuff that's unchanged
|
||||
|
@@ -35,6 +35,9 @@
|
||||
#include "utils/xspfloader.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#include "jobview/ErrorStatusMessage.h"
|
||||
#include "pipeline.h"
|
||||
|
||||
#ifdef QCA2_FOUND
|
||||
#include "utils/groovesharkparser.h"
|
||||
#endif //QCA2_FOUND
|
||||
@@ -43,7 +46,7 @@
|
||||
using namespace Tomahawk;
|
||||
|
||||
bool DropJob::s_canParseSpotifyPlaylists = false;
|
||||
|
||||
static QString s_dropJobInfoId = "dropjob";
|
||||
|
||||
DropJob::DropJob( QObject *parent )
|
||||
: QObject( parent )
|
||||
@@ -124,7 +127,7 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType
|
||||
// Not the most elegant
|
||||
if ( url.contains( "spotify" ) && url.contains( "playlist" ) && s_canParseSpotifyPlaylists )
|
||||
return true;
|
||||
|
||||
|
||||
if ( url.contains( "grooveshark.com" ) && url.contains( "playlist" ) )
|
||||
return true;
|
||||
}
|
||||
@@ -571,7 +574,7 @@ DropJob::handleGroovesharkUrls ( const QString& urlsRaw )
|
||||
#ifdef QCA2_FOUND
|
||||
QStringList urls = urlsRaw.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
|
||||
tDebug() << "Got Grooveshark urls!" << urls;
|
||||
|
||||
|
||||
if ( dropAction() == Default )
|
||||
setDropAction( Create );
|
||||
|
||||
@@ -691,6 +694,67 @@ DropJob::onTracksAdded( const QList<Tomahawk::query_ptr>& tracksList )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::tracksFromDB( const QList< query_ptr >& tracks )
|
||||
{
|
||||
// Tracks that we get from databasecommand_alltracks are resolved only against the database and explicitly marked
|
||||
// as finished. if the source they resolve to is offline they will not resolve against any resolver.
|
||||
// explicitly resolve them if they fall in that case first
|
||||
foreach( const query_ptr& track, tracks )
|
||||
{
|
||||
if ( !track->playable() && !track->solved() && track->results().size() ) // we have offline results
|
||||
{
|
||||
track->setResolveFinished( false );
|
||||
Pipeline::instance()->resolve( track );
|
||||
}
|
||||
}
|
||||
|
||||
album_ptr albumPtr;
|
||||
artist_ptr artistPtr;
|
||||
if ( Tomahawk::Album* album = qobject_cast< Tomahawk::Album* >( sender() ) )
|
||||
{
|
||||
foreach ( const album_ptr& ptr, m_albumsToKeep )
|
||||
if ( ptr.data() == album )
|
||||
{
|
||||
albumPtr = ptr;
|
||||
m_albumsToKeep.remove( ptr );
|
||||
}
|
||||
}
|
||||
else if ( Tomahawk::Artist* artist = qobject_cast< Tomahawk::Artist* >( sender() ) )
|
||||
{
|
||||
foreach ( const artist_ptr& ptr, m_artistsToKeep )
|
||||
if ( ptr.data() == artist )
|
||||
{
|
||||
artistPtr = ptr;
|
||||
m_artistsToKeep.remove( ptr );
|
||||
}
|
||||
}
|
||||
|
||||
// If we have no tracks, this means no sources in our network have the give request (artist or album)
|
||||
// Since we really do want to try to drop them, we ask the infosystem as well.
|
||||
if ( tracks.isEmpty() )
|
||||
{
|
||||
if ( !albumPtr.isNull() && !albumPtr->artist().isNull() )
|
||||
{
|
||||
Q_ASSERT( artistPtr.isNull() );
|
||||
--m_queryCount; // This query is done. New query is infosystem query
|
||||
getAlbumFromInfoystem( albumPtr->artist()->name(), albumPtr->name() );
|
||||
}
|
||||
else if ( !artistPtr.isNull() )
|
||||
{
|
||||
Q_ASSERT( albumPtr.isNull() );
|
||||
--m_queryCount;
|
||||
getTopTen( artistPtr->name() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
onTracksAdded( tracks );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::removeDuplicates()
|
||||
{
|
||||
@@ -699,10 +763,18 @@ DropJob::removeDuplicates()
|
||||
{
|
||||
bool contains = false;
|
||||
foreach( const Tomahawk::query_ptr &tmpItem, list )
|
||||
{
|
||||
if ( item->album() == tmpItem->album()
|
||||
&& item->artist() == tmpItem->artist()
|
||||
&& item->track() == tmpItem->track() )
|
||||
{
|
||||
if ( item->playable() && !tmpItem->playable() )
|
||||
list.replace( list.indexOf( tmpItem ), item );
|
||||
|
||||
contains = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !contains )
|
||||
list.append( item );
|
||||
}
|
||||
@@ -733,28 +805,31 @@ DropJob::removeRemoteSources()
|
||||
void
|
||||
DropJob::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
|
||||
{
|
||||
if ( requestData.caller == "changeme" )
|
||||
if ( requestData.caller == s_dropJobInfoId )
|
||||
{
|
||||
Tomahawk::InfoSystem::InfoStringHash artistInfo;
|
||||
const Tomahawk::InfoSystem::InfoStringHash info = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
|
||||
|
||||
artistInfo = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
|
||||
const QString artist = info["artist"];
|
||||
const QString album = info["album"];
|
||||
|
||||
QString artist = artistInfo["artist"];
|
||||
|
||||
qDebug() << "Got requestData response for artist" << artist << output;
|
||||
qDebug() << "Got requestData response for artist" << artist << "and album:" << album << output;
|
||||
|
||||
QList< query_ptr > results;
|
||||
|
||||
int i = 0;
|
||||
foreach ( const QVariant& title, output.toMap().value( "tracks" ).toList() )
|
||||
{
|
||||
qDebug() << "got title" << title;
|
||||
results << Query::get( artist, title.toString(), QString(), uuid() );
|
||||
|
||||
if ( ++i == 10 ) // Only getting top ten for now. Would make sense to make it configurable
|
||||
break;
|
||||
}
|
||||
|
||||
if ( results.isEmpty() )
|
||||
{
|
||||
const QString which = album.isEmpty() ? "artist" : "album";
|
||||
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "No tracks found for given %1" ).arg( which ), 5 ) );
|
||||
}
|
||||
onTracksAdded( results );
|
||||
}
|
||||
}
|
||||
@@ -766,8 +841,10 @@ DropJob::getArtist( const QString &artist )
|
||||
artist_ptr artistPtr = Artist::get( artist );
|
||||
if ( artistPtr->playlistInterface()->tracks().isEmpty() )
|
||||
{
|
||||
m_artistsToKeep.insert( artistPtr );
|
||||
|
||||
connect( artistPtr.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr> ) ),
|
||||
SLOT( onTracksAdded( QList<Tomahawk::query_ptr> ) ) );
|
||||
SLOT( tracksFromDB( QList<Tomahawk::query_ptr> ) ) );
|
||||
m_queryCount++;
|
||||
return QList< query_ptr >();
|
||||
}
|
||||
@@ -787,9 +864,14 @@ DropJob::getAlbum(const QString &artist, const QString &album)
|
||||
|
||||
if ( albumPtr->playlistInterface()->tracks().isEmpty() )
|
||||
{
|
||||
// For albums that don't exist until this moment, we are the main shared pointer holding on.
|
||||
// fetching the tracks is asynchronous, so the resulting signal is queued. when we go out of scope we delete
|
||||
// the artist_ptr which means we never get the signal delivered. so we hold on to the album pointer till we're done
|
||||
m_albumsToKeep.insert( albumPtr );
|
||||
|
||||
m_dropJob = new DropJobNotifier( QPixmap( RESPATH "images/album-icon.png" ), Album );
|
||||
connect( albumPtr.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr> ) ),
|
||||
SLOT( onTracksAdded( QList<Tomahawk::query_ptr> ) ) );
|
||||
SLOT( tracksFromDB( QList<Tomahawk::query_ptr> ) ) );
|
||||
JobStatusView::instance()->model()->addJob( m_dropJob );
|
||||
|
||||
m_queryCount++;
|
||||
@@ -811,7 +893,7 @@ DropJob::getTopTen( const QString &artist )
|
||||
artistInfo["artist"] = artist;
|
||||
|
||||
Tomahawk::InfoSystem::InfoRequestData requestData;
|
||||
requestData.caller = "changeme";
|
||||
requestData.caller = s_dropJobInfoId;
|
||||
requestData.customData = QVariantMap();
|
||||
|
||||
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
|
||||
@@ -821,3 +903,28 @@ DropJob::getTopTen( const QString &artist )
|
||||
|
||||
m_queryCount++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::getAlbumFromInfoystem( const QString& artist, const QString& album )
|
||||
{
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
|
||||
|
||||
Tomahawk::InfoSystem::InfoStringHash artistInfo;
|
||||
artistInfo["artist"] = artist;
|
||||
artistInfo["album"] = album;
|
||||
|
||||
Tomahawk::InfoSystem::InfoRequestData requestData;
|
||||
requestData.caller = s_dropJobInfoId;
|
||||
requestData.customData = QVariantMap();
|
||||
|
||||
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
|
||||
|
||||
requestData.type = Tomahawk::InfoSystem::InfoAlbumSongs;
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
|
||||
|
||||
m_queryCount++;
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,8 @@
|
||||
#include "query.h"
|
||||
|
||||
#include "infosystem/infosystem.h"
|
||||
#include "utils/xspfloader.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QMimeData>
|
||||
@@ -120,9 +122,9 @@ private slots:
|
||||
void onTracksAdded( const QList<Tomahawk::query_ptr>& );
|
||||
void infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
|
||||
|
||||
void tracksFromDB( const QList< Tomahawk::query_ptr >& );
|
||||
private:
|
||||
/// handle parsing mime data
|
||||
|
||||
void handleAllUrls( const QString& urls );
|
||||
void handleTrackUrls( const QString& urls );
|
||||
QList< Tomahawk::query_ptr > tracksFromQueryList( const QMimeData* d );
|
||||
@@ -135,6 +137,7 @@ private:
|
||||
QList< Tomahawk::query_ptr > getAlbum( const QString& artist, const QString& album );
|
||||
|
||||
void getTopTen( const QString& artist );
|
||||
void getAlbumFromInfoystem( const QString& artist, const QString& album );
|
||||
|
||||
void removeDuplicates();
|
||||
void removeRemoteSources();
|
||||
@@ -151,6 +154,8 @@ private:
|
||||
Tomahawk::DropJobNotifier* m_dropJob;
|
||||
|
||||
QList< Tomahawk::query_ptr > m_resultList;
|
||||
QSet< Tomahawk::album_ptr > m_albumsToKeep;
|
||||
QSet< Tomahawk::artist_ptr > m_artistsToKeep;
|
||||
|
||||
static bool s_canParseSpotifyPlaylists;
|
||||
};
|
||||
|
@@ -45,9 +45,9 @@ ChartsPlugin::ChartsPlugin()
|
||||
, m_chartsFetchJobs( 0 )
|
||||
{
|
||||
/// Add resources here
|
||||
m_chartResources << "billboard" << "itunes" << "rdio" << "wearehunted" << "ex.fm" << "soundcloudwall.com";
|
||||
m_chartResources << "billboard" << "itunes" << "rdio" << "wearehunted" << "ex.fm" << "soundcloudwall";
|
||||
/// If you add resource, update version aswell
|
||||
m_chartVersion = "1.0";
|
||||
m_chartVersion = "2.1";
|
||||
m_supportedGetTypes << InfoChart << InfoChartCapabilities;
|
||||
|
||||
}
|
||||
@@ -332,7 +332,9 @@ ChartsPlugin::chartTypes()
|
||||
if( source == "itunes" ){
|
||||
chartName = "iTunes";
|
||||
}
|
||||
|
||||
if( source == "soundcloudwall" ){
|
||||
chartName = "SoundCloudWall";
|
||||
}
|
||||
if( source == "wearehunted" ){
|
||||
chartName = "WeAreHunted";
|
||||
}
|
||||
|
@@ -451,8 +451,15 @@ LastFmPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSy
|
||||
QString artistName = criteria["artist"];
|
||||
QString albumName = criteria["album"];
|
||||
|
||||
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=album.imageredirect&artist=%1&album=%2&autocorrect=1&size=large&api_key=7a90f6672a04b809ee309af169f34b8b";
|
||||
QNetworkRequest req( imgurl.arg( artistName ).arg( albumName ) );
|
||||
QUrl imgurl( "http://ws.audioscrobbler.com/2.0/" );
|
||||
imgurl.addQueryItem( "method", "album.imageredirect" );
|
||||
imgurl.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artistName, "", "+" ) );
|
||||
imgurl.addEncodedQueryItem( "album", QUrl::toPercentEncoding( albumName, "", "+" ) );
|
||||
imgurl.addQueryItem( "autocorrect", QString::number( 1 ) );
|
||||
imgurl.addQueryItem( "size", "large" );
|
||||
imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" );
|
||||
|
||||
QNetworkRequest req( imgurl );
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( req );
|
||||
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
|
||||
|
||||
@@ -464,8 +471,14 @@ LastFmPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSy
|
||||
{
|
||||
QString artistName = criteria["artist"];
|
||||
|
||||
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=artist.imageredirect&artist=%1&autocorrect=1&size=large&api_key=7a90f6672a04b809ee309af169f34b8b";
|
||||
QNetworkRequest req( imgurl.arg( artistName ) );
|
||||
QUrl imgurl( "http://ws.audioscrobbler.com/2.0/" );
|
||||
imgurl.addQueryItem( "method", "artist.imageredirect" );
|
||||
imgurl.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artistName, "", "+" ) );
|
||||
imgurl.addQueryItem( "autocorrect", QString::number( 1 ) );
|
||||
imgurl.addQueryItem( "size", "large" );
|
||||
imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" );
|
||||
|
||||
QNetworkRequest req( imgurl );
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( req );
|
||||
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
|
||||
|
||||
|
@@ -43,7 +43,6 @@ SpotifyPlugin::SpotifyPlugin()
|
||||
: InfoPlugin()
|
||||
, m_chartsFetchJobs( 0 )
|
||||
{
|
||||
|
||||
m_supportedGetTypes << InfoChart << InfoChartCapabilities;
|
||||
|
||||
}
|
||||
@@ -71,7 +70,6 @@ SpotifyPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
|
||||
InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash >();
|
||||
|
||||
|
||||
switch ( requestData.type )
|
||||
{
|
||||
case InfoChart:
|
||||
@@ -87,6 +85,7 @@ SpotifyPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
case InfoChartCapabilities:
|
||||
fetchChartCapabilities( requestData );
|
||||
break;
|
||||
|
||||
default:
|
||||
dataError( requestData );
|
||||
}
|
||||
@@ -110,7 +109,6 @@ SpotifyPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Hash did not contain required params!";
|
||||
dataError( requestData );
|
||||
return;
|
||||
|
||||
}
|
||||
/// Set the criterias for current chart
|
||||
criteria["chart_id"] = hash["chart_id"];
|
||||
@@ -118,6 +116,8 @@ SpotifyPlugin::fetchChart( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
|
||||
emit getCachedInfo( criteria, 86400000 /* Expire chart cache in 1 day */, requestData );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
{
|
||||
@@ -132,12 +132,12 @@ SpotifyPlugin::fetchChartCapabilities( Tomahawk::InfoSystem::InfoRequestData req
|
||||
emit getCachedInfo( criteria, 604800000, requestData );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyPlugin::notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
{
|
||||
switch ( requestData.type )
|
||||
{
|
||||
|
||||
case InfoChart:
|
||||
{
|
||||
/// Fetch the chart, we need source and id
|
||||
@@ -149,8 +149,6 @@ SpotifyPlugin::notInCacheSlot( Tomahawk::InfoSystem::InfoStringHash criteria, To
|
||||
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
|
||||
connect( reply, SIGNAL( finished() ), SLOT( chartReturned() ) );
|
||||
return;
|
||||
|
||||
|
||||
}
|
||||
case InfoChartCapabilities:
|
||||
{
|
||||
@@ -212,9 +210,8 @@ SpotifyPlugin::chartTypes()
|
||||
}
|
||||
|
||||
QVariantMap charts;
|
||||
foreach(QVariant geos, chartObj.value("Charts").toList().takeLast().toMap().value("geo").toList() )
|
||||
foreach( QVariant geos, chartObj.value( "Charts" ).toList().takeLast().toMap().value( "geo" ).toList() )
|
||||
{
|
||||
|
||||
const QString geo = geos.toMap().value( "name" ).toString();
|
||||
const QString geoId = geos.toMap().value( "id" ).toString();
|
||||
QString country;
|
||||
@@ -225,7 +222,6 @@ SpotifyPlugin::chartTypes()
|
||||
country = geo;
|
||||
else
|
||||
{
|
||||
|
||||
QLocale l( QString( "en_%1" ).arg( geo ) );
|
||||
country = Tomahawk::CountryUtils::fullCountryFromCode( geo );
|
||||
|
||||
@@ -240,7 +236,7 @@ SpotifyPlugin::chartTypes()
|
||||
}
|
||||
|
||||
QList< InfoStringHash > chart_types;
|
||||
foreach(QVariant types, chartObj.value("Charts").toList().takeFirst().toMap().value("types").toList() )
|
||||
foreach( QVariant types, chartObj.value( "Charts" ).toList().takeFirst().toMap().value( "types" ).toList() )
|
||||
{
|
||||
QString type = types.toMap().value( "id" ).toString();
|
||||
QString label = types.toMap().value( "name" ).toString();
|
||||
@@ -251,18 +247,15 @@ SpotifyPlugin::chartTypes()
|
||||
c[ "type" ] = type;
|
||||
|
||||
chart_types.append( c );
|
||||
|
||||
}
|
||||
|
||||
charts.insert( country.toUtf8(), QVariant::fromValue<QList< InfoStringHash > >( chart_types ) );
|
||||
|
||||
}
|
||||
|
||||
QVariantMap defaultMap;
|
||||
defaultMap[ "spotify" ] = QStringList() << "United States" << "Top Albums";
|
||||
m_allChartsMap[ "defaults" ] = defaultMap;
|
||||
m_allChartsMap.insert( "Spotify", QVariant::fromValue<QVariantMap>( charts ) );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -281,13 +274,12 @@ SpotifyPlugin::chartTypes()
|
||||
}
|
||||
m_cachedRequests.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyPlugin::chartReturned()
|
||||
{
|
||||
|
||||
/// Chart request returned something! Woho
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
|
||||
QString url = reply->url().toString();
|
||||
@@ -318,14 +310,13 @@ SpotifyPlugin::chartReturned()
|
||||
else
|
||||
setChartType( None );
|
||||
|
||||
foreach(QVariant result, res.value("toplist").toMap().value("result").toList() )
|
||||
foreach( QVariant result, res.value( "toplist" ).toMap().value( "result" ).toList() )
|
||||
{
|
||||
QString title, artist;
|
||||
QVariantMap chartMap = result.toMap();
|
||||
|
||||
if ( !chartMap.isEmpty() )
|
||||
{
|
||||
|
||||
title = chartMap.value( "title" ).toString();
|
||||
artist = chartMap.value( "artist" ).toString();
|
||||
|
||||
@@ -341,7 +332,6 @@ SpotifyPlugin::chartReturned()
|
||||
|
||||
if( chartType() == Album )
|
||||
{
|
||||
|
||||
InfoStringHash pair;
|
||||
pair["artist"] = artist;
|
||||
pair["album"] = title;
|
||||
@@ -351,10 +341,8 @@ SpotifyPlugin::chartReturned()
|
||||
|
||||
if( chartType() == Artist )
|
||||
{
|
||||
|
||||
top_artists << chartMap.value( "name" ).toString();
|
||||
qDebug() << "SpotifyChart type is artist";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -393,5 +381,4 @@ SpotifyPlugin::chartReturned()
|
||||
}
|
||||
else
|
||||
qDebug() << "Network error in fetching chart:" << reply->url().toString();
|
||||
|
||||
}
|
||||
|
@@ -42,8 +42,6 @@ MprisPlugin::MprisPlugin()
|
||||
: InfoPlugin()
|
||||
, m_coverTempFile( 0 )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
// init
|
||||
m_playbackStatus = "Stopped";
|
||||
|
||||
@@ -54,79 +52,84 @@ MprisPlugin::MprisPlugin()
|
||||
new MprisPluginRootAdaptor( this );
|
||||
new MprisPluginPlayerAdaptor( this );
|
||||
QDBusConnection dbus = QDBusConnection::sessionBus();
|
||||
dbus.registerObject("/org/mpris/MediaPlayer2", this);
|
||||
dbus.registerService("org.mpris.MediaPlayer2.tomahawk");
|
||||
dbus.registerObject( "/org/mpris/MediaPlayer2", this );
|
||||
dbus.registerService( "org.mpris.MediaPlayer2.tomahawk" );
|
||||
|
||||
// Listen to volume changes
|
||||
connect( AudioEngine::instance(), SIGNAL( volumeChanged( int ) ),
|
||||
SLOT( onVolumeChanged( int ) ) );
|
||||
SLOT( onVolumeChanged( int ) ) );
|
||||
|
||||
// When the playlist changes, signals for several properties are sent
|
||||
connect( AudioEngine::instance(), SIGNAL( playlistChanged( Tomahawk::playlistinterface_ptr ) ),
|
||||
SLOT( onPlaylistChanged( Tomahawk::playlistinterface_ptr ) ) );
|
||||
SLOT( onPlaylistChanged( Tomahawk::playlistinterface_ptr ) ) );
|
||||
|
||||
// When a track is added or removed, CanGoNext updated signal is sent
|
||||
Tomahawk::playlistinterface_ptr playlist = AudioEngine::instance()->playlist();
|
||||
if( !playlist.isNull() )
|
||||
if ( !playlist.isNull() )
|
||||
{
|
||||
connect( playlist.data(), SIGNAL( trackCountChanged( unsigned int ) ),
|
||||
SLOT( onTrackCountChanged( unsigned int ) ) );
|
||||
SLOT( onTrackCountChanged( unsigned int ) ) );
|
||||
}
|
||||
|
||||
// Connect to AudioEngine's seeked signal
|
||||
connect( AudioEngine::instance(), SIGNAL( seeked( qint64 ) ),
|
||||
SLOT( onSeeked( qint64 ) ) );
|
||||
SLOT( onSeeked( qint64 ) ) );
|
||||
|
||||
// Connect to the InfoSystem (we need to get album covers via getInfo)
|
||||
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
|
||||
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) );
|
||||
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
|
||||
SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) );
|
||||
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
|
||||
SIGNAL( finished( QString ) ),
|
||||
SLOT( infoSystemFinished( QString ) ) );
|
||||
}
|
||||
|
||||
|
||||
MprisPlugin::~MprisPlugin()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
delete m_coverTempFile;
|
||||
}
|
||||
|
||||
|
||||
// org.mpris.MediaPlayer2
|
||||
|
||||
bool
|
||||
MprisPlugin::canQuit() const
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MprisPlugin::canRaise() const
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MprisPlugin::hasTrackList() const
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
MprisPlugin::identity() const
|
||||
{
|
||||
return QString("Tomahawk");
|
||||
return QString( "Tomahawk" );
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
MprisPlugin::desktopEntry() const
|
||||
{
|
||||
return QString("tomahawk");
|
||||
return QString( "tomahawk" );
|
||||
}
|
||||
|
||||
|
||||
QStringList
|
||||
MprisPlugin::supportedUriSchemes() const
|
||||
{
|
||||
@@ -135,23 +138,27 @@ MprisPlugin::supportedUriSchemes() const
|
||||
return uriSchemes;
|
||||
}
|
||||
|
||||
|
||||
QStringList
|
||||
MprisPlugin::supportedMimeTypes() const
|
||||
{
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::Raise()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::Quit()
|
||||
{
|
||||
QApplication::quit();
|
||||
}
|
||||
|
||||
|
||||
// org.mpris.MediaPlayer2.Player
|
||||
|
||||
bool
|
||||
@@ -160,24 +167,28 @@ MprisPlugin::canControl() const
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MprisPlugin::canGoNext() const
|
||||
{
|
||||
return AudioEngine::instance()->canGoNext();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MprisPlugin::canGoPrevious() const
|
||||
{
|
||||
return AudioEngine::instance()->canGoPrevious();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MprisPlugin::canPause() const
|
||||
{
|
||||
return AudioEngine::instance()->currentTrack();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MprisPlugin::canPlay() const
|
||||
{
|
||||
@@ -186,6 +197,7 @@ MprisPlugin::canPlay() const
|
||||
return AudioEngine::instance()->currentTrack() || ( !p.isNull() && p->trackCount() );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MprisPlugin::canSeek() const
|
||||
{
|
||||
@@ -196,6 +208,7 @@ MprisPlugin::canSeek() const
|
||||
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
MprisPlugin::loopStatus() const
|
||||
{
|
||||
@@ -215,39 +228,42 @@ MprisPlugin::loopStatus() const
|
||||
return "None";
|
||||
break;
|
||||
default:
|
||||
return QString("None");
|
||||
return "None";
|
||||
break;
|
||||
}
|
||||
|
||||
return QString("None");
|
||||
return QString( "None" );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::setLoopStatus( const QString &value )
|
||||
MprisPlugin::setLoopStatus( const QString& value )
|
||||
{
|
||||
Tomahawk::playlistinterface_ptr p = AudioEngine::instance()->playlist();
|
||||
if ( p.isNull() )
|
||||
return;
|
||||
if( value == "Track")
|
||||
if ( value == "Track" )
|
||||
p->setRepeatMode( PlaylistInterface::RepeatOne );
|
||||
else if( value == "Playlist" )
|
||||
else if ( value == "Playlist" )
|
||||
p->setRepeatMode( PlaylistInterface::RepeatAll );
|
||||
else if( value == "None" )
|
||||
else if ( value == "None" )
|
||||
p->setRepeatMode( PlaylistInterface::NoRepeat );
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
MprisPlugin::maximumRate() const
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
|
||||
QVariantMap
|
||||
MprisPlugin::metadata() const
|
||||
{
|
||||
QVariantMap metadataMap;
|
||||
Tomahawk::result_ptr track = AudioEngine::instance()->currentTrack();
|
||||
if( track )
|
||||
if ( track )
|
||||
{
|
||||
metadataMap.insert( "mpris:trackid", QString( "/track/" ) + track->id().replace( "-", "" ) );
|
||||
metadataMap.insert( "mpris:length", track->duration() );
|
||||
@@ -256,9 +272,11 @@ MprisPlugin::metadata() const
|
||||
metadataMap.insert( "xesam:title", track->track() );
|
||||
|
||||
// Only return art if tempfile exists, and if its name contains the same "artist_album_tomahawk_cover.png"
|
||||
if( m_coverTempFile && m_coverTempFile->exists() &&
|
||||
m_coverTempFile->fileName().contains( track->artist()->name() + "_" + track->album()->name() + "_tomahawk_cover.png" ) )
|
||||
if ( m_coverTempFile && m_coverTempFile->exists() &&
|
||||
m_coverTempFile->fileName().contains( track->artist()->name() + "_" + track->album()->name() + "_tomahawk_cover.png" ) )
|
||||
{
|
||||
metadataMap.insert( "mpris:artUrl", QString( QUrl::fromLocalFile( QFileInfo( *m_coverTempFile ).absoluteFilePath() ).toEncoded() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to fetch the album cover
|
||||
@@ -280,18 +298,21 @@ MprisPlugin::metadata() const
|
||||
return metadataMap;
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
MprisPlugin::minimumRate() const
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
MprisPlugin::playbackStatus() const
|
||||
{
|
||||
return m_playbackStatus;
|
||||
}
|
||||
|
||||
|
||||
qlonglong
|
||||
MprisPlugin::position() const
|
||||
{
|
||||
@@ -299,18 +320,21 @@ MprisPlugin::position() const
|
||||
return (qlonglong) ( AudioEngine::instance()->currentTime() * 1000 );
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
MprisPlugin::rate() const
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::setRate( double value )
|
||||
{
|
||||
Q_UNUSED( value );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MprisPlugin::shuffle() const
|
||||
{
|
||||
@@ -320,6 +344,7 @@ MprisPlugin::shuffle() const
|
||||
return p->shuffled();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::setShuffle( bool value )
|
||||
{
|
||||
@@ -329,70 +354,76 @@ MprisPlugin::setShuffle( bool value )
|
||||
return p->setShuffled( value );
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
MprisPlugin::volume() const
|
||||
{
|
||||
return AudioEngine::instance()->volume();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::setVolume( double value )
|
||||
{
|
||||
AudioEngine::instance()->setVolume( value );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::Next()
|
||||
{
|
||||
AudioEngine::instance()->next();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::OpenUri( const QString &Uri )
|
||||
MprisPlugin::OpenUri( const QString& Uri )
|
||||
{
|
||||
if( Uri.contains( "tomahawk://" ) )
|
||||
if ( Uri.contains( "tomahawk://" ) )
|
||||
GlobalActionManager::instance()->parseTomahawkLink( Uri );
|
||||
else if( Uri.contains( "spotify:" ) )
|
||||
else if ( Uri.contains( "spotify:" ) )
|
||||
GlobalActionManager::instance()->openSpotifyLink( Uri );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::Pause()
|
||||
{
|
||||
AudioEngine::instance()->pause();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::Play()
|
||||
{
|
||||
AudioEngine::instance()->play();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::PlayPause()
|
||||
{
|
||||
AudioEngine::instance()->playPause();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::Previous()
|
||||
{
|
||||
AudioEngine::instance()->previous();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::Seek( qlonglong Offset )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if( !canSeek() )
|
||||
if ( !canSeek() )
|
||||
return;
|
||||
|
||||
qlonglong seekTime = position() + Offset;
|
||||
qDebug() << "seekTime: " << seekTime;
|
||||
if( seekTime < 0 )
|
||||
if ( seekTime < 0 )
|
||||
AudioEngine::instance()->seek( 0 );
|
||||
else if( seekTime > AudioEngine::instance()->currentTrackTotalTime()*1000 )
|
||||
else if ( seekTime > AudioEngine::instance()->currentTrackTotalTime()*1000 )
|
||||
Next();
|
||||
// seekTime is in microseconds, but we work internally in milliseconds
|
||||
else
|
||||
@@ -400,50 +431,46 @@ MprisPlugin::Seek( qlonglong Offset )
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::SetPosition( const QDBusObjectPath &TrackId, qlonglong Position )
|
||||
MprisPlugin::SetPosition( const QDBusObjectPath& TrackId, qlonglong Position )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if( !canSeek() )
|
||||
if ( !canSeek() )
|
||||
return;
|
||||
|
||||
qDebug() << "path: " << TrackId.path();
|
||||
qDebug() << "position: " << Position;
|
||||
|
||||
if( TrackId.path() != QString("/track/") + AudioEngine::instance()->currentTrack()->id().replace( "-", "" ) )
|
||||
if ( TrackId.path() != QString( "/track/" ) + AudioEngine::instance()->currentTrack()->id().replace( "-", "" ) )
|
||||
return;
|
||||
|
||||
if( ( Position < 0) || ( Position > AudioEngine::instance()->currentTrackTotalTime()*1000 ) )
|
||||
if ( ( Position < 0) || ( Position > AudioEngine::instance()->currentTrackTotalTime()*1000 ) )
|
||||
return;
|
||||
|
||||
qDebug() << "seeking to: " << Position/1000 << "ms";
|
||||
|
||||
AudioEngine::instance()->seek( (qint64) (Position / 1000 ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::Stop()
|
||||
{
|
||||
AudioEngine::instance()->stop();
|
||||
}
|
||||
|
||||
|
||||
// InfoPlugin Methods
|
||||
|
||||
void
|
||||
MprisPlugin::getInfo( Tomahawk::InfoSystem::InfoRequestData requestData )
|
||||
{
|
||||
Q_UNUSED( requestData );
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input )
|
||||
{
|
||||
Q_UNUSED( caller );
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
bool isPlayingInfo = false;
|
||||
|
||||
switch ( type )
|
||||
@@ -469,11 +496,11 @@ MprisPlugin::pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVar
|
||||
break;
|
||||
}
|
||||
|
||||
if( isPlayingInfo )
|
||||
notifyPropertyChanged( "org.mpris.MediaPlayer2.Player", "PlaybackStatus");
|
||||
|
||||
if ( isPlayingInfo )
|
||||
notifyPropertyChanged( "org.mpris.MediaPlayer2.Player", "PlaybackStatus" );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::stateChanged( AudioState newState, AudioState oldState )
|
||||
{
|
||||
@@ -481,12 +508,11 @@ MprisPlugin::stateChanged( AudioState newState, AudioState oldState )
|
||||
Q_UNUSED( oldState );
|
||||
}
|
||||
|
||||
|
||||
/** Audio state slots */
|
||||
void
|
||||
MprisPlugin::audioStarted( const QVariant &input )
|
||||
MprisPlugin::audioStarted( const QVariant& input )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if ( !input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
|
||||
return;
|
||||
|
||||
@@ -495,64 +521,55 @@ MprisPlugin::audioStarted( const QVariant &input )
|
||||
return;
|
||||
|
||||
m_playbackStatus = "Playing";
|
||||
notifyPropertyChanged( "org.mpris.MediaPlayer2.Player", "Metadata");
|
||||
|
||||
//hash["artist"];
|
||||
//hash["title"];
|
||||
//QString nowPlaying = "";
|
||||
//qDebug() << "nowPlaying: " << nowPlaying;
|
||||
notifyPropertyChanged( "org.mpris.MediaPlayer2.Player", "Metadata" );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::audioFinished( const QVariant &input )
|
||||
MprisPlugin::audioFinished( const QVariant& input )
|
||||
{
|
||||
Q_UNUSED( input );
|
||||
//qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::audioStopped()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
m_playbackStatus = "Stopped";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::audioPaused()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
m_playbackStatus = "Paused";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::audioResumed( const QVariant &input )
|
||||
MprisPlugin::audioResumed( const QVariant& input )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
audioStarted( input );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::onVolumeChanged( int volume )
|
||||
{
|
||||
Q_UNUSED( volume );
|
||||
notifyPropertyChanged( "org.mpris.MediaPlayer2.Player", "Volume");
|
||||
notifyPropertyChanged( "org.mpris.MediaPlayer2.Player", "Volume" );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::onPlaylistChanged( Tomahawk::playlistinterface_ptr playlist )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
disconnect( this, SLOT( onTrackCountChanged( unsigned int ) ) );
|
||||
qDebug() << "disconnected";
|
||||
if( !playlist.isNull() )
|
||||
qDebug() << "playlist not null";
|
||||
|
||||
if( !playlist.isNull() )
|
||||
if ( !playlist.isNull() )
|
||||
connect( playlist.data(), SIGNAL( trackCountChanged( unsigned int ) ),
|
||||
SLOT( onTrackCountChanged( unsigned int ) ) );
|
||||
|
||||
qDebug() << "connected new playlist";
|
||||
|
||||
// Notify relevant changes
|
||||
notifyPropertyChanged( "org.mpris.MediaPlayer2.Player", "LoopStatus" );
|
||||
notifyPropertyChanged( "org.mpris.MediaPlayer2.Player", "Shuffle" );
|
||||
@@ -560,6 +577,7 @@ MprisPlugin::onPlaylistChanged( Tomahawk::playlistinterface_ptr playlist )
|
||||
onTrackCountChanged( 0 );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::onTrackCountChanged( unsigned int tracks )
|
||||
{
|
||||
@@ -569,12 +587,14 @@ MprisPlugin::onTrackCountChanged( unsigned int tracks )
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
MprisPlugin::onSeeked( qint64 ms )
|
||||
{
|
||||
|
||||
void
|
||||
MprisPlugin::onSeeked( qint64 ms )
|
||||
{
|
||||
qlonglong us = (qlonglong) ( ms*1000 );
|
||||
emit Seeked( us );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
|
||||
@@ -603,7 +623,7 @@ MprisPlugin::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData,
|
||||
image.loadFromData( ba );
|
||||
|
||||
// Pull out request data for album+artist
|
||||
if( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
|
||||
if ( !requestData.input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() )
|
||||
{
|
||||
qDebug() << "Cannot convert metadata input to album cover retrieval";
|
||||
return;
|
||||
@@ -612,41 +632,33 @@ MprisPlugin::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData,
|
||||
Tomahawk::InfoSystem::InfoStringHash hash = requestData.input.value< Tomahawk::InfoSystem::InfoStringHash>();
|
||||
|
||||
// delete the old tempfile and make new one, to avoid caching of filename by mpris clients
|
||||
if( m_coverTempFile )
|
||||
if ( m_coverTempFile )
|
||||
{
|
||||
delete m_coverTempFile;
|
||||
m_coverTempFile = new QTemporaryFile( QDir::toNativeSeparators(
|
||||
QDir::tempPath() + "/" + hash["artist"] + "_" + hash["album"] + "_tomahawk_cover.png" ) );
|
||||
if( !m_coverTempFile->open() )
|
||||
m_coverTempFile = 0;
|
||||
}
|
||||
|
||||
if ( image.isNull() )
|
||||
return;
|
||||
|
||||
m_coverTempFile = new QTemporaryFile( QDir::toNativeSeparators( QDir::tempPath() + "/" + hash["artist"] + "_" + hash["album"] + "_tomahawk_cover.png" ) );
|
||||
if ( !m_coverTempFile->open() )
|
||||
{
|
||||
qDebug() << "WARNING: could not write temporary file for cover art!";
|
||||
}
|
||||
|
||||
// Finally, save the image to the new temp file
|
||||
//if( image.save( QFileInfo( *m_coverTempFile ).absoluteFilePath(), "PNG" ) )
|
||||
if( image.save( m_coverTempFile, "PNG") )
|
||||
if ( image.save( m_coverTempFile, "PNG" ) )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "Image saving successful, notifying";
|
||||
qDebug() << "Saving to: " << QFileInfo( *m_coverTempFile ).absoluteFilePath();
|
||||
qDebug() << "Saving cover image to:" << QFileInfo( *m_coverTempFile ).absoluteFilePath();
|
||||
m_coverTempFile->close();
|
||||
notifyPropertyChanged( "org.mpris.MediaPlayer2.Player", "Metadata" );
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << " failed to save image!";
|
||||
tDebug() << Q_FUNC_INFO << "failed to save cover image!";
|
||||
m_coverTempFile->close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
if( m_coverTempFile->open() )
|
||||
{
|
||||
QTextStream out( m_coverTempFile );
|
||||
out << ba;
|
||||
m_coverTempFile->close();
|
||||
notifyPropertyChanged( "org.mpris.MediaPlayer2.Player", "Metadata" );
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -657,14 +669,14 @@ MprisPlugin::infoSystemFinished( QString target )
|
||||
Q_UNUSED( target );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MprisPlugin::notifyPropertyChanged( const QString& interface,
|
||||
const QString& propertyName )
|
||||
MprisPlugin::notifyPropertyChanged( const QString& interface, const QString& propertyName )
|
||||
{
|
||||
QDBusMessage signal = QDBusMessage::createSignal(
|
||||
"/org/mpris/MediaPlayer2",
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged");
|
||||
"PropertiesChanged" );
|
||||
signal << interface;
|
||||
QVariantMap changedProps;
|
||||
changedProps.insert(propertyName, property(propertyName.toAscii()));
|
||||
|
@@ -87,7 +87,7 @@ public:
|
||||
|
||||
Q_PROPERTY( QString LoopStatus READ loopStatus WRITE setLoopStatus )
|
||||
QString loopStatus() const;
|
||||
void setLoopStatus( const QString &value );
|
||||
void setLoopStatus( const QString& value );
|
||||
|
||||
Q_PROPERTY( double MaximumRate READ maximumRate )
|
||||
double maximumRate() const;
|
||||
@@ -129,16 +129,15 @@ public slots:
|
||||
|
||||
// org.mpris.MediaPlayer2.Player
|
||||
void Next();
|
||||
void OpenUri( const QString &Uri );
|
||||
void OpenUri( const QString& Uri );
|
||||
void Pause();
|
||||
void Play();
|
||||
void PlayPause();
|
||||
void Previous();
|
||||
void Seek( qlonglong Offset );
|
||||
void SetPosition( const QDBusObjectPath &TrackId, qlonglong Position );
|
||||
void SetPosition( const QDBusObjectPath& TrackId, qlonglong Position );
|
||||
void Stop();
|
||||
|
||||
|
||||
protected slots:
|
||||
void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input );
|
||||
@@ -160,16 +159,16 @@ private:
|
||||
// Get Info
|
||||
|
||||
// Push Info
|
||||
void audioStarted( const QVariant &input );
|
||||
void audioFinished( const QVariant &input );
|
||||
void audioStarted( const QVariant& input );
|
||||
void audioFinished( const QVariant& input );
|
||||
void audioStopped();
|
||||
void audioPaused();
|
||||
void audioResumed( const QVariant &input );
|
||||
void audioResumed( const QVariant& input );
|
||||
|
||||
// DBus
|
||||
void notifyPropertyChanged( const QString& interface, const QString& propertyName );
|
||||
QString m_playbackStatus;
|
||||
QTemporaryFile *m_coverTempFile;
|
||||
QTemporaryFile* m_coverTempFile;
|
||||
};
|
||||
|
||||
};
|
||||
|
56
src/libtomahawk/jobview/ErrorStatusMessage.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/* === 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 "ErrorStatusMessage.h"
|
||||
|
||||
#include "utils/tomahawkutils.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
QPixmap* ErrorStatusMessage::s_pixmap = 0;
|
||||
|
||||
ErrorStatusMessage::ErrorStatusMessage( const QString& message, int timeoutSecs )
|
||||
: JobStatusItem()
|
||||
, m_message( message )
|
||||
{
|
||||
m_timer = new QTimer( this );
|
||||
m_timer->setInterval( timeoutSecs * 1000 );
|
||||
m_timer->setSingleShot( true );
|
||||
|
||||
connect( m_timer, SIGNAL( timeout() ), this, SIGNAL( finished() ) );
|
||||
|
||||
if ( !s_pixmap )
|
||||
s_pixmap = new QPixmap( RESPATH "images/process-stop.png" );
|
||||
|
||||
m_timer->start();
|
||||
}
|
||||
|
||||
|
||||
QPixmap
|
||||
ErrorStatusMessage::icon() const
|
||||
{
|
||||
Q_ASSERT( s_pixmap );
|
||||
return *s_pixmap;
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
ErrorStatusMessage::mainText() const
|
||||
{
|
||||
return m_message;
|
||||
}
|
48
src/libtomahawk/jobview/ErrorStatusMessage.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* === 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 ERRORSTATUSMESSAGE_H
|
||||
#define ERRORSTATUSMESSAGE_H
|
||||
|
||||
#include "JobStatusItem.h"
|
||||
#include "dllmacro.h"
|
||||
|
||||
class QTimer;
|
||||
class QPixmap;
|
||||
|
||||
class DLLEXPORT ErrorStatusMessage : public JobStatusItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ErrorStatusMessage( const QString& errorMessage, int defaultTimeoutSecs = 8 );
|
||||
|
||||
QString type() const { return "errormessage"; }
|
||||
QString rightColumnText() const { return QString(); }
|
||||
|
||||
QPixmap icon() const;
|
||||
QString mainText() const;
|
||||
|
||||
bool allowMultiLine() const { return true; }
|
||||
private:
|
||||
QString m_message;
|
||||
QTimer* m_timer;
|
||||
|
||||
static QPixmap* s_pixmap;
|
||||
};
|
||||
|
||||
#endif // ERRORSTATUSMESSAGE_H
|
47
src/libtomahawk/jobview/IndexingJobItem.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "IndexingJobItem.h"
|
||||
|
||||
#include "utils/tomahawkutils.h"
|
||||
|
||||
static QPixmap* s_indexIcon = 0;
|
||||
|
||||
|
||||
QString
|
||||
IndexingJobItem::mainText() const
|
||||
{
|
||||
return tr( "Indexing database" );
|
||||
}
|
||||
|
||||
QPixmap
|
||||
IndexingJobItem::icon() const
|
||||
{
|
||||
if ( s_indexIcon == 0 )
|
||||
s_indexIcon = new QPixmap( RESPATH "images/view-refresh.png" );
|
||||
|
||||
return *s_indexIcon;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void IndexingJobItem::done()
|
||||
{
|
||||
emit finished();
|
||||
}
|
||||
|
39
src/libtomahawk/jobview/IndexingJobItem.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INDEXINGJOBITEM_H
|
||||
#define INDEXINGJOBITEM_H
|
||||
|
||||
#include <jobview/JobStatusItem.h>
|
||||
|
||||
|
||||
class IndexingJobItem : public JobStatusItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IndexingJobItem() {}
|
||||
|
||||
void done();
|
||||
|
||||
virtual QString rightColumnText() const { return QString(); }
|
||||
virtual QString mainText() const;
|
||||
virtual QPixmap icon() const;
|
||||
virtual QString type() const { return "indexerjob"; }
|
||||
};
|
||||
|
||||
#endif // INDEXINGJOBITEM_H
|
@@ -23,14 +23,16 @@
|
||||
|
||||
#include <QPainter>
|
||||
#include <QApplication>
|
||||
#include <QListView>
|
||||
|
||||
#define ROW_HEIGHT 20
|
||||
#define ICON_PADDING 1
|
||||
#define PADDING 2
|
||||
JobStatusDelegate::JobStatusDelegate( QObject* parent )
|
||||
: QStyledItemDelegate ( parent )
|
||||
, m_parentView( qobject_cast< QListView* >( parent ) )
|
||||
{
|
||||
|
||||
Q_ASSERT( m_parentView );
|
||||
}
|
||||
|
||||
JobStatusDelegate::~JobStatusDelegate()
|
||||
@@ -45,6 +47,7 @@ JobStatusDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
QStyleOptionViewItemV4 opt = option;
|
||||
initStyleOption( &opt, index );
|
||||
QFontMetrics fm( opt.font );
|
||||
const bool allowMultiLine = index.data( JobStatusModel::AllowMultiLineRole ).toBool();
|
||||
|
||||
opt.state &= ~QStyle::State_MouseOver;
|
||||
QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget );
|
||||
@@ -52,7 +55,9 @@ JobStatusDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
// painter->drawLine( opt.rect.topLeft(), opt.rect.topRight() );
|
||||
|
||||
painter->setRenderHint( QPainter::Antialiasing );
|
||||
const 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 >();
|
||||
p = p.scaledToHeight( iconRect.height(), Qt::SmoothTransformation );
|
||||
painter->drawPixmap( iconRect, p );
|
||||
@@ -71,15 +76,34 @@ JobStatusDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
|
||||
const int mainW = rightEdge - 3*PADDING - iconRect.right();
|
||||
QString mainText = index.data( Qt::DisplayRole ).toString();
|
||||
mainText = fm.elidedText( mainText, Qt::ElideRight, mainW );
|
||||
painter->drawText( QRect( iconRect.right() + 2*PADDING, PADDING + opt.rect.y(), mainW, opt.rect.height() - 2*PADDING ), Qt::AlignLeft | Qt::AlignVCenter, mainText );
|
||||
QTextOption to( Qt::AlignLeft | Qt::AlignVCenter );
|
||||
if ( !allowMultiLine )
|
||||
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 );
|
||||
}
|
||||
|
||||
QSize
|
||||
JobStatusDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
// return QStyledItemDelegate::sizeHint( option, index );
|
||||
const int w = QStyledItemDelegate::sizeHint ( option, index ).width();
|
||||
return QSize( w, ROW_HEIGHT );
|
||||
const bool allowMultiLine = index.data( JobStatusModel::AllowMultiLineRole ).toBool();
|
||||
|
||||
if ( !allowMultiLine )
|
||||
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), ROW_HEIGHT );
|
||||
else if ( m_cachedMultiLineHeights.contains( index ) )
|
||||
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), m_cachedMultiLineHeights[ index ] );
|
||||
|
||||
// Don't elide, but stretch across as many rows as required
|
||||
QStyleOptionViewItemV4 opt = option;
|
||||
initStyleOption( &opt, index );
|
||||
|
||||
const QString text = index.data( Qt::DisplayRole ).toString();
|
||||
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 );
|
||||
|
||||
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), rect.height() + 4*PADDING );
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
class QPainter;
|
||||
class QListView;
|
||||
|
||||
class JobStatusDelegate : public QStyledItemDelegate
|
||||
{
|
||||
@@ -33,6 +34,10 @@ public:
|
||||
|
||||
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
|
||||
private:
|
||||
mutable QHash< QPersistentModelIndex, int > m_cachedMultiLineHeights;
|
||||
QListView* m_parentView;
|
||||
};
|
||||
|
||||
#endif // JOBSTATUSDELEGATE_H
|
||||
|
@@ -53,6 +53,7 @@ public:
|
||||
* and a count will be shown instead.
|
||||
*/
|
||||
virtual bool collapseItem() const { return false; }
|
||||
virtual bool allowMultiLine() const { return false; }
|
||||
|
||||
signals:
|
||||
/// Ask for an update
|
||||
|
@@ -100,6 +100,8 @@ JobStatusModel::data( const QModelIndex& index, int role ) const
|
||||
else
|
||||
return item->rightColumnText();
|
||||
}
|
||||
case AllowMultiLineRole:
|
||||
return item->allowMultiLine();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
|
@@ -31,7 +31,8 @@ public:
|
||||
enum JobRoles {
|
||||
// DecorationRole is icon
|
||||
// DisplayRole is main col
|
||||
RightColumnRole = Qt::UserRole + 1
|
||||
RightColumnRole = Qt::UserRole + 1,
|
||||
AllowMultiLineRole = Qt::UserRole + 2
|
||||
};
|
||||
|
||||
explicit JobStatusModel( QObject* parent = 0 );
|
||||
|
@@ -40,6 +40,7 @@ JobStatusView* JobStatusView::s_instance = 0;
|
||||
JobStatusView::JobStatusView( AnimatedSplitter* parent )
|
||||
: AnimatedWidget( parent )
|
||||
, m_parent( parent )
|
||||
, m_cachedHeight( -1 )
|
||||
{
|
||||
s_instance = this;
|
||||
|
||||
@@ -56,9 +57,7 @@ JobStatusView::JobStatusView( AnimatedSplitter* parent )
|
||||
|
||||
m_view->setFrameShape( QFrame::NoFrame );
|
||||
m_view->setAttribute( Qt::WA_MacShowFocusRect, 0 );
|
||||
|
||||
// new QTreeWidgetItem( m_tree );
|
||||
m_view->setUniformItemSizes( true );
|
||||
m_view->setUniformItemSizes( false );
|
||||
|
||||
#ifndef Q_WS_WIN
|
||||
QFont f = font();
|
||||
@@ -86,12 +85,14 @@ JobStatusView::setModel( JobStatusModel* m )
|
||||
|
||||
connect( m_view->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( checkCount() ) );
|
||||
connect( m_view->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( checkCount() ) );
|
||||
connect( m_view->model(), SIGNAL( modelReset() ), this, SLOT( checkCount() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JobStatusView::checkCount()
|
||||
{
|
||||
m_cachedHeight = -1;
|
||||
if ( m_view->model()->rowCount() == 0 && !isHidden() )
|
||||
emit hideWidget();
|
||||
else
|
||||
@@ -102,15 +103,21 @@ JobStatusView::checkCount()
|
||||
QSize
|
||||
JobStatusView::sizeHint() const
|
||||
{
|
||||
if ( m_cachedHeight >= 0 )
|
||||
return QSize( 0, m_cachedHeight );
|
||||
|
||||
unsigned int y = 0;
|
||||
// y += m_tree->header()->height();
|
||||
y += m_view->contentsMargins().top() + m_view->contentsMargins().bottom();
|
||||
|
||||
if ( m_view->model()->rowCount() )
|
||||
{
|
||||
unsigned int rowheight = m_view->sizeHintForRow( 0 );
|
||||
y += rowheight * m_view->model()->rowCount() + 2;
|
||||
for ( int i = 0; i < m_view->model()->rowCount(); i++ )
|
||||
{
|
||||
y += m_view->sizeHintForRow( i );
|
||||
}
|
||||
y += 2; // some padding
|
||||
}
|
||||
|
||||
m_cachedHeight = y;
|
||||
return QSize( 0, y );
|
||||
}
|
||||
|
@@ -56,6 +56,7 @@ private:
|
||||
QListView* m_view;
|
||||
JobStatusModel* m_model;
|
||||
AnimatedSplitter* m_parent;
|
||||
mutable int m_cachedHeight;
|
||||
|
||||
static JobStatusView* s_instance;
|
||||
};
|
||||
|
@@ -43,7 +43,7 @@ PortFwdThread::~PortFwdThread()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "waiting for event loop to finish...";
|
||||
quit();
|
||||
wait( 1000 );
|
||||
wait( 6000 );
|
||||
|
||||
delete m_portfwd;
|
||||
}
|
||||
|
@@ -61,6 +61,7 @@ Pipeline::Pipeline( QObject* parent )
|
||||
|
||||
Pipeline::~Pipeline()
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
m_running = false;
|
||||
|
||||
// stop script resolvers
|
||||
@@ -412,10 +413,11 @@ Pipeline::shunt( const query_ptr& q )
|
||||
r->resolve( q );
|
||||
emit resolving( q );
|
||||
|
||||
m_qidsTimeout.insert( q->id(), true );
|
||||
|
||||
if ( r->timeout() > 0 )
|
||||
{
|
||||
m_qidsTimeout.insert( q->id(), true );
|
||||
new FuncTimeout( r->timeout(), boost::bind( &Pipeline::timeoutShunt, this, q ), this );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -48,6 +48,8 @@ public:
|
||||
explicit Pipeline( QObject* parent = 0 );
|
||||
virtual ~Pipeline();
|
||||
|
||||
bool isRunning() const { return m_running; }
|
||||
|
||||
unsigned int pendingQueryCount() const { return m_queries_pending.count(); }
|
||||
unsigned int activeQueryCount() const { return m_qidsState.count(); }
|
||||
|
||||
|
@@ -71,7 +71,11 @@ XspfUpdater::playlistLoaded()
|
||||
foreach ( const plentry_ptr ple, playlist()->entries() )
|
||||
tracks << ple->query();
|
||||
|
||||
QList< query_ptr > mergedTracks = TomahawkUtils::mergePlaylistChanges( tracks, loader->entries() );
|
||||
bool changed = false;
|
||||
QList< query_ptr > mergedTracks = TomahawkUtils::mergePlaylistChanges( tracks, loader->entries(), changed );
|
||||
|
||||
if ( !changed )
|
||||
return;
|
||||
|
||||
QList<Tomahawk::plentry_ptr> el = playlist()->entriesFromQueries( mergedTracks, true );
|
||||
playlist()->createNewRevision( uuid(), playlist()->currentrevision(), el );
|
||||
|
@@ -40,7 +40,6 @@ AlbumItemDelegate::AlbumItemDelegate( QAbstractItemView* parent, AlbumProxyModel
|
||||
, m_view( parent )
|
||||
, m_model( proxy )
|
||||
{
|
||||
m_defaultCover = QPixmap( RESPATH "images/no-album-art-placeholder.png" );
|
||||
}
|
||||
|
||||
|
||||
@@ -89,21 +88,19 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
painter->drawLine( shadowRect.bottomLeft() + QPoint( 0, 4 ), shadowRect.bottomRight() + QPoint( 0, 4 ) );
|
||||
}
|
||||
|
||||
QRect r = option.rect.adjusted( 6, 5, -6, -41 );
|
||||
QPixmap cover;
|
||||
if ( !item->album().isNull() )
|
||||
{
|
||||
cover.loadFromData( item->album()->cover() );
|
||||
cover = item->album()->cover( r.size() );
|
||||
if ( cover.isNull() )
|
||||
cover = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::CoverInCase, r.size() );
|
||||
}
|
||||
else if ( !item->artist().isNull() )
|
||||
{
|
||||
cover.loadFromData( item->artist()->cover() );
|
||||
cover = item->artist()->cover( r.size() );
|
||||
}
|
||||
|
||||
if ( cover.isNull() )
|
||||
cover = m_defaultCover;
|
||||
|
||||
QRect r = option.rect.adjusted( 6, 5, -6, -41 );
|
||||
|
||||
if ( option.state & QStyle::State_Selected )
|
||||
{
|
||||
#if defined(Q_WS_MAC) || defined(Q_WS_WIN)
|
||||
@@ -123,17 +120,7 @@ AlbumItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
#endif
|
||||
}
|
||||
|
||||
QPixmap scover;
|
||||
if ( m_cache.contains( cover.cacheKey() ) )
|
||||
{
|
||||
scover = m_cache.value( cover.cacheKey() );
|
||||
}
|
||||
else
|
||||
{
|
||||
scover = cover.scaled( r.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_cache.insert( cover.cacheKey(), scover );
|
||||
}
|
||||
painter->drawPixmap( r, scover );
|
||||
painter->drawPixmap( r, cover );
|
||||
|
||||
painter->setPen( opt.palette.color( QPalette::Text ) );
|
||||
QTextOption to;
|
||||
|
@@ -49,12 +49,10 @@ private:
|
||||
QAbstractItemView* m_view;
|
||||
AlbumProxyModel* m_model;
|
||||
|
||||
mutable QHash< qint64, QPixmap > m_cache;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_artistNameRects;
|
||||
QPersistentModelIndex m_hoveringOver;
|
||||
|
||||
QPixmap m_shadowPixmap;
|
||||
QPixmap m_defaultCover;
|
||||
};
|
||||
|
||||
#endif // ALBUMITEMDELEGATE_H
|
||||
|
@@ -304,7 +304,18 @@ AlbumModel::addAlbums( const QList<Tomahawk::album_ptr>& albums )
|
||||
if ( m_overwriteOnAdd )
|
||||
clear();
|
||||
|
||||
if ( !albums.count() )
|
||||
QList<Tomahawk::album_ptr> trimmedAlbums;
|
||||
foreach ( const album_ptr& album, albums )
|
||||
{
|
||||
if ( !album.isNull() && album->name().length() )
|
||||
{
|
||||
if ( findItem( album ) || trimmedAlbums.contains( album ) )
|
||||
continue;
|
||||
trimmedAlbums << album;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !trimmedAlbums.count() )
|
||||
{
|
||||
emit itemCountChanged( rowCount( QModelIndex() ) );
|
||||
return;
|
||||
@@ -313,12 +324,12 @@ AlbumModel::addAlbums( const QList<Tomahawk::album_ptr>& albums )
|
||||
int c = rowCount( QModelIndex() );
|
||||
QPair< int, int > crows;
|
||||
crows.first = c;
|
||||
crows.second = c + albums.count() - 1;
|
||||
crows.second = c + trimmedAlbums.count() - 1;
|
||||
|
||||
emit beginInsertRows( QModelIndex(), crows.first, crows.second );
|
||||
|
||||
AlbumItem* albumitem;
|
||||
foreach( const album_ptr& album, albums )
|
||||
foreach( const album_ptr& album, trimmedAlbums )
|
||||
{
|
||||
albumitem = new AlbumItem( album, m_rootItem );
|
||||
albumitem->index = createIndex( m_rootItem->children.count() - 1, 0, albumitem );
|
||||
@@ -339,7 +350,18 @@ AlbumModel::addArtists( const QList<Tomahawk::artist_ptr>& artists )
|
||||
if ( m_overwriteOnAdd )
|
||||
clear();
|
||||
|
||||
if ( !artists.count() )
|
||||
QList<Tomahawk::artist_ptr> trimmedArtists;
|
||||
foreach ( const artist_ptr& artist, artists )
|
||||
{
|
||||
if ( !artist.isNull() && artist->name().length() )
|
||||
{
|
||||
if ( findItem( artist ) || trimmedArtists.contains( artist ) )
|
||||
continue;
|
||||
trimmedArtists << artist;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !trimmedArtists.count() )
|
||||
{
|
||||
emit itemCountChanged( rowCount( QModelIndex() ) );
|
||||
return;
|
||||
@@ -348,12 +370,12 @@ AlbumModel::addArtists( const QList<Tomahawk::artist_ptr>& artists )
|
||||
int c = rowCount( QModelIndex() );
|
||||
QPair< int, int > crows;
|
||||
crows.first = c;
|
||||
crows.second = c + artists.count() - 1;
|
||||
crows.second = c + trimmedArtists.count() - 1;
|
||||
|
||||
emit beginInsertRows( QModelIndex(), crows.first, crows.second );
|
||||
|
||||
AlbumItem* albumitem;
|
||||
foreach( const artist_ptr& artist, artists )
|
||||
foreach ( const artist_ptr& artist, trimmedArtists )
|
||||
{
|
||||
albumitem = new AlbumItem( artist, m_rootItem );
|
||||
albumitem->index = createIndex( m_rootItem->children.count() - 1, 0, albumitem );
|
||||
@@ -396,3 +418,35 @@ AlbumModel::onDataChanged()
|
||||
AlbumItem* p = (AlbumItem*)sender();
|
||||
emit dataChanged( p->index, p->index.sibling( p->index.row(), columnCount( QModelIndex() ) - 1 ) );
|
||||
}
|
||||
|
||||
|
||||
AlbumItem*
|
||||
AlbumModel::findItem( const artist_ptr& artist ) const
|
||||
{
|
||||
for ( int i = 0; i < rowCount( QModelIndex() ); i++ )
|
||||
{
|
||||
AlbumItem* item = itemFromIndex( index( i, 0, QModelIndex() ) );
|
||||
if ( !item->artist().isNull() && item->artist() == artist )
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
AlbumItem*
|
||||
AlbumModel::findItem( const album_ptr& album ) const
|
||||
{
|
||||
for ( int i = 0; i < rowCount( QModelIndex() ); i++ )
|
||||
{
|
||||
AlbumItem* item = itemFromIndex( index( i, 0, QModelIndex() ) );
|
||||
if ( !item->album().isNull() && item->album() == album )
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -71,6 +71,9 @@ public:
|
||||
virtual void setTitle( const QString& title ) { m_title = title; }
|
||||
virtual void setDescription( const QString& description ) { m_description = description; }
|
||||
|
||||
AlbumItem* findItem( const Tomahawk::artist_ptr& artist ) const;
|
||||
AlbumItem* findItem( const Tomahawk::album_ptr& album ) const;
|
||||
|
||||
AlbumItem* itemFromIndex( const QModelIndex& index ) const
|
||||
{
|
||||
if ( index.isValid() )
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <qmath.h>
|
||||
|
||||
#include "audio/audioengine.h"
|
||||
#include "context/ContextWidget.h"
|
||||
#include "tomahawksettings.h"
|
||||
#include "artist.h"
|
||||
#include "albumitem.h"
|
||||
@@ -113,6 +114,20 @@ AlbumView::setAlbumModel( AlbumModel* model )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AlbumView::currentChanged( const QModelIndex& current, const QModelIndex& previous )
|
||||
{
|
||||
QListView::currentChanged( current, previous );
|
||||
|
||||
AlbumItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( current ) );
|
||||
if ( item )
|
||||
{
|
||||
if ( !item->album().isNull() )
|
||||
ViewManager::instance()->context()->setAlbum( item->album() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AlbumView::onItemActivated( const QModelIndex& index )
|
||||
{
|
||||
|
@@ -71,6 +71,9 @@ protected:
|
||||
void paintEvent( QPaintEvent* event );
|
||||
void resizeEvent( QResizeEvent* event );
|
||||
|
||||
protected slots:
|
||||
virtual void currentChanged( const QModelIndex& current, const QModelIndex& previous );
|
||||
|
||||
private slots:
|
||||
void onItemCountChanged( unsigned int items );
|
||||
|
||||
|
@@ -80,6 +80,11 @@ ArtistView::ArtistView( QWidget* parent )
|
||||
setFont( f );
|
||||
#endif
|
||||
|
||||
m_timer.setInterval( SCROLL_TIMEOUT );
|
||||
connect( verticalScrollBar(), SIGNAL( rangeChanged( int, int ) ), SLOT( onViewChanged() ) );
|
||||
connect( verticalScrollBar(), SIGNAL( valueChanged( int ) ), SLOT( onViewChanged() ) );
|
||||
connect( &m_timer, SIGNAL( timeout() ), SLOT( onScrollTimeout() ) );
|
||||
|
||||
connect( this, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) );
|
||||
connect( this, SIGNAL( customContextMenuRequested( const QPoint& ) ), SLOT( onCustomContextMenu( const QPoint& ) ) );
|
||||
connect( m_contextMenu, SIGNAL( triggered( int ) ), SLOT( onMenuTriggered( int ) ) );
|
||||
@@ -128,7 +133,8 @@ ArtistView::setTreeModel( TreeModel* model )
|
||||
connect( m_proxyModel, SIGNAL( filteringFinished() ), m_loadingSpinner, SLOT( fadeOut() ) );
|
||||
|
||||
connect( m_model, SIGNAL( itemCountChanged( unsigned int ) ), SLOT( onItemCountChanged( unsigned int ) ) );
|
||||
connect( m_proxyModel, SIGNAL( filterChanged( QString ) ), SLOT( onFilterChanged( QString ) ) );
|
||||
connect( m_proxyModel, SIGNAL( filteringFinished() ), SLOT( onFilterChangeFinished() ) );
|
||||
connect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ) );
|
||||
|
||||
guid(); // this will set the guid on the header
|
||||
|
||||
@@ -145,6 +151,44 @@ ArtistView::setTreeModel( TreeModel* model )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ArtistView::onViewChanged()
|
||||
{
|
||||
if ( m_timer.isActive() )
|
||||
m_timer.stop();
|
||||
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ArtistView::onScrollTimeout()
|
||||
{
|
||||
if ( m_timer.isActive() )
|
||||
m_timer.stop();
|
||||
|
||||
QModelIndex left = indexAt( viewport()->rect().topLeft() );
|
||||
while ( left.isValid() && left.parent().isValid() )
|
||||
left = left.parent();
|
||||
|
||||
QModelIndex right = indexAt( viewport()->rect().bottomLeft() );
|
||||
while ( right.isValid() && right.parent().isValid() )
|
||||
right = right.parent();
|
||||
|
||||
int max = m_proxyModel->playlistInterface()->trackCount();
|
||||
if ( right.isValid() )
|
||||
max = right.row() + 1;
|
||||
|
||||
if ( !max )
|
||||
return;
|
||||
|
||||
for ( int i = left.row(); i < max; i++ )
|
||||
{
|
||||
m_model->getCover( m_proxyModel->mapToSource( m_proxyModel->index( i, 0 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ArtistView::currentChanged( const QModelIndex& current, const QModelIndex& previous )
|
||||
{
|
||||
@@ -236,7 +280,7 @@ ArtistView::onItemCountChanged( unsigned int items )
|
||||
|
||||
|
||||
void
|
||||
ArtistView::onFilterChanged( const QString& )
|
||||
ArtistView::onFilterChangeFinished()
|
||||
{
|
||||
if ( selectedIndexes().count() )
|
||||
scrollTo( selectedIndexes().at( 0 ), QAbstractItemView::PositionAtCenter );
|
||||
|
@@ -93,8 +93,10 @@ protected slots:
|
||||
|
||||
private slots:
|
||||
void onItemCountChanged( unsigned int items );
|
||||
void onFilterChanged( const QString& filter );
|
||||
void onFilterChangeFinished();
|
||||
void onFilteringStarted();
|
||||
void onViewChanged();
|
||||
void onScrollTimeout();
|
||||
|
||||
void onCustomContextMenu( const QPoint& pos );
|
||||
void onMenuTriggered( int action );
|
||||
@@ -113,6 +115,7 @@ private:
|
||||
Tomahawk::ContextMenu* m_contextMenu;
|
||||
|
||||
bool m_showModes;
|
||||
QTimer m_timer;
|
||||
mutable QString m_guid;
|
||||
};
|
||||
|
||||
|
@@ -42,7 +42,7 @@ CustomPlaylistView::CustomPlaylistView( CustomPlaylistView::PlaylistType type, c
|
||||
|
||||
if ( m_type == SourceLovedTracks )
|
||||
connect( m_source.data(), SIGNAL( socialAttributesChanged( QString ) ), this, SLOT( socialAttributesChanged( QString ) ) );
|
||||
else if ( m_type == AllLovedTracks )
|
||||
else if ( m_type == TopLovedTracks )
|
||||
{
|
||||
connect( SourceList::instance()->getLocal().data(), SIGNAL( socialAttributesChanged( QString ) ), this, SLOT( socialAttributesChanged( QString ) ) );
|
||||
foreach ( const source_ptr& s, SourceList::instance()->sources( true ) )
|
||||
@@ -86,12 +86,12 @@ CustomPlaylistView::generateTracks()
|
||||
"GROUP BY track.id "
|
||||
"ORDER BY counter DESC, social_attributes.timestamp DESC " ).arg( m_source->isLocal() ? "IS NULL" : QString( "= %1" ).arg( m_source->id() ) );
|
||||
break;
|
||||
case AllLovedTracks:
|
||||
case TopLovedTracks:
|
||||
sql = QString( "SELECT track.name, artist.name, source, COUNT(*) as counter "
|
||||
"FROM social_attributes, track, artist "
|
||||
"WHERE social_attributes.id = track.id AND artist.id = track.artist AND social_attributes.k = 'Love' AND social_attributes.v = 'true'"
|
||||
"WHERE social_attributes.id = track.id AND artist.id = track.artist AND social_attributes.k = 'Love' AND social_attributes.v = 'true' "
|
||||
"GROUP BY track.id "
|
||||
"ORDER BY counter DESC, social_attributes.timestamp DESC " );
|
||||
"ORDER BY counter DESC, social_attributes.timestamp DESC LIMIT 0, 50" );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,11 @@ CustomPlaylistView::generateTracks()
|
||||
void
|
||||
CustomPlaylistView::tracksGenerated( QList< query_ptr > tracks )
|
||||
{
|
||||
QList< query_ptr > newTracks = TomahawkUtils::mergePlaylistChanges( m_model->queries(), tracks );
|
||||
bool changed = false;
|
||||
QList< query_ptr > newTracks = TomahawkUtils::mergePlaylistChanges( m_model->queries(), tracks, changed);
|
||||
|
||||
if ( !changed )
|
||||
return;
|
||||
|
||||
m_model->clear();
|
||||
m_model->append( newTracks );
|
||||
|
@@ -33,7 +33,7 @@ class DLLEXPORT CustomPlaylistView : public PlaylistView
|
||||
public:
|
||||
enum PlaylistType {
|
||||
SourceLovedTracks,
|
||||
AllLovedTracks
|
||||
TopLovedTracks
|
||||
};
|
||||
|
||||
explicit CustomPlaylistView( PlaylistType type, const source_ptr& s, QWidget* parent = 0 );
|
||||
|
@@ -54,19 +54,22 @@ DynamicModel::loadPlaylist( const Tomahawk::dynplaylist_ptr& playlist, bool load
|
||||
{
|
||||
Q_UNUSED( loadEntries );
|
||||
|
||||
if( !m_playlist.isNull() ) {
|
||||
if ( !m_playlist.isNull() )
|
||||
{
|
||||
disconnect( m_playlist->generator().data(), SIGNAL( nextTrackGenerated( Tomahawk::query_ptr ) ), this, SLOT( newTrackGenerated( Tomahawk::query_ptr ) ) );
|
||||
}
|
||||
const int oldCount = rowCount( QModelIndex() );
|
||||
|
||||
m_playlist = playlist;
|
||||
|
||||
m_deduper.clear();
|
||||
if( m_playlist->mode() == OnDemand )
|
||||
if ( m_playlist->mode() == OnDemand )
|
||||
setFilterUnresolvable( true );
|
||||
|
||||
connect( m_playlist->generator().data(), SIGNAL( nextTrackGenerated( Tomahawk::query_ptr ) ), this, SLOT( newTrackGenerated( Tomahawk::query_ptr ) ) );
|
||||
PlaylistModel::loadPlaylist( m_playlist, m_playlist->mode() == Static );
|
||||
|
||||
if( m_playlist->mode() == OnDemand )
|
||||
if ( m_playlist->mode() == OnDemand && oldCount != rowCount( QModelIndex() ) )
|
||||
emit trackCountChanged( rowCount( QModelIndex() ) );
|
||||
}
|
||||
|
||||
@@ -74,7 +77,7 @@ DynamicModel::loadPlaylist( const Tomahawk::dynplaylist_ptr& playlist, bool load
|
||||
QString
|
||||
DynamicModel::description() const
|
||||
{
|
||||
if( !m_playlist.isNull() && !m_playlist->generator().isNull() )
|
||||
if ( !m_playlist.isNull() && !m_playlist->generator().isNull() )
|
||||
return m_playlist->generator()->sentenceSummary();
|
||||
else
|
||||
return QString();
|
||||
@@ -95,7 +98,8 @@ DynamicModel::startOnDemand()
|
||||
void
|
||||
DynamicModel::newTrackGenerated( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
if( m_onDemandRunning ) {
|
||||
if ( m_onDemandRunning )
|
||||
{
|
||||
bool isDuplicate = false;
|
||||
for ( int i = 0; i < m_deduper.size(); i++ )
|
||||
{
|
||||
@@ -125,7 +129,7 @@ void
|
||||
DynamicModel::stopOnDemand( bool stopPlaying )
|
||||
{
|
||||
m_onDemandRunning = false;
|
||||
if( stopPlaying )
|
||||
if ( stopPlaying )
|
||||
AudioEngine::instance()->stop();
|
||||
|
||||
disconnect( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), this, SLOT( newTrackLoading() ) );
|
||||
@@ -135,7 +139,7 @@ DynamicModel::stopOnDemand( bool stopPlaying )
|
||||
void
|
||||
DynamicModel::changeStation()
|
||||
{
|
||||
if( m_onDemandRunning )
|
||||
if ( m_onDemandRunning )
|
||||
m_changeOnNext = true;
|
||||
else // if we're not running, just start
|
||||
m_playlist->generator()->startOnDemand();
|
||||
@@ -171,7 +175,7 @@ DynamicModel::trackResolveFinished( bool success )
|
||||
{
|
||||
qDebug() << "Got successful resolved track:" << q->track() << q->artist() << m_lastResolvedRow << m_currentAttempts;
|
||||
|
||||
if( m_currentAttempts > 0 ) {
|
||||
if ( m_currentAttempts > 0 ) {
|
||||
qDebug() << "EMITTING AN ASK FOR COLLAPSE:" << m_lastResolvedRow << m_currentAttempts;
|
||||
emit collapseFromTo( m_lastResolvedRow, m_currentAttempts );
|
||||
}
|
||||
@@ -188,11 +192,14 @@ void
|
||||
DynamicModel::newTrackLoading()
|
||||
{
|
||||
qDebug() << "Got NEW TRACK LOADING signal";
|
||||
if( m_changeOnNext ) { // reset instead of getting the next one
|
||||
if ( m_changeOnNext )
|
||||
{ // reset instead of getting the next one
|
||||
m_lastResolvedRow = rowCount( QModelIndex() );
|
||||
m_searchingForNext = true;
|
||||
m_playlist->generator()->startOnDemand();
|
||||
} else if( m_onDemandRunning && m_currentAttempts == 0 && !m_searchingForNext ) { // if we're in dynamic mode and we're also currently idle
|
||||
}
|
||||
else if ( m_onDemandRunning && m_currentAttempts == 0 && !m_searchingForNext )
|
||||
{ // if we're in dynamic mode and we're also currently idle
|
||||
m_lastResolvedRow = rowCount( QModelIndex() );
|
||||
m_searchingForNext = true;
|
||||
qDebug() << "IDLE fetching new track!";
|
||||
@@ -204,13 +211,17 @@ DynamicModel::newTrackLoading()
|
||||
void
|
||||
DynamicModel::tracksGenerated( const QList< query_ptr > entries, int limitResolvedTo )
|
||||
{
|
||||
if( m_filterUnresolvable && m_playlist->mode() == OnDemand ) { // wait till we get them resolved (for previewing stations)
|
||||
if ( m_filterUnresolvable && m_playlist->mode() == OnDemand )
|
||||
{ // wait till we get them resolved (for previewing stations)
|
||||
m_limitResolvedTo = limitResolvedTo;
|
||||
filterUnresolved( entries );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
addToPlaylist( entries, m_playlist->mode() == OnDemand ); // if ondemand, we're previewing, so clear old
|
||||
|
||||
if( m_playlist->mode() == OnDemand ) {
|
||||
if ( m_playlist->mode() == OnDemand )
|
||||
{
|
||||
m_lastResolvedRow = rowCount( QModelIndex() );
|
||||
}
|
||||
}
|
||||
@@ -224,9 +235,9 @@ DynamicModel::filterUnresolved( const QList< query_ptr >& entries )
|
||||
{
|
||||
m_toResolveList = entries;
|
||||
|
||||
foreach( const query_ptr& q, entries ) {
|
||||
foreach ( const query_ptr& q, entries )
|
||||
connect( q.data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( filteringTrackResolved( bool ) ) );
|
||||
}
|
||||
|
||||
Pipeline::instance()->resolve( entries, true );
|
||||
}
|
||||
|
||||
@@ -240,7 +251,8 @@ DynamicModel::filteringTrackResolved( bool successful )
|
||||
|
||||
// if meantime the user began the station, abort
|
||||
qDebug() << "Got filtering resolved finished for track, was it successful?:" << q->track() << q->artist() << successful << q->playable();
|
||||
if( m_onDemandRunning ) {
|
||||
if ( m_onDemandRunning )
|
||||
{
|
||||
m_toResolveList.clear();
|
||||
m_resolvedList.clear();
|
||||
|
||||
@@ -248,8 +260,10 @@ DynamicModel::filteringTrackResolved( bool successful )
|
||||
}
|
||||
|
||||
query_ptr realptr;
|
||||
foreach( const query_ptr& qptr, m_toResolveList ) {
|
||||
if( qptr.data() == q ) {
|
||||
foreach ( const query_ptr& qptr, m_toResolveList )
|
||||
{
|
||||
if ( qptr.data() == q )
|
||||
{
|
||||
realptr = qptr;
|
||||
break;
|
||||
}
|
||||
@@ -259,25 +273,30 @@ DynamicModel::filteringTrackResolved( bool successful )
|
||||
|
||||
m_toResolveList.removeAll( realptr );
|
||||
|
||||
if( realptr->playable() ) {
|
||||
if ( realptr->playable() )
|
||||
{
|
||||
m_resolvedList << realptr;
|
||||
|
||||
// append and update internal lastResolvedRow
|
||||
addToPlaylist( QList< query_ptr >() << realptr, false );
|
||||
if( m_playlist->mode() == OnDemand ) {
|
||||
if ( m_playlist->mode() == OnDemand )
|
||||
{
|
||||
m_lastResolvedRow = rowCount( QModelIndex() );
|
||||
}
|
||||
|
||||
if( m_toResolveList.isEmpty() || m_resolvedList.size() == m_limitResolvedTo ) { // done
|
||||
if ( m_toResolveList.isEmpty() || m_resolvedList.size() == m_limitResolvedTo )
|
||||
{ // done
|
||||
m_toResolveList.clear();
|
||||
m_resolvedList.clear();
|
||||
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Got unsuccessful resolve request for this track" << realptr->track() << realptr->artist();
|
||||
}
|
||||
|
||||
if( m_toResolveList.isEmpty() && rowCount( QModelIndex() ) == 0 ) // we failed
|
||||
if ( m_toResolveList.isEmpty() && rowCount( QModelIndex() ) == 0 ) // we failed
|
||||
emit trackGenerationFailure( tr( "Could not find a playable track.\n\nPlease change the filters or try again." ) );
|
||||
}
|
||||
|
||||
@@ -285,16 +304,20 @@ DynamicModel::filteringTrackResolved( bool successful )
|
||||
void
|
||||
DynamicModel::addToPlaylist( const QList< query_ptr >& entries, bool clearFirst )
|
||||
{
|
||||
if( clearFirst )
|
||||
if ( clearFirst )
|
||||
clear();
|
||||
|
||||
foreach ( const query_ptr& q, entries )
|
||||
m_deduper.append( QPair< QString, QString >( q->track(), q->artist() ) );
|
||||
|
||||
if( m_playlist->author()->isLocal() && m_playlist->mode() == Static ) {
|
||||
if ( m_playlist->author()->isLocal() && m_playlist->mode() == Static )
|
||||
{
|
||||
m_playlist->addEntries( entries, m_playlist->currentrevision() );
|
||||
} else { // read-only, so add tracks only in the GUI, not to the playlist itself
|
||||
foreach( const query_ptr& query, entries ) {
|
||||
}
|
||||
else
|
||||
{ // read-only, so add tracks only in the GUI, not to the playlist itself
|
||||
foreach ( const query_ptr& query, entries )
|
||||
{
|
||||
append( query );
|
||||
}
|
||||
}
|
||||
@@ -310,12 +333,15 @@ DynamicModel::remove(const QModelIndex& idx, bool moreToCome)
|
||||
return;
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "DYNAMIC MODEL REMOVIN!" << moreToCome << ( idx == index( rowCount( QModelIndex() ) - 1, 0, QModelIndex() ) );
|
||||
if( m_playlist->mode() == OnDemand ) {
|
||||
if( !moreToCome && idx == index( rowCount( QModelIndex() ) - 1, 0, QModelIndex() ) ) { // if the user is manually removing the last one, re-add as we're a station
|
||||
if ( m_playlist->mode() == OnDemand )
|
||||
{
|
||||
if ( !moreToCome && idx == index( rowCount( QModelIndex() ) - 1, 0, QModelIndex() ) )
|
||||
{ // if the user is manually removing the last one, re-add as we're a station
|
||||
newTrackLoading();
|
||||
}
|
||||
TrackModel::remove( idx );
|
||||
} else
|
||||
}
|
||||
else
|
||||
PlaylistModel::remove( idx, moreToCome );
|
||||
// don't call onPlaylistChanged.
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -32,33 +32,33 @@ namespace Tomahawk
|
||||
|
||||
class DynamicModel;
|
||||
|
||||
|
||||
|
||||
class DynamicView : public PlaylistView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DynamicView( QWidget* parent = 0 );
|
||||
virtual ~DynamicView();
|
||||
|
||||
|
||||
virtual void setDynamicModel( DynamicModel* model );
|
||||
|
||||
|
||||
void setOnDemand( bool onDemand );
|
||||
void setReadOnly( bool readOnly );
|
||||
|
||||
|
||||
void setDynamicWorking( bool working );
|
||||
|
||||
|
||||
virtual void paintEvent( QPaintEvent* event );
|
||||
|
||||
|
||||
public slots:
|
||||
void showMessageTimeout( const QString& title, const QString& body );
|
||||
void showMessage( const QString& message );
|
||||
|
||||
|
||||
// collapse and animate the transition
|
||||
// there MUST be a row *after* startRow + num. that is, you can't collapse
|
||||
// entries unless there is at least one entry after the last collapsed row
|
||||
// optionally you can specify how many rows are past the block of collapsed rows
|
||||
void collapseEntries( int startRow, int num, int numToKeep = 1 );
|
||||
|
||||
|
||||
private slots:
|
||||
void onTrackCountChanged( unsigned int );
|
||||
void checkForOverflow();
|
||||
@@ -70,7 +70,7 @@ private:
|
||||
DynamicModel* m_model;
|
||||
QString m_title;
|
||||
QString m_body;
|
||||
|
||||
|
||||
bool m_onDemand;
|
||||
bool m_readOnly;
|
||||
bool m_checkOnCollapse;
|
||||
@@ -88,7 +88,7 @@ private:
|
||||
QTimeLine m_fadeOutAnim;
|
||||
QTimeLine m_slideAnim;
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@@ -181,6 +181,7 @@ Tomahawk::EchonestControl::updateWidgets()
|
||||
input->hide();
|
||||
m_match = QWeakPointer< QWidget >( match );
|
||||
m_input = QWeakPointer< QWidget >( input );
|
||||
m_data.first = m_currentType;
|
||||
} else if( selectedType() == "Artist Description" ) {
|
||||
m_currentType = Echonest::DynamicPlaylist::Description;
|
||||
|
||||
@@ -199,6 +200,7 @@ Tomahawk::EchonestControl::updateWidgets()
|
||||
input->hide();
|
||||
m_match = QWeakPointer< QWidget >( match );
|
||||
m_input = QWeakPointer< QWidget >( input );
|
||||
m_data.first = m_currentType;
|
||||
} else if( selectedType() == "User Radio" ) {
|
||||
m_currentType = Echonest::DynamicPlaylist::SourceCatalog;
|
||||
|
||||
@@ -246,6 +248,7 @@ Tomahawk::EchonestControl::updateWidgets()
|
||||
input->hide();
|
||||
m_match = QWeakPointer< QWidget >( match );
|
||||
m_input = QWeakPointer< QWidget >( input );
|
||||
m_data.first = m_currentType;
|
||||
} else if( selectedType() == "Variety" ) {
|
||||
m_currentType = Echonest::DynamicPlaylist::Variety;
|
||||
|
||||
@@ -266,6 +269,7 @@ Tomahawk::EchonestControl::updateWidgets()
|
||||
input->hide();
|
||||
m_match = QWeakPointer< QWidget >( match );
|
||||
m_input = QWeakPointer< QWidget >( input );
|
||||
m_data.first = m_currentType;
|
||||
} else if( selectedType() == "Adventurousness" ) {
|
||||
m_currentType = Echonest::DynamicPlaylist::Adventurousness;
|
||||
|
||||
@@ -287,6 +291,7 @@ Tomahawk::EchonestControl::updateWidgets()
|
||||
input->hide();
|
||||
m_match = QWeakPointer< QWidget >( match );
|
||||
m_input = QWeakPointer< QWidget >( input );
|
||||
m_data.first = m_currentType;
|
||||
} else if( selectedType() == "Tempo" ) {
|
||||
m_currentType = Echonest::DynamicPlaylist::MinTempo;
|
||||
|
||||
|
@@ -118,32 +118,34 @@ DynamicWidget::loadDynamicPlaylist( const Tomahawk::dynplaylist_ptr& playlist )
|
||||
{
|
||||
// special case: if we have launched multiple setRevision calls, and the number of controls is different, it means that we're getting an intermediate setRevision
|
||||
// called after the user has already created more revisions. ignore in that case.
|
||||
if( m_playlist.data() == playlist.data() && m_seqRevLaunched > 0
|
||||
if ( m_playlist.data() == playlist.data() && m_seqRevLaunched > 0
|
||||
&& m_controls->controls().size() != playlist->generator()->controls().size() // different number of controls
|
||||
&& qAbs( m_playlist->generator()->controls().size() - playlist->generator()->controls().size() ) < m_seqRevLaunched ) { // difference in controls has to be less than how many revisions we launched
|
||||
&& qAbs( m_playlist->generator()->controls().size() - playlist->generator()->controls().size() ) < m_seqRevLaunched )
|
||||
{ // difference in controls has to be less than how many revisions we launched
|
||||
return;
|
||||
}
|
||||
m_seqRevLaunched = 0;
|
||||
|
||||
// if we're being told to load the same dynamic playlist over again, only do it if the controls have a different number
|
||||
if( !m_playlist.isNull() && ( m_playlist.data() == playlist.data() ) // same playlist pointer
|
||||
&& m_playlist->generator()->controls().size() == playlist->generator()->controls().size() ) {
|
||||
if ( !m_playlist.isNull() && ( m_playlist.data() == playlist.data() ) // same playlist pointer
|
||||
&& m_playlist->generator()->controls().size() == playlist->generator()->controls().size() )
|
||||
{
|
||||
// we can skip our work. just let the dynamiccontrollist show the difference
|
||||
m_controls->setControls( m_playlist, m_playlist->author()->isLocal() );
|
||||
|
||||
m_playlist = playlist;
|
||||
|
||||
if( !m_runningOnDemand ) {
|
||||
if ( !m_runningOnDemand )
|
||||
m_model->loadPlaylist( m_playlist );
|
||||
} else if( !m_controlsChanged ) { // if the controls changed, we already dealt with that and don't want to change station yet
|
||||
else if ( !m_controlsChanged ) // if the controls changed, we already dealt with that and don't want to change station yet
|
||||
m_model->changeStation();
|
||||
}
|
||||
m_controlsChanged = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( !m_playlist.isNull() ) {
|
||||
if ( !m_playlist.isNull() )
|
||||
{
|
||||
disconnect( m_playlist->generator().data(), SIGNAL( generated( QList<Tomahawk::query_ptr> ) ), this, SLOT( tracksGenerated( QList<Tomahawk::query_ptr> ) ) );
|
||||
disconnect( m_playlist.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision) ), this, SLOT(onRevisionLoaded( Tomahawk::DynamicPlaylistRevision) ) );
|
||||
disconnect( m_playlist->generator().data(), SIGNAL( error( QString, QString ) ), this, SLOT( generatorError( QString, QString ) ) );
|
||||
@@ -160,23 +162,22 @@ DynamicWidget::loadDynamicPlaylist( const Tomahawk::dynplaylist_ptr& playlist )
|
||||
m_setup->setPlaylist( m_playlist );
|
||||
|
||||
|
||||
if( !m_playlist->author()->isLocal() ) { // hide controls, as we show the description in the summary
|
||||
if ( !m_playlist->author()->isLocal() ) // hide controls, as we show the description in the summary
|
||||
m_layout->removeWidget( m_controls );
|
||||
} else if( m_layout->indexOf( m_controls ) == -1 ) {
|
||||
else if ( m_layout->indexOf( m_controls ) == -1 )
|
||||
m_layout->insertWidget( 0, m_controls );
|
||||
}
|
||||
|
||||
if( m_playlist->mode() == OnDemand && !m_playlist->generator()->controls().isEmpty() )
|
||||
showPreview();
|
||||
|
||||
if( !m_playlist.isNull() )
|
||||
m_controls->setControls( m_playlist, m_playlist->author()->isLocal() );
|
||||
|
||||
connect( m_playlist->generator().data(), SIGNAL( generated( QList<Tomahawk::query_ptr> ) ), this, SLOT( tracksGenerated( QList<Tomahawk::query_ptr> ) ) );
|
||||
connect( m_playlist.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( onRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ) );
|
||||
connect( m_playlist->generator().data(), SIGNAL( error( QString, QString ) ), this, SLOT( generatorError( QString, QString ) ) );
|
||||
connect( m_playlist.data(), SIGNAL( deleted( Tomahawk::dynplaylist_ptr ) ), this, SLOT( onDeleted() ) );
|
||||
connect( m_playlist.data(), SIGNAL( changed() ), this, SLOT( onChanged() ) );
|
||||
|
||||
if ( m_playlist->mode() == OnDemand && !m_playlist->generator()->controls().isEmpty() )
|
||||
showPreview();
|
||||
|
||||
if ( !m_playlist.isNull() )
|
||||
m_controls->setControls( m_playlist, m_playlist->author()->isLocal() );
|
||||
}
|
||||
|
||||
|
||||
@@ -226,12 +227,15 @@ DynamicWidget::resizeEvent(QResizeEvent* )
|
||||
void
|
||||
DynamicWidget::layoutFloatingWidgets()
|
||||
{
|
||||
if( !m_runningOnDemand ) {
|
||||
if ( !m_runningOnDemand )
|
||||
{
|
||||
int x = ( width() / 2 ) - ( m_setup->size().width() / 2 );
|
||||
int y = height() - m_setup->size().height() - 40; // padding
|
||||
|
||||
m_setup->move( x, y );
|
||||
} else if( m_runningOnDemand && m_steering ) {
|
||||
}
|
||||
else if( m_runningOnDemand && m_steering )
|
||||
{
|
||||
int x = ( width() / 2 ) - ( m_steering->size().width() / 2 );
|
||||
int y = height() - m_steering->size().height() - 40; // padding
|
||||
|
||||
@@ -243,13 +247,15 @@ DynamicWidget::layoutFloatingWidgets()
|
||||
void
|
||||
DynamicWidget::playlistChanged( Tomahawk::playlistinterface_ptr pl )
|
||||
{
|
||||
if( pl == m_view->proxyModel()->playlistInterface() ) { // same playlist
|
||||
if ( pl == m_view->proxyModel()->playlistInterface() ) // same playlist
|
||||
m_activePlaylist = true;
|
||||
} else {
|
||||
else
|
||||
{
|
||||
m_activePlaylist = false;
|
||||
|
||||
// user started playing something somewhere else, so give it a rest
|
||||
if( m_runningOnDemand ) {
|
||||
if ( m_runningOnDemand )
|
||||
{
|
||||
stopStation( false );
|
||||
}
|
||||
}
|
||||
@@ -259,9 +265,8 @@ DynamicWidget::playlistChanged( Tomahawk::playlistinterface_ptr pl )
|
||||
void
|
||||
DynamicWidget::showEvent(QShowEvent* )
|
||||
{
|
||||
if( !m_playlist.isNull() && !m_runningOnDemand ) {
|
||||
if ( !m_playlist.isNull() && !m_runningOnDemand )
|
||||
m_setup->fadeIn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -289,8 +294,9 @@ DynamicWidget::stationFailed( const QString& msg )
|
||||
void
|
||||
DynamicWidget::trackStarted()
|
||||
{
|
||||
if( m_activePlaylist && !m_playlist.isNull() &&
|
||||
m_playlist->mode() == OnDemand && !m_runningOnDemand ) {
|
||||
if ( m_activePlaylist && !m_playlist.isNull() &&
|
||||
m_playlist->mode() == OnDemand && !m_runningOnDemand )
|
||||
{
|
||||
|
||||
startStation();
|
||||
}
|
||||
@@ -300,7 +306,7 @@ DynamicWidget::trackStarted()
|
||||
void
|
||||
DynamicWidget::tracksAdded()
|
||||
{
|
||||
if( m_playlist->mode() == OnDemand && m_runningOnDemand && m_setup->isVisible() )
|
||||
if ( m_playlist->mode() == OnDemand && m_runningOnDemand && m_setup->isVisible() )
|
||||
m_setup->fadeOut();
|
||||
}
|
||||
|
||||
@@ -325,7 +331,8 @@ DynamicWidget::startStation()
|
||||
|
||||
m_setup->fadeOut();
|
||||
// show the steering controls
|
||||
if( m_playlist->generator()->onDemandSteerable() ) {
|
||||
if ( m_playlist->generator()->onDemandSteerable() )
|
||||
{
|
||||
// position it horizontally centered, above the botton.
|
||||
m_steering = m_playlist->generator()->steeringWidget();
|
||||
Q_ASSERT( m_steering );
|
||||
@@ -361,7 +368,7 @@ DynamicWidget::tracksGenerated( const QList< query_ptr >& queries )
|
||||
{
|
||||
m_resolveOnNextLoad = true;
|
||||
}
|
||||
else if( m_playlist->mode() == OnDemand )
|
||||
else if ( m_playlist->mode() == OnDemand )
|
||||
{
|
||||
limit = 5;
|
||||
}
|
||||
@@ -380,7 +387,7 @@ DynamicWidget::controlsChanged( bool added )
|
||||
// when playing a station just ignore it till we're ready and get a controlChanged()
|
||||
m_controlsChanged = true;
|
||||
|
||||
if( !m_playlist->author()->isLocal() )
|
||||
if ( !m_playlist->author()->isLocal() )
|
||||
return;
|
||||
m_playlist->createNewRevision();
|
||||
m_seqRevLaunched++;
|
||||
@@ -396,7 +403,7 @@ void
|
||||
DynamicWidget::controlChanged( const Tomahawk::dyncontrol_ptr& control )
|
||||
{
|
||||
Q_UNUSED( control );
|
||||
if( !m_playlist->author()->isLocal() )
|
||||
if ( !m_playlist->author()->isLocal() )
|
||||
return;
|
||||
m_playlist->createNewRevision();
|
||||
m_seqRevLaunched++;
|
||||
@@ -443,8 +450,7 @@ DynamicWidget::steeringChanged()
|
||||
void
|
||||
DynamicWidget::showPreview()
|
||||
{
|
||||
if ( m_playlist->mode() == OnDemand &&
|
||||
!m_runningOnDemand )
|
||||
if ( m_playlist->mode() == OnDemand && !m_runningOnDemand )
|
||||
{
|
||||
// if this is a not running station, preview matching tracks
|
||||
m_model->clear();
|
||||
@@ -456,12 +462,16 @@ DynamicWidget::showPreview()
|
||||
void
|
||||
DynamicWidget::generatorError( const QString& title, const QString& content )
|
||||
{
|
||||
if( m_runningOnDemand ) {
|
||||
stopStation( false );
|
||||
}
|
||||
m_view->setDynamicWorking( false );
|
||||
m_loading->fadeOut();
|
||||
m_view->showMessageTimeout( title, content );
|
||||
|
||||
if ( m_runningOnDemand )
|
||||
{
|
||||
stopStation( false );
|
||||
m_view->showMessage( tr( "Station ran out of tracks!\n\nTry tweaking the filters for a new set of songs to play." ) );
|
||||
}
|
||||
else
|
||||
m_view->showMessageTimeout( title, content );
|
||||
}
|
||||
|
||||
|
||||
@@ -528,7 +538,7 @@ DynamicWidget::onDeleted()
|
||||
void
|
||||
DynamicWidget::onChanged()
|
||||
{
|
||||
if( !m_playlist.isNull() &&
|
||||
ViewManager::instance()->currentPage() == this )
|
||||
emit nameChanged( m_playlist->title() );
|
||||
if ( !m_playlist.isNull() &&
|
||||
ViewManager::instance()->currentPage() == this )
|
||||
emit nameChanged( m_playlist->title() );
|
||||
}
|
||||
|
@@ -155,32 +155,18 @@ TreeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
QPixmap cover;
|
||||
if ( !item->album().isNull() )
|
||||
{
|
||||
cover.loadFromData( item->album()->cover() );
|
||||
cover = item->album()->cover( r.size(), false );
|
||||
if ( cover.isNull() )
|
||||
cover = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, r.size() );
|
||||
}
|
||||
else if ( !item->artist().isNull() )
|
||||
{
|
||||
cover.loadFromData( item->artist()->cover() );
|
||||
cover = item->artist()->cover( r.size(), false );
|
||||
if ( cover.isNull() )
|
||||
cover = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultArtistImage, TomahawkUtils::ScaledCover, r.size() );
|
||||
}
|
||||
|
||||
QPixmap scover;
|
||||
if ( cover.isNull() )
|
||||
{
|
||||
if ( !item->artist().isNull() )
|
||||
cover = m_defaultArtistImage;
|
||||
else
|
||||
cover = m_defaultAlbumCover;
|
||||
}
|
||||
|
||||
if ( m_cache.contains( cover.cacheKey() ) )
|
||||
{
|
||||
scover = m_cache.value( cover.cacheKey() );
|
||||
}
|
||||
else
|
||||
{
|
||||
scover = cover.scaled( r.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_cache.insert( cover.cacheKey(), scover );
|
||||
}
|
||||
painter->drawPixmap( r, scover );
|
||||
painter->drawPixmap( r, cover );
|
||||
|
||||
QTextOption to;
|
||||
to.setAlignment( Qt::AlignVCenter );
|
||||
|
@@ -43,8 +43,6 @@ private:
|
||||
ArtistView* m_view;
|
||||
TreeProxyModel* m_model;
|
||||
|
||||
mutable QHash< qint64, QPixmap > m_cache;
|
||||
|
||||
QPixmap m_nowPlayingIcon;
|
||||
QPixmap m_defaultAlbumCover;
|
||||
QPixmap m_defaultArtistImage;
|
||||
|
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <QMimeData>
|
||||
|
||||
#include "pipeline.h"
|
||||
#include "source.h"
|
||||
#include "sourcelist.h"
|
||||
#include "audio/audioengine.h"
|
||||
@@ -87,6 +88,18 @@ TreeModel::collection() const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TreeModel::getCover( const QModelIndex& index )
|
||||
{
|
||||
TreeModelItem* item = itemFromIndex( index );
|
||||
|
||||
if ( !item->artist().isNull() && !item->artist()->infoLoaded() )
|
||||
item->artist()->cover( QSize( 0, 0 ) );
|
||||
else if ( !item->album().isNull() && !item->album()->infoLoaded() )
|
||||
item->album()->cover( QSize( 0, 0 ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TreeModel::setCurrentItem( const QModelIndex& index )
|
||||
{
|
||||
@@ -783,6 +796,8 @@ TreeModel::onAlbumsAdded( const QList<Tomahawk::album_ptr>& albums, const QModel
|
||||
albumitem = new TreeModelItem( album, parentItem );
|
||||
albumitem->index = createIndex( parentItem->children.count() - 1, 0, albumitem );
|
||||
connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
|
||||
|
||||
getCover( albumitem->index );
|
||||
}
|
||||
|
||||
emit endInsertRows();
|
||||
@@ -915,10 +930,11 @@ TreeModel::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QV
|
||||
|
||||
foreach ( const QString& trackName, tracks )
|
||||
{
|
||||
query_ptr query = Query::get( inputInfo[ "artist" ], trackName, inputInfo[ "album" ], uuid() );
|
||||
query_ptr query = Query::get( inputInfo[ "artist" ], trackName, inputInfo[ "album" ] );
|
||||
query->setAlbumPos( trackNo++ );
|
||||
ql << query;
|
||||
}
|
||||
Pipeline::instance()->resolve( ql );
|
||||
|
||||
onTracksAdded( ql, idx );
|
||||
}
|
||||
|
@@ -98,6 +98,8 @@ public:
|
||||
void addAlbums( const Tomahawk::artist_ptr& artist, const QModelIndex& parent, bool autoRefetch = false );
|
||||
void addTracks( const Tomahawk::album_ptr& album, const QModelIndex& parent, bool autoRefetch = false );
|
||||
|
||||
void getCover( const QModelIndex& index );
|
||||
|
||||
ColumnStyle columnStyle() const { return m_columnStyle; }
|
||||
void setColumnStyle( ColumnStyle style );
|
||||
|
||||
|
@@ -104,6 +104,7 @@ Query::Query( const QString& query, const QID& qid )
|
||||
|
||||
Query::~Query()
|
||||
{
|
||||
QMutexLocker lock( &m_mutex );
|
||||
m_ownRef.clear();
|
||||
}
|
||||
|
||||
@@ -459,7 +460,15 @@ Query::howSimilar( const Tomahawk::result_ptr& r )
|
||||
|
||||
if ( isFullTextQuery() )
|
||||
{
|
||||
const QString artistTrackname = DatabaseImpl::sortname( fullTextQuery() );
|
||||
const QString rArtistTrackname = DatabaseImpl::sortname( r->artist()->name() + " " + r->track() );
|
||||
|
||||
int atrdist = levenshtein( artistTrackname, rArtistTrackname );
|
||||
int mlatr = qMax( artistTrackname.length(), rArtistTrackname.length() );
|
||||
float dcatr = (float)( mlatr - atrdist ) / mlatr;
|
||||
|
||||
float res = qMax( dcart, dcalb );
|
||||
res = qMax( res, dcatr );
|
||||
return qMax( res, dctrk );
|
||||
}
|
||||
else
|
||||
@@ -489,7 +498,7 @@ Query::loadSocialActions()
|
||||
query_ptr q = m_ownRef.toStrongRef();
|
||||
|
||||
DatabaseCommand_LoadSocialActions* cmd = new DatabaseCommand_LoadSocialActions( q );
|
||||
connect( cmd, SIGNAL( finished() ), SLOT( onSocialActionsLoaded() ));
|
||||
connect( cmd, SIGNAL( finished() ), SLOT( onSocialActionsLoaded() ) );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
|
||||
}
|
||||
|
||||
|
@@ -350,6 +350,12 @@ Source::trackTimerFired()
|
||||
void
|
||||
Source::addCommand( const QSharedPointer<DatabaseCommand>& command )
|
||||
{
|
||||
if ( QThread::currentThread() != thread() )
|
||||
{
|
||||
QMetaObject::invokeMethod( this, "addCommand", Qt::QueuedConnection, Q_ARG( const QSharedPointer<DatabaseCommand>, command ) );
|
||||
return;
|
||||
}
|
||||
|
||||
m_cmds << command;
|
||||
if ( !command->singletonCmd() )
|
||||
m_lastCmdGuid = command->guid();
|
||||
@@ -363,7 +369,6 @@ Source::executeCommands()
|
||||
{
|
||||
if ( QThread::currentThread() != thread() )
|
||||
{
|
||||
tDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO;
|
||||
QMetaObject::invokeMethod( this, "executeCommands", Qt::QueuedConnection );
|
||||
return;
|
||||
}
|
||||
|
@@ -129,9 +129,9 @@ private slots:
|
||||
void trackTimerFired();
|
||||
|
||||
void executeCommands();
|
||||
void addCommand( const QSharedPointer<DatabaseCommand>& command );
|
||||
|
||||
private:
|
||||
void addCommand( const QSharedPointer<DatabaseCommand>& command );
|
||||
void updateTracks();
|
||||
void reportSocialAttributesChanged( DatabaseCommand_SocialAction* action );
|
||||
|
||||
|
@@ -137,7 +137,7 @@ SourcePlaylistInterface::onSourcePlaybackStarted( const Tomahawk::query_ptr& que
|
||||
{
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO;
|
||||
connect( query.data(), SIGNAL( resolvingFinished( bool ) ), SLOT( resolvingFinished( bool ) ) );
|
||||
Pipeline::instance()->resolve( query, true );
|
||||
Pipeline::instance()->resolve( query );
|
||||
m_gotNextItem = false;
|
||||
}
|
||||
|
||||
|
@@ -29,7 +29,7 @@
|
||||
#include "database/databasecommand_updatesearchindex.h"
|
||||
#include "database/database.h"
|
||||
|
||||
#define VERSION 5
|
||||
#define VERSION 6
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -47,19 +47,24 @@ TomahawkSettings::TomahawkSettings( QObject* parent )
|
||||
{
|
||||
s_instance = this;
|
||||
|
||||
if( !contains( "configversion") )
|
||||
#ifdef Q_OS_LINUX
|
||||
QFile file( fileName() );
|
||||
file.setPermissions( file.permissions() & ~(QFile::ReadGroup | QFile::WriteGroup | QFile::ExeGroup | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther ) );
|
||||
#endif
|
||||
|
||||
if ( !contains( "configversion" ) )
|
||||
{
|
||||
setValue( "configversion", VERSION );
|
||||
doInitialSetup();
|
||||
}
|
||||
else if( value( "configversion" ).toUInt() != VERSION )
|
||||
else if ( value( "configversion" ).toUInt() != VERSION )
|
||||
{
|
||||
qDebug() << "Config version outdated, old:" << value( "configversion" ).toUInt()
|
||||
<< "new:" << VERSION
|
||||
<< "Doing upgrade, if any...";
|
||||
|
||||
int current = value( "configversion" ).toUInt();
|
||||
while( current < VERSION )
|
||||
while ( current < VERSION )
|
||||
{
|
||||
doUpgrade( current, current + 1 );
|
||||
|
||||
@@ -68,7 +73,6 @@ TomahawkSettings::TomahawkSettings( QObject* parent )
|
||||
// insert upgrade code here as required
|
||||
setValue( "configversion", VERSION );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -91,22 +95,23 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion )
|
||||
{
|
||||
Q_UNUSED( newVersion );
|
||||
|
||||
if( oldVersion == 1 )
|
||||
if ( oldVersion == 1 )
|
||||
{
|
||||
qDebug() << "Migrating config from verson 1 to 2: script resolver config name";
|
||||
if( contains( "script/resolvers" ) ) {
|
||||
setValue( "script/loadedresolvers", value( "script/resolvers" ) );
|
||||
remove( "script/resolvers" );
|
||||
}
|
||||
} else if( oldVersion == 2 )
|
||||
}
|
||||
else if ( oldVersion == 2 )
|
||||
{
|
||||
qDebug() << "Migrating config from version 2 to 3: Converting jabber and twitter accounts to new SIP Factory approach";
|
||||
// migrate old accounts to new system. only jabber and twitter, and max one each. create a new plugin for each if needed
|
||||
// not pretty as we hardcode a plugin id and assume that we know how the config layout is, but hey, this is migration after all
|
||||
if( contains( "jabber/username" ) && contains( "jabber/password" ) )
|
||||
if ( contains( "jabber/username" ) && contains( "jabber/password" ) )
|
||||
{
|
||||
QString sipName = "sipjabber";
|
||||
if( value( "jabber/username" ).toString().contains( "@gmail" ) )
|
||||
if ( value( "jabber/username" ).toString().contains( "@gmail" ) )
|
||||
sipName = "sipgoogle";
|
||||
|
||||
setValue( QString( "%1_legacy/username" ).arg( sipName ), value( "jabber/username" ) );
|
||||
@@ -123,7 +128,7 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion )
|
||||
remove( "jabber/server" );
|
||||
remove( "jabber/port" );
|
||||
}
|
||||
if( contains( "twitter/ScreenName" ) && contains( "twitter/OAuthToken" ) )
|
||||
if ( contains( "twitter/ScreenName" ) && contains( "twitter/OAuthToken" ) )
|
||||
{
|
||||
setValue( "siptwitter_legacy/ScreenName", value( "twitter/ScreenName" ) );
|
||||
setValue( "siptwitter_legacy/OAuthToken", value( "twitter/OAuthToken" ) );
|
||||
@@ -144,7 +149,8 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion )
|
||||
}
|
||||
// create a zeroconf plugin too
|
||||
addSipPlugin( "sipzeroconf_legacy" );
|
||||
} else if ( oldVersion == 3 )
|
||||
}
|
||||
else if ( oldVersion == 3 )
|
||||
{
|
||||
if ( contains( "script/atticaresolverstates" ) )
|
||||
{
|
||||
@@ -183,7 +189,8 @@ TomahawkSettings::doUpgrade( int oldVersion, int newVersion )
|
||||
tDebug() << "UPGRADING AND DELETING:" << resolverDir.absolutePath();
|
||||
TomahawkUtils::removeDirectory( resolverDir.absolutePath() );
|
||||
}
|
||||
} else if ( oldVersion == 4 )
|
||||
}
|
||||
else if ( oldVersion == 4 || oldVersion == 5 )
|
||||
{
|
||||
// 0.3.0 contained a bug which prevent indexing local files. Force a reindex.
|
||||
QTimer::singleShot( 0, this, SLOT( updateIndex() ) );
|
||||
@@ -935,6 +942,7 @@ TomahawkSettings::setNowPlayingEnabled( bool enable )
|
||||
setValue( "adium/enablenowplaying", enable );
|
||||
}
|
||||
|
||||
|
||||
TomahawkSettings::PrivateListeningMode
|
||||
TomahawkSettings::privateListeningMode() const
|
||||
{
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "dropjob.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#include "jobview/ErrorStatusMessage.h"
|
||||
#include "dropjobnotifier.h"
|
||||
#include "viewmanager.h"
|
||||
|
||||
@@ -38,6 +39,10 @@
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
#include <QWebPage>
|
||||
#include <QWebFrame>
|
||||
#include <QWebElement>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
QPixmap* GroovesharkParser::s_pixmap = 0;
|
||||
@@ -71,15 +76,17 @@ GroovesharkParser::~GroovesharkParser()
|
||||
void
|
||||
GroovesharkParser::lookupUrl( const QString& link )
|
||||
{
|
||||
if( link.contains( "playlist" ) )
|
||||
if ( link.contains( "playlist" ) )
|
||||
{
|
||||
if( !m_createNewPlaylist )
|
||||
if ( !m_createNewPlaylist )
|
||||
m_trackMode = true;
|
||||
else
|
||||
m_trackMode = false;
|
||||
|
||||
lookupGroovesharkPlaylist( link );
|
||||
}
|
||||
else if ( link.contains( "grooveshark.com/s/" ) || link.contains( "grooveshark.com/#/s/" ) )
|
||||
lookupGroovesharkTrack( link );
|
||||
else
|
||||
return;
|
||||
|
||||
@@ -96,7 +103,7 @@ GroovesharkParser::lookupGroovesharkPlaylist( const QString& linkRaw )
|
||||
tDebug() << "no fragment, setting fragment to path";
|
||||
urlFragment = QUrl(linkRaw).path();
|
||||
}
|
||||
|
||||
|
||||
tDebug() << urlFragment;
|
||||
|
||||
int paramStartingPostition = urlFragment.indexOf( "?" );
|
||||
@@ -107,22 +114,22 @@ GroovesharkParser::lookupGroovesharkPlaylist( const QString& linkRaw )
|
||||
bool ok;
|
||||
|
||||
QStringList urlParts = urlFragment.split( "/", QString::SkipEmptyParts );
|
||||
|
||||
|
||||
tDebug() << urlParts;
|
||||
|
||||
|
||||
int playlistID = urlParts.at( 2 ).toInt( &ok, 10 );
|
||||
if (!ok)
|
||||
{
|
||||
tDebug() << "incorrect grooveshark url";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
m_title = urlParts.at( 1 );
|
||||
|
||||
|
||||
tDebug() << "should get playlist " << playlistID;
|
||||
|
||||
|
||||
DropJob::DropType type;
|
||||
|
||||
type = DropJob::Playlist;
|
||||
@@ -152,6 +159,53 @@ GroovesharkParser::lookupGroovesharkPlaylist( const QString& linkRaw )
|
||||
m_queries.insert( reply );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GroovesharkParser::lookupGroovesharkTrack( const QString& track )
|
||||
{
|
||||
tLog() << "Parsing Grooveshark Track Page:" << track;
|
||||
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( track ) ) );
|
||||
connect( reply, SIGNAL( finished() ), this, SLOT( trackPageFetchFinished() ) );
|
||||
|
||||
m_browseJob = new DropJobNotifier( pixmap(), "Grooveshark", DropJob::Track, reply );
|
||||
JobStatusView::instance()->model()->addJob( m_browseJob );
|
||||
|
||||
m_queries << reply;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GroovesharkParser::trackPageFetchFinished()
|
||||
{
|
||||
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
|
||||
Q_ASSERT( r );
|
||||
|
||||
m_queries.remove( r );
|
||||
r->deleteLater();
|
||||
|
||||
QWebPage page;
|
||||
page.settings()->setAttribute( QWebSettings::JavascriptEnabled, false );
|
||||
page.settings()->setAttribute( QWebSettings::PluginsEnabled, false );
|
||||
page.settings()->setAttribute( QWebSettings::JavaEnabled, false );
|
||||
page.settings()->setAttribute( QWebSettings::AutoLoadImages, false );
|
||||
page.mainFrame()->setHtml( QString::fromUtf8( r->readAll() ) );
|
||||
QWebElement title = page.mainFrame()->findFirstElement("span[itemprop='name']");
|
||||
QWebElement artist = page.mainFrame()->findFirstElement("noscript span[itemprop='byArtist']");
|
||||
QWebElement album = page.mainFrame()->findFirstElement("noscript span[itemprop='inAlbum']");
|
||||
|
||||
if ( !title.toPlainText().isEmpty() && !artist.toPlainText().isEmpty() )
|
||||
{
|
||||
tDebug() << "Got track info from grooveshark, enough to create a query:" << title.toPlainText() << artist.toPlainText() << album.toPlainText();
|
||||
|
||||
Tomahawk::query_ptr q = Tomahawk::Query::get( artist.toPlainText(), title.toPlainText(), album.toPlainText(), uuid(), true );
|
||||
m_tracks << q;
|
||||
}
|
||||
|
||||
checkTrackFinished();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GroovesharkParser::groovesharkLookupFinished()
|
||||
{
|
||||
@@ -178,7 +232,7 @@ GroovesharkParser::groovesharkLookupFinished()
|
||||
foreach (const QVariant& var, list)
|
||||
{
|
||||
QVariantMap trackResult = var.toMap();
|
||||
|
||||
|
||||
QString title, artist, album;
|
||||
|
||||
title = trackResult.value( "SongName", QString() ).toString();
|
||||
@@ -194,10 +248,11 @@ GroovesharkParser::groovesharkLookupFinished()
|
||||
Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album, uuid(), m_trackMode );
|
||||
m_tracks << q;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else
|
||||
{
|
||||
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Error fetching Grooveshark information from the network!" ) ) );
|
||||
tLog() << "Error in network request to grooveshark for track decoding:" << r->errorString();
|
||||
}
|
||||
|
||||
@@ -229,7 +284,7 @@ GroovesharkParser::checkPlaylistFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
emit tracks( m_tracks );
|
||||
|
||||
deleteLater();
|
||||
|
@@ -42,7 +42,7 @@ class QNetworkReply;
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
|
||||
class DropJobNotifier;
|
||||
|
||||
class DLLEXPORT GroovesharkParser : public QObject
|
||||
@@ -58,6 +58,7 @@ signals:
|
||||
|
||||
private slots:
|
||||
void groovesharkLookupFinished();
|
||||
void trackPageFetchFinished();
|
||||
|
||||
void playlistCreated();
|
||||
private:
|
||||
@@ -65,6 +66,8 @@ private:
|
||||
|
||||
void lookupUrl( const QString& url );
|
||||
void lookupGroovesharkPlaylist( const QString& playlist );
|
||||
void lookupGroovesharkTrack( const QString& track );
|
||||
|
||||
void checkTrackFinished();
|
||||
void checkPlaylistFinished();
|
||||
int m_limit;
|
||||
@@ -79,7 +82,7 @@ private:
|
||||
QCA::SymmetricKey m_apiKey;
|
||||
|
||||
static QPixmap* s_pixmap;
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "sourcelist.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#include "jobview/ErrorStatusMessage.h"
|
||||
|
||||
#include <qjson/parser.h>
|
||||
|
||||
@@ -166,6 +167,7 @@ ItunesParser::itunesResponseLookupFinished()
|
||||
|
||||
} else
|
||||
{
|
||||
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Error fetching iTunes information from the network!" ) ) );
|
||||
tLog() << "Error in network request to Itunes for track decoding:" << r->errorString();
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "dropjob.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#include "jobview/ErrorStatusMessage.h"
|
||||
#include "dropjobnotifier.h"
|
||||
#include "viewmanager.h"
|
||||
#include "sourcelist.h"
|
||||
@@ -189,6 +190,7 @@ RdioParser::rdioReturned()
|
||||
|
||||
} else
|
||||
{
|
||||
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Error fetching Rdio information from the network!" ) ) );
|
||||
tLog() << "Error in network request to Rdio for track decoding:" << r->errorString();
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,11 @@
|
||||
|
||||
#include "utils/logger.h"
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "dropjobnotifier.h"
|
||||
#include "query.h"
|
||||
#include "jobview/ErrorStatusMessage.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
|
||||
#include <qjson/parser.h>
|
||||
|
||||
@@ -30,6 +34,7 @@
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
QPixmap* ShortenedLinkParser::s_pixmap = 0;
|
||||
|
||||
ShortenedLinkParser::ShortenedLinkParser ( const QStringList& urls, QObject* parent )
|
||||
: QObject( parent )
|
||||
@@ -58,6 +63,8 @@ ShortenedLinkParser::handlesUrl( const QString& url )
|
||||
url.contains( "itun.es" ) ||
|
||||
url.contains( "tinyurl.com" ) ||
|
||||
url.contains( "tinysong.com" ) ||
|
||||
url.contains( "grooveshark.com/s/~/" ) || // These redirect to the 'real' grooveshark track url
|
||||
url.contains( "grooveshark.com/#/s/~/" ) ||
|
||||
url.contains( "rd.io" ) );
|
||||
}
|
||||
|
||||
@@ -65,11 +72,18 @@ void
|
||||
ShortenedLinkParser::lookupUrl ( const QString& url )
|
||||
{
|
||||
tDebug() << "Looking up..." << url;
|
||||
QString cleaned = url;
|
||||
if ( cleaned.contains( "/#/s/" ) )
|
||||
cleaned.replace( "/#", "" );
|
||||
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( url ) ) );
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( cleaned ) ) );
|
||||
connect( reply, SIGNAL( finished() ), this, SLOT( lookupFinished() ) );
|
||||
|
||||
m_queries.insert( reply );
|
||||
|
||||
m_expandJob = new DropJobNotifier( pixmap(), "shortened", DropJob::Track, reply );
|
||||
JobStatusView::instance()->model()->addJob( m_expandJob );
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -78,6 +92,9 @@ ShortenedLinkParser::lookupFinished()
|
||||
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
|
||||
Q_ASSERT( r );
|
||||
|
||||
if ( r->error() != QNetworkReply::NoError )
|
||||
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Network error parsing shortened link!" ) ) );
|
||||
|
||||
QVariant redir = r->attribute( QNetworkRequest::RedirectionTargetAttribute );
|
||||
if ( redir.isValid() && !redir.toUrl().isEmpty() )
|
||||
{
|
||||
@@ -89,7 +106,7 @@ ShortenedLinkParser::lookupFinished()
|
||||
else
|
||||
{
|
||||
tLog() << "Got a redirected url:" << r->url().toString();
|
||||
m_links << r->url().toString();
|
||||
m_links << r->url().toString();
|
||||
m_queries.remove( r );
|
||||
r->deleteLater();
|
||||
checkFinished();
|
||||
@@ -108,3 +125,13 @@ ShortenedLinkParser::checkFinished()
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QPixmap
|
||||
ShortenedLinkParser::pixmap()
|
||||
{
|
||||
if ( !s_pixmap )
|
||||
s_pixmap = new QPixmap( RESPATH "images/add.png" );
|
||||
|
||||
return *s_pixmap;
|
||||
}
|
||||
|
@@ -26,12 +26,15 @@
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
#include <QStringList>
|
||||
#include <QPixmap>
|
||||
|
||||
class QNetworkReply;
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
class DropJobNotifier;
|
||||
|
||||
/**
|
||||
* Small class to parse whitelisted shortened links into the redirected urls
|
||||
*
|
||||
@@ -58,8 +61,13 @@ private:
|
||||
void lookupUrl( const QString& url );
|
||||
void checkFinished();
|
||||
|
||||
static QPixmap pixmap();
|
||||
|
||||
QStringList m_links;
|
||||
QSet< QNetworkReply* > m_queries;
|
||||
DropJobNotifier* m_expandJob;
|
||||
|
||||
static QPixmap* s_pixmap;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "dropjob.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#include "jobview/ErrorStatusMessage.h"
|
||||
#include "dropjobnotifier.h"
|
||||
#include "viewmanager.h"
|
||||
|
||||
@@ -220,6 +221,7 @@ SpotifyParser::spotifyBrowseFinished()
|
||||
|
||||
} else
|
||||
{
|
||||
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Error fetching Spotify information from the network!" ) ) );
|
||||
tLog() << "Error in network request to Spotify for track decoding:" << r->errorString();
|
||||
}
|
||||
|
||||
|
@@ -533,10 +533,12 @@ newerVersion( const QString& oldVersion, const QString& newVersion )
|
||||
|
||||
|
||||
QList< Tomahawk::query_ptr >
|
||||
mergePlaylistChanges( const QList< Tomahawk::query_ptr >& orig, const QList< Tomahawk::query_ptr >& newTracks )
|
||||
mergePlaylistChanges( const QList< Tomahawk::query_ptr >& orig, const QList< Tomahawk::query_ptr >& newTracks, bool& changed )
|
||||
{
|
||||
int sameCount = 0;
|
||||
QList< Tomahawk::query_ptr > tosave = newTracks;
|
||||
changed = false;
|
||||
|
||||
foreach ( const Tomahawk::query_ptr& newquery, newTracks )
|
||||
{
|
||||
foreach ( const Tomahawk::query_ptr& oldq, orig )
|
||||
@@ -558,6 +560,7 @@ mergePlaylistChanges( const QList< Tomahawk::query_ptr >& orig, const QList< Tom
|
||||
if ( orig.size() == newTracks.size() && sameCount == orig.size() )
|
||||
return orig;
|
||||
|
||||
changed = true;
|
||||
return tosave;
|
||||
}
|
||||
|
||||
|
@@ -42,6 +42,18 @@ namespace TomahawkUtils
|
||||
MediaTypeTrack
|
||||
};
|
||||
|
||||
enum ImageType
|
||||
{
|
||||
DefaultAlbumCover,
|
||||
DefaultArtistImage
|
||||
};
|
||||
enum ImageMode
|
||||
{
|
||||
NoDefaultCover,
|
||||
CoverInCase,
|
||||
ScaledCover
|
||||
};
|
||||
|
||||
class DLLEXPORT NetworkProxyFactory : public QNetworkProxyFactory
|
||||
{
|
||||
public:
|
||||
@@ -98,7 +110,7 @@ namespace TomahawkUtils
|
||||
*
|
||||
* \return true if some changes were made, false if the new tracks are the same as the current tracks in \param orig
|
||||
*/
|
||||
DLLEXPORT QList< Tomahawk::query_ptr > mergePlaylistChanges( const QList< Tomahawk::query_ptr >& orig, const QList< Tomahawk::query_ptr >& newTracks );
|
||||
DLLEXPORT QList< Tomahawk::query_ptr > mergePlaylistChanges( const QList< Tomahawk::query_ptr >& orig, const QList< Tomahawk::query_ptr >& newTracks, bool& changed );
|
||||
|
||||
DLLEXPORT void crash();
|
||||
}
|
||||
|
@@ -36,6 +36,8 @@
|
||||
#include <windowsx.h>
|
||||
#endif
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace TomahawkUtils
|
||||
{
|
||||
static int s_headerHeight = 0;
|
||||
@@ -83,15 +85,15 @@ createDragPixmap( MediaType type, int itemCount )
|
||||
QPixmap pixmap;
|
||||
switch ( type )
|
||||
{
|
||||
case MediaTypeArtist:
|
||||
pixmap = QPixmap( ":/data/images/artist-icon.png" ).scaledToWidth( size, Qt::SmoothTransformation );
|
||||
break;
|
||||
case MediaTypeAlbum:
|
||||
pixmap = QPixmap( ":/data/images/album-icon.png" ).scaledToWidth( size, Qt::SmoothTransformation );
|
||||
break;
|
||||
case MediaTypeTrack:
|
||||
pixmap = QPixmap( QString( ":/data/images/track-icon-%2x%2.png" ).arg( size ) );
|
||||
break;
|
||||
case MediaTypeArtist:
|
||||
pixmap = QPixmap( ":/data/images/artist-icon.png" ).scaledToWidth( size, Qt::SmoothTransformation );
|
||||
break;
|
||||
case MediaTypeAlbum:
|
||||
pixmap = QPixmap( ":/data/images/album-icon.png" ).scaledToWidth( size, Qt::SmoothTransformation );
|
||||
break;
|
||||
case MediaTypeTrack:
|
||||
pixmap = QPixmap( QString( ":/data/images/track-icon-%2x%2.png" ).arg( size ) );
|
||||
break;
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
@@ -303,4 +305,59 @@ alphaBlend( const QColor& colorFrom, const QColor& colorTo, float opacity )
|
||||
return QColor( r, g, b );
|
||||
}
|
||||
|
||||
|
||||
QPixmap
|
||||
defaultPixmap( ImageType type, ImageMode mode, const QSize& size )
|
||||
{
|
||||
QPixmap pixmap;
|
||||
QHash< int, QPixmap > subsubcache;
|
||||
QHash< int, QHash< int, QPixmap > > subcache;
|
||||
static QHash< int, QHash< int, QHash< int, QPixmap > > > cache;
|
||||
|
||||
if ( cache.contains( type ) )
|
||||
{
|
||||
subcache = cache.value( type );
|
||||
|
||||
if ( subcache.contains( mode ) )
|
||||
{
|
||||
subsubcache = subcache.value( mode );
|
||||
|
||||
if ( subsubcache.contains( size.width() ) )
|
||||
return subsubcache.value( size.width() );
|
||||
}
|
||||
}
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case DefaultAlbumCover:
|
||||
if ( mode == CoverInCase )
|
||||
pixmap = QPixmap( RESPATH "images/no-album-art-placeholder.png" );
|
||||
else
|
||||
pixmap = QPixmap( RESPATH "images/no-album-no-case.png" );
|
||||
break;
|
||||
|
||||
case DefaultArtistImage:
|
||||
pixmap = QPixmap( RESPATH "images/no-artist-image-placeholder.png" );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( pixmap.isNull() )
|
||||
{
|
||||
Q_ASSERT( false );
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
if ( !size.isNull() )
|
||||
pixmap = pixmap.scaled( size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
subsubcache.insert( size.width(), pixmap );
|
||||
subcache.insert( mode, subsubcache );
|
||||
cache.insert( type, subcache );
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
} // ns
|
||||
|
@@ -19,6 +19,8 @@
|
||||
#ifndef TOMAHAWKUTILSGUI_H
|
||||
#define TOMAHAWKUTILSGUI_H
|
||||
|
||||
#include <QSize>
|
||||
|
||||
#include "tomahawkutils.h"
|
||||
#include "dllmacro.h"
|
||||
|
||||
@@ -46,6 +48,8 @@ namespace TomahawkUtils
|
||||
|
||||
DLLEXPORT int headerHeight();
|
||||
DLLEXPORT void setHeaderHeight( int height );
|
||||
|
||||
DLLEXPORT QPixmap defaultPixmap( ImageType type, ImageMode mode, const QSize& size = QSize( 0, 0 ) );
|
||||
}
|
||||
|
||||
#endif // TOMAHAWKUTILSGUI_H
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2011-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
|
||||
@@ -25,6 +26,12 @@
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#include "jobview/ErrorStatusMessage.h"
|
||||
#endif
|
||||
|
||||
#include "sourcelist.h"
|
||||
#include "playlist.h"
|
||||
#include <XspfUpdater.h>
|
||||
@@ -32,6 +39,22 @@
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
QString
|
||||
XSPFLoader::errorToString( XSPFErrorCode error )
|
||||
{
|
||||
switch ( error )
|
||||
{
|
||||
case ParseError:
|
||||
return tr( "Failed to parse contents of XSPF playlist" );
|
||||
case InvalidTrackError:
|
||||
return tr( "Some playlist entries were found without artist and track name, they will be omitted");
|
||||
case FetchError:
|
||||
return tr( "Failed to fetch the desired playlist from the network, or the desired file does not exist" );
|
||||
default:
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
XSPFLoader::XSPFLoader( bool autoCreate, bool autoUpdate, QObject *parent )
|
||||
: QObject( parent )
|
||||
, m_autoCreate( autoCreate )
|
||||
@@ -97,6 +120,9 @@ void
|
||||
XSPFLoader::reportError()
|
||||
{
|
||||
emit error( FetchError );
|
||||
#ifndef ENABLE_HEADLESS
|
||||
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( errorToString( FetchError) ) );
|
||||
#endif
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2011-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
|
||||
@@ -48,6 +49,8 @@ public:
|
||||
void setOverrideTitle( const QString& newTitle );
|
||||
void setAutoResolveTracks( bool autoResolve ) { m_autoResolve = autoResolve; }
|
||||
|
||||
static QString errorToString( XSPFErrorCode error );
|
||||
|
||||
signals:
|
||||
void error( XSPFLoader::XSPFErrorCode error );
|
||||
void ok( const Tomahawk::playlist_ptr& );
|
||||
|
@@ -74,6 +74,7 @@ ViewManager::ViewManager( QObject* parent )
|
||||
, m_whatsHotWidget( new WhatsHotWidget() )
|
||||
, m_topLovedWidget( 0 )
|
||||
, m_currentMode( PlaylistInterface::Tree )
|
||||
, m_loaded( false )
|
||||
{
|
||||
s_instance = this;
|
||||
|
||||
@@ -112,6 +113,10 @@ ViewManager::ViewManager( QObject* parent )
|
||||
connect( &m_filterTimer, SIGNAL( timeout() ), SLOT( applyFilter() ) );
|
||||
connect( m_infobar, SIGNAL( filterTextChanged( QString ) ), SLOT( setFilter( QString ) ) );
|
||||
connect( m_infobar, SIGNAL( autoUpdateChanged( int ) ), SLOT( autoUpdateChanged( int ) ) );
|
||||
|
||||
connect( this, SIGNAL( tomahawkLoaded() ), m_whatsHotWidget, SLOT( fetchData() ) );
|
||||
connect( this, SIGNAL( tomahawkLoaded() ), m_welcomeWidget, SLOT( loadData() ) );
|
||||
|
||||
/* connect( m_infobar, SIGNAL( flatMode() ), SLOT( setTableMode() ) );
|
||||
connect( m_infobar, SIGNAL( artistMode() ), SLOT( setTreeMode() ) );
|
||||
connect( m_infobar, SIGNAL( albumMode() ), SLOT( setAlbumMode() ) );*/
|
||||
@@ -121,6 +126,10 @@ ViewManager::ViewManager( QObject* parent )
|
||||
ViewManager::~ViewManager()
|
||||
{
|
||||
saveCurrentPlaylistSettings();
|
||||
delete m_whatsHotWidget;
|
||||
delete m_welcomeWidget;
|
||||
delete m_topLovedWidget;
|
||||
delete m_contextWidget;
|
||||
delete m_widget;
|
||||
}
|
||||
|
||||
@@ -366,7 +375,8 @@ ViewManager::showSuperCollection()
|
||||
}
|
||||
}
|
||||
|
||||
m_superCollectionModel->setTitle( tr( "All available tracks" ) );
|
||||
m_superCollectionModel->setTitle( tr( "SuperCollection" ) );
|
||||
m_superCollectionModel->setDescription( tr( "Combined libraries of all your online friends" ) );
|
||||
m_superAlbumModel->setTitle( tr( "All available albums" ) );
|
||||
|
||||
ViewPage* shown = 0;
|
||||
@@ -427,7 +437,7 @@ Tomahawk::ViewPage*
|
||||
ViewManager::showTopLovedPage()
|
||||
{
|
||||
if ( !m_topLovedWidget )
|
||||
m_topLovedWidget = new CustomPlaylistView( CustomPlaylistView::AllLovedTracks, source_ptr(), m_widget );
|
||||
m_topLovedWidget = new CustomPlaylistView( CustomPlaylistView::TopLovedTracks, source_ptr(), m_widget );
|
||||
|
||||
return show( m_topLovedWidget );
|
||||
}
|
||||
@@ -811,6 +821,15 @@ ViewManager::createDynamicPlaylist( const Tomahawk::source_ptr& src, const QVari
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ViewManager::setTomahawkLoaded()
|
||||
{
|
||||
m_loaded = true;
|
||||
emit tomahawkLoaded();
|
||||
}
|
||||
|
||||
|
||||
|
||||
ViewPage*
|
||||
ViewManager::pageForCollection( const collection_ptr& col ) const
|
||||
{
|
||||
|
@@ -106,6 +106,8 @@ public:
|
||||
// linked to the sidebar. call it right after creating the playlist
|
||||
PlaylistView* createPageForPlaylist( const Tomahawk::playlist_ptr& pl );
|
||||
|
||||
bool isTomahawkLoaded() const { return m_loaded; }
|
||||
|
||||
signals:
|
||||
void numSourcesChanged( unsigned int sources );
|
||||
void numTracksChanged( unsigned int tracks );
|
||||
@@ -130,6 +132,8 @@ signals:
|
||||
void showQueueRequested();
|
||||
void hideQueueRequested();
|
||||
|
||||
void tomahawkLoaded();
|
||||
|
||||
public slots:
|
||||
Tomahawk::ViewPage* showSuperCollection();
|
||||
Tomahawk::ViewPage* showWelcomePage();
|
||||
@@ -164,6 +168,8 @@ public slots:
|
||||
void createPlaylist( const Tomahawk::source_ptr& src, const QVariant& contents );
|
||||
void createDynamicPlaylist( const Tomahawk::source_ptr& src, const QVariant& contents );
|
||||
|
||||
void setTomahawkLoaded();
|
||||
|
||||
private slots:
|
||||
void setFilter( const QString& filter );
|
||||
void applyFilter();
|
||||
@@ -217,6 +223,8 @@ private:
|
||||
QTimer m_filterTimer;
|
||||
QString m_filter;
|
||||
|
||||
bool m_loaded;
|
||||
|
||||
static ViewManager* s_instance;
|
||||
};
|
||||
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "utils/logger.h"
|
||||
#include "tomahawksettings.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QProcess>
|
||||
|
||||
static QString s_macVolumePath = "/Volumes";
|
||||
@@ -30,40 +31,49 @@ CheckDirModel::CheckDirModel( QWidget* parent )
|
||||
: QFileSystemModel( parent )
|
||||
, m_shownVolumes( false )
|
||||
{
|
||||
#ifdef Q_WS_MAC
|
||||
#ifdef Q_OS_MAC
|
||||
m_setFilePath = QString( "%1/SetFile" ) .arg( QCoreApplication::applicationDirPath() );
|
||||
m_getFileInfoPath = QString( "%1/GetFileInfo" ).arg( QCoreApplication::applicationDirPath() );
|
||||
|
||||
QProcess* checkVolumeVisible = new QProcess( this );
|
||||
connect( checkVolumeVisible, SIGNAL( readyReadStandardOutput() ), this, SLOT( getFileInfoResult() ) );
|
||||
checkVolumeVisible->start( "GetFileInfo", QStringList() << "-aV" << s_macVolumePath );
|
||||
qDebug() << "Running GetFileInfo:" << m_getFileInfoPath << "-aV" << s_macVolumePath;
|
||||
checkVolumeVisible->start( m_getFileInfoPath, QStringList() << "-aV" << s_macVolumePath );
|
||||
#endif
|
||||
}
|
||||
|
||||
CheckDirModel::~CheckDirModel()
|
||||
{
|
||||
#ifdef Q_WS_MAC
|
||||
#ifdef Q_OS_MAC
|
||||
// reset to previous state
|
||||
if ( m_shownVolumes )
|
||||
QProcess::startDetached( QString( "SetFile -a V %1" ).arg( s_macVolumePath ) );
|
||||
QProcess::startDetached( QString( "%1 -a V %2" ).arg( m_setFilePath).arg( s_macVolumePath ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CheckDirModel::getFileInfoResult()
|
||||
{
|
||||
#ifdef Q_WS_MAC
|
||||
#ifdef Q_OS_MAC
|
||||
QProcess* p = qobject_cast< QProcess* >( sender() );
|
||||
Q_ASSERT( p );
|
||||
|
||||
QByteArray res = p->readAll().trimmed();
|
||||
qDebug() << "Got output from GetFileInfo:" << res;
|
||||
// 1 means /Volumes is hidden, so we show it while the dialog is visible
|
||||
if ( res == "1" )
|
||||
{
|
||||
// Remove the hidden flag for the /Volumnes folder so all mount points are visible in the default (Q)FileSystemModel
|
||||
QProcess* p = new QProcess( this );
|
||||
connect( p, SIGNAL( finished( int, QProcess::ExitStatus ) ), this, SLOT( volumeShowFinished() ) );
|
||||
p->start( QString( "SetFile -a v %1" ).arg( s_macVolumePath ) );
|
||||
QProcess* showProcess = new QProcess( this );
|
||||
qDebug() << "Running SetFile:" << QString( "%1 -a v %2" ).arg( m_setFilePath ).arg( s_macVolumePath );
|
||||
showProcess->start( QString( "%1 -a v %2" ).arg( m_setFilePath ).arg( s_macVolumePath ) );
|
||||
connect( showProcess, SIGNAL( readyReadStandardError() ), this, SLOT( processErrorOutput() ) );
|
||||
m_shownVolumes = true;
|
||||
|
||||
QTimer::singleShot( 500, this, SLOT( volumeShowFinished() ) );
|
||||
}
|
||||
|
||||
p->terminate();
|
||||
p->deleteLater();
|
||||
#endif
|
||||
}
|
||||
@@ -74,6 +84,16 @@ CheckDirModel::volumeShowFinished()
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CheckDirModel::processErrorOutput()
|
||||
{
|
||||
QProcess* p = qobject_cast< QProcess* >( sender() );
|
||||
Q_ASSERT( p );
|
||||
qDebug() << "Got ERROR OUTPUT from subprocess in CheckDirModel:" << p->readAll();
|
||||
}
|
||||
|
||||
|
||||
Qt::ItemFlags
|
||||
CheckDirModel::flags( const QModelIndex& index ) const
|
||||
{
|
||||
|
@@ -46,11 +46,13 @@ signals:
|
||||
private slots:
|
||||
void getFileInfoResult();
|
||||
void volumeShowFinished();
|
||||
|
||||
void processErrorOutput();
|
||||
private:
|
||||
QHash<QPersistentModelIndex, Qt::CheckState> m_checkTable;
|
||||
|
||||
bool m_shownVolumes;
|
||||
QString m_setFilePath;
|
||||
QString m_getFileInfoPath;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -61,20 +61,20 @@ AlbumInfoWidget::AlbumInfoWidget( const Tomahawk::album_ptr& album, ModelMode st
|
||||
ui->tracksView->setTreeModel( m_tracksModel );
|
||||
ui->tracksView->setRootIsDecorated( false );
|
||||
|
||||
m_pixmap = QPixmap( RESPATH "images/no-album-art-placeholder.png" ).scaledToWidth( 48, Qt::SmoothTransformation );
|
||||
m_pixmap = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, QSize( 48, 48 ) );
|
||||
|
||||
m_button = new OverlayButton( ui->tracksView );
|
||||
m_button->setCheckable( true );
|
||||
m_button->setChecked( m_tracksModel->mode() == InfoSystemMode );
|
||||
if ( m_button->isChecked() )
|
||||
m_button->setText( tr( "Click to show Super Collection Tracks" ) );
|
||||
m_button->setText( tr( "Click to show SuperCollection Tracks" ) );
|
||||
else
|
||||
m_button->setText( tr( "Click to show Official Tracks" ) );
|
||||
|
||||
m_buttonAlbums = new OverlayButton( ui->albumsView );
|
||||
m_buttonAlbums->setCheckable( true );
|
||||
m_buttonAlbums->setChecked( true );
|
||||
m_buttonAlbums->setText( tr( "Click to show Super Collection Albums" ) );
|
||||
m_buttonAlbums->setText( tr( "Click to show SuperCollection Albums" ) );
|
||||
m_buttonAlbums->show();
|
||||
|
||||
connect( m_button, SIGNAL( clicked() ), SLOT( onModeToggle() ) );
|
||||
@@ -113,7 +113,7 @@ AlbumInfoWidget::setMode( ModelMode mode )
|
||||
onModeToggle();
|
||||
|
||||
if ( mode == InfoSystemMode )
|
||||
m_button->setText( tr( "Click to show Super Collection Tracks" ) );
|
||||
m_button->setText( tr( "Click to show SuperCollection Tracks" ) );
|
||||
else
|
||||
m_button->setText( tr( "Click to show Official Tracks" ) );
|
||||
}
|
||||
@@ -131,7 +131,7 @@ void
|
||||
AlbumInfoWidget::onAlbumsModeToggle()
|
||||
{
|
||||
if ( m_buttonAlbums->isChecked() )
|
||||
m_buttonAlbums->setText( tr( "Click to show Super Collection Albums" ) );
|
||||
m_buttonAlbums->setText( tr( "Click to show SuperCollection Albums" ) );
|
||||
else
|
||||
m_buttonAlbums->setText( tr( "Click to show Official Albums" ) );
|
||||
|
||||
@@ -243,10 +243,10 @@ AlbumInfoWidget::loadAlbums( bool autoRefetch )
|
||||
void
|
||||
AlbumInfoWidget::onAlbumCoverUpdated()
|
||||
{
|
||||
if ( m_album->cover().isNull() )
|
||||
if ( m_album->cover( QSize( 0, 0 ) ).isNull() )
|
||||
return;
|
||||
|
||||
m_pixmap.loadFromData( m_album->cover() );
|
||||
m_pixmap = m_album->cover( QSize( 0, 0 ) );
|
||||
emit pixmapChanged( m_pixmap );
|
||||
}
|
||||
|
||||
|