Compare commits
20 Commits
twitterfix
...
stable
Author | SHA1 | Date | |
---|---|---|---|
|
5afce9327f | ||
|
db413b2049 | ||
|
646d2fbfd3 | ||
|
dcb46877f0 | ||
|
985b54d84d | ||
|
c6ca3d8660 | ||
|
a104e92471 | ||
|
1929804541 | ||
|
a564b3b272 | ||
|
d083528ad5 | ||
|
4d63a9462d | ||
|
5a64886b7c | ||
|
76986e8908 | ||
|
9a9a7148af | ||
|
aec7a0b140 | ||
|
eff42af593 | ||
|
ad2b54ad90 | ||
|
4e316a48ea | ||
|
87863ae7e2 | ||
|
5e439b990f |
@@ -1,9 +0,0 @@
|
||||
[main]
|
||||
host = https://www.transifex.net
|
||||
|
||||
[tomahawk.tomahawk-master]
|
||||
file_filter = lang/tomahawk_<lang>.ts
|
||||
source_file = lang/tomahawk_en.ts
|
||||
source_lang = en
|
||||
type = QT
|
||||
|
@@ -1,7 +1,10 @@
|
||||
PROJECT( tomahawk )
|
||||
CMAKE_MINIMUM_REQUIRED( VERSION 2.8.6 )
|
||||
CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )
|
||||
SET( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules" )
|
||||
CMAKE_POLICY(SET CMP0017 NEW)
|
||||
|
||||
IF( ${CMAKE_VERSION} VERSION_GREATER 2.8.3 )
|
||||
CMAKE_POLICY(SET CMP0017 NEW)
|
||||
ENDIF( ${CMAKE_VERSION} VERSION_GREATER 2.8.3 )
|
||||
|
||||
###
|
||||
### Tomahawk application info
|
||||
@@ -13,7 +16,7 @@ SET( TOMAHAWK_DESCRIPTION_SUMMARY "The social media player" )
|
||||
|
||||
SET( TOMAHAWK_VERSION_MAJOR 0 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 4 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 99 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 2 )
|
||||
|
||||
#SET( TOMAHAWK_VERSION_RC 0 )
|
||||
|
||||
@@ -23,21 +26,8 @@ add_definitions( "-fvisibility=hidden" )
|
||||
# build options
|
||||
option(BUILD_GUI "Build Tomahawk with GUI" ON)
|
||||
option(BUILD_RELEASE "Generate TOMAHAWK_VERSION without GIT info" OFF)
|
||||
option(WITH_BREAKPAD "Build with breakpad integration" ON)
|
||||
option(WITH_CRASHREPORTER "Build with CrashReporter" ON)
|
||||
option(LEGACY_KDE_INTEGRATION "Install tomahawk.protocol file, deprecated since 4.6.0" OFF)
|
||||
|
||||
IF( CMAKE_SYSTEM_PROCESSOR MATCHES "arm" )
|
||||
message(STATUS "Build of breakpad library disabled on this platform.")
|
||||
SET(WITH_BREAKPAD OFF)
|
||||
SET(WITH_CRASHREPORTER OFF)
|
||||
ENDIF()
|
||||
|
||||
# add definitions based on build options
|
||||
IF(WITH_BREAKPAD)
|
||||
message(STATUS "Build with support for breakpad.")
|
||||
ENDIF()
|
||||
|
||||
# generate version string
|
||||
|
||||
# base string used in release and unstable builds
|
||||
@@ -50,7 +40,7 @@ ENDIF()
|
||||
IF( NOT BUILD_RELEASE )
|
||||
INCLUDE( CMakeDateStamp )
|
||||
SET( TOMAHAWK_VERSION_DATE "${CMAKE_DATESTAMP_YEAR}${CMAKE_DATESTAMP_MONTH}${CMAKE_DATESTAMP_DAY}" )
|
||||
IF( TOMAHAWK_VERSION_DATE GREATER 0)
|
||||
IF( ${TOMAHAWK_VERSION_DATE} GREATER 0)
|
||||
SET( TOMAHAWK_VERSION ${TOMAHAWK_VERSION}.${TOMAHAWK_VERSION_DATE} )
|
||||
ENDIF()
|
||||
|
||||
@@ -121,17 +111,30 @@ macro_optional_find_package(QCA2)
|
||||
macro_log_feature(QCA2_FOUND "QCA2" "Provides encryption and signing functions required for Grooveshark resolver" "http://delta.affinix.com/qca/" FALSE "" "")
|
||||
|
||||
macro_optional_find_package(LibAttica)
|
||||
macro_log_feature(LIBATTICA_FOUND "libattica" "Provides support for automatic fetching and managing of resolvers from the tomahawk website" "https://projects.kde.org/projects/kdesupport/attica" TRUE "" "")
|
||||
macro_log_feature(LIBATTICA_FOUND "libattica" "Provides support for automatic fetching and managing of resolvers from the tomahawk website" "https://projects.kde.org/projects/kdesupport/attica" FALSE "" "")
|
||||
|
||||
macro_optional_find_package(QuaZip)
|
||||
macro_log_feature(QuaZip_FOUND "QuaZip" "Provides support for extracting downloaded resolvers automatically." "http://quazip.sourceforge.net/" TRUE "" "")
|
||||
macro_log_feature(QuaZip_FOUND "QuaZip" "Provides support for extracting downloaded resolvers automatically." "http://quazip.sourceforge.net/" FALSE "" "")
|
||||
|
||||
macro_optional_find_package(Jreen 1.0.5)
|
||||
macro_log_feature(JREEN_FOUND "Jreen" "Qt XMPP Library" "http://qutim.org/jreen / https://github.com/euroelessar/jreen" FALSE "" "Jreen is needed for the Jabber SIP plugin.\n")
|
||||
macro_optional_find_package(Jreen)
|
||||
macro_log_feature(LIBJREEN_FOUND "Jreen" "Qt XMPP Library" "https://github.com/euroelessar/jreen" FALSE "" "Jreen is needed for the Jabber SIP plugin.\n")
|
||||
|
||||
macro_optional_find_package(QTweetLib)
|
||||
macro_log_feature(QTWEETLIB_FOUND "QTweetLib" "Qt Twitter Library" "https://github.com/minimoog/QTweetLib" FALSE "" "QTweetLib is needed for the Twitter SIP plugin.\n")
|
||||
|
||||
|
||||
IF( NOT QuaZip_FOUND )
|
||||
add_subdirectory( ${CMAKE_SOURCE_DIR}/src/libtomahawk/thirdparty/quazip )
|
||||
SET( QuaZip_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/libtomahawk/thirdparty/quazip )
|
||||
SET( QuaZip_LIBRARY quazip )
|
||||
SET( QuaZip_LIBRARIES ${QuaZip_LIBRARY} )
|
||||
SET( QuaZip_FOUND true )
|
||||
macro_log_feature(QuaZip_FOUND "QuaZip" "Provides support for extracting downloaded resolvers automatically. Building internal copy" "http://quazip.sourceforge.net/" FALSE "" "")
|
||||
|
||||
# copy headers to build/quazip so we can use proper includes inside the code
|
||||
FILE( COPY ${CMAKE_SOURCE_DIR}/src/libtomahawk/thirdparty/quazip/quazip/ DESTINATION ${CMAKE_BINARY_DIR}/libtomahawk/thirdparty/quazip )
|
||||
ENDIF()
|
||||
|
||||
# required
|
||||
#While we distribute our own liblastfm2, don't need to look for it
|
||||
#macro_optional_find_package(LibLastFm 0.3.3)
|
||||
@@ -210,3 +213,9 @@ ADD_SUBDIRECTORY( src/libtomahawk )
|
||||
SET( TOMAHAWK_LIBRARIES tomahawklib )
|
||||
ADD_SUBDIRECTORY( src )
|
||||
ADD_SUBDIRECTORY( admin )
|
||||
|
||||
IF( BUILD_GUI )
|
||||
IF( NOT DISABLE_CRASHREPORTER )
|
||||
ADD_SUBDIRECTORY( src/breakpad/CrashReporter )
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
@@ -1,99 +0,0 @@
|
||||
MACRO(PARSE_ARGUMENTS prefix arg_names option_names)
|
||||
SET(DEFAULT_ARGS)
|
||||
FOREACH(arg_name ${arg_names})
|
||||
SET(${prefix}_${arg_name})
|
||||
ENDFOREACH(arg_name)
|
||||
FOREACH(option ${option_names})
|
||||
SET(${prefix}_${option} FALSE)
|
||||
ENDFOREACH(option)
|
||||
|
||||
SET(current_arg_name DEFAULT_ARGS)
|
||||
SET(current_arg_list)
|
||||
FOREACH(arg ${ARGN})
|
||||
SET(larg_names ${arg_names})
|
||||
LIST(FIND larg_names "${arg}" is_arg_name)
|
||||
IF (is_arg_name GREATER -1)
|
||||
SET(${prefix}_${current_arg_name} ${current_arg_list})
|
||||
SET(current_arg_name ${arg})
|
||||
SET(current_arg_list)
|
||||
ELSE (is_arg_name GREATER -1)
|
||||
SET(loption_names ${option_names})
|
||||
LIST(FIND loption_names "${arg}" is_option)
|
||||
IF (is_option GREATER -1)
|
||||
SET(${prefix}_${arg} TRUE)
|
||||
ELSE (is_option GREATER -1)
|
||||
SET(current_arg_list ${current_arg_list} ${arg})
|
||||
ENDIF (is_option GREATER -1)
|
||||
ENDIF (is_arg_name GREATER -1)
|
||||
ENDFOREACH(arg)
|
||||
SET(${prefix}_${current_arg_name} ${current_arg_list})
|
||||
ENDMACRO(PARSE_ARGUMENTS)
|
||||
|
||||
MACRO(CAR var)
|
||||
SET(${var} ${ARGV1})
|
||||
ENDMACRO(CAR)
|
||||
|
||||
MACRO(CDR var junk)
|
||||
SET(${var} ${ARGN})
|
||||
ENDMACRO(CDR)
|
||||
|
||||
|
||||
macro(add_tomahawk_plugin)
|
||||
parse_arguments(PLUGIN
|
||||
"SOURCES;UI;LINK_LIBRARIES;TYPE;EXPORT_MACRO;COMPILE_DEFINITIONS"
|
||||
"NO_INSTALL"
|
||||
${ARGN}
|
||||
)
|
||||
car(PLUGIN_NAME ${PLUGIN_DEFAULT_ARGS})
|
||||
|
||||
# message("*** Arguments for ${PLUGIN_NAME}")
|
||||
# message("Sources: ${PLUGIN_SOURCES}")
|
||||
# message("Link libraries: ${PLUGIN_LINK_LIBRARIES}")
|
||||
# message("UI: ${PLUGIN_UI}")
|
||||
# message("TYPE: ${PLUGIN_TYPE}")
|
||||
# message("EXPORT_MACRO: ${PLUGIN_EXPORT_MACRO}")
|
||||
|
||||
# create target name once for convenience
|
||||
set(target "tomahawk_${PLUGIN_TYPE}_${PLUGIN_NAME}")
|
||||
|
||||
# qt stuff
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
if(PLUGIN_UI)
|
||||
qt4_wrap_ui(PLUGIN_UI_SOURCES ${PLUGIN_UI})
|
||||
list(APPEND PLUGIN_SOURCES ${PLUGIN_UI_SOURCES})
|
||||
endif()
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/resources.qrc")
|
||||
qt4_add_resources(PLUGIN_RC_SOURCES "resources.qrc")
|
||||
list(APPEND PLUGIN_SOURCES ${PLUGIN_RC_SOURCES})
|
||||
unset(PLUGIN_RC_SOURCES)
|
||||
endif()
|
||||
|
||||
# add target
|
||||
add_library(${target} MODULE ${PLUGIN_SOURCES})
|
||||
|
||||
# definitions - can this be moved into set_target_properties below?
|
||||
add_definitions(${QT_DEFINITIONS})
|
||||
set_target_properties(${target} PROPERTIES AUTOMOC TRUE COMPILE_DEFINITIONS ${PLUGIN_EXPORT_MACRO})
|
||||
if(PLUGIN_COMPILE_DEFINITIONS)
|
||||
# Dear CMake, i hate you! Sincerely, domme
|
||||
# At least in CMake 2.8.8, you CANNOT set more than one COMPILE_DEFINITIONS value
|
||||
# only takes the first one if called multiple times or bails out with wrong number of arguments
|
||||
# when passing in a list, thus i redefine the export macro here in hope it won't mess up other targets
|
||||
add_definitions( "-D${PLUGIN_EXPORT_MACRO}" )
|
||||
|
||||
set_target_properties(${target} PROPERTIES COMPILE_DEFINITIONS ${PLUGIN_COMPILE_DEFINITIONS})
|
||||
endif()
|
||||
|
||||
# add link targets
|
||||
target_link_libraries(${target} tomahawklib)
|
||||
if(PLUGIN_LINK_LIBRARIES)
|
||||
target_link_libraries(${target} ${PLUGIN_LINK_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# make installation optional, maybe useful for dummy plugins one day
|
||||
if(NOT PLUGIN_NO_INSTALL)
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS ${target} DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
endmacro()
|
@@ -5,32 +5,40 @@
|
||||
# LIBJREEN_LIBRARY, the path to libjreen
|
||||
# LIBJREEN_FOUND, whether libjreen was found
|
||||
|
||||
FIND_PACKAGE(PkgConfig QUIET)
|
||||
PKG_CHECK_MODULES(PC_JREEN QUIET libjreen)
|
||||
|
||||
FIND_PATH(JREEN_INCLUDE_DIR NAMES jreen/jreen.h
|
||||
HINTS
|
||||
${PC_JREEN_INCLUDEDIR}
|
||||
${PC_JREEN_INCLUDE_DIRS}
|
||||
${CMAKE_INSTALL_INCLUDEDIR}
|
||||
${KDE4_INCLUDE_DIR}
|
||||
find_path(LIBJREEN_INCLUDE_DIR NAMES jreen/jreen.h
|
||||
HINTS
|
||||
~/usr/include
|
||||
/opt/local/include
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/kde4/include
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
${KDE4_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
FIND_LIBRARY(JREEN_LIBRARIES NAMES jreen
|
||||
HINTS
|
||||
${PC_JREEN_LIBDIR}
|
||||
${PC_JREEN_LIBRARY_DIRS}
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
${KDE4_LIB_DIR}
|
||||
find_library( LIBJREEN_LIBRARY NAMES jreen
|
||||
PATHS
|
||||
~/usr/lib
|
||||
/opt/local/lib
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
/usr/local/lib
|
||||
/opt/kde4/lib
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
${CMAKE_INSTALL_PREFIX}/lib64
|
||||
${KDE4_LIB_DIR}
|
||||
)
|
||||
|
||||
IF(JREEN_LIBRARIES AND JREEN_INCLUDE_DIR AND NOT PC_JREEN_VERSION)
|
||||
MESSAGE(WARNING "You don't have pkg-config and so the Jreen version check does not work!")
|
||||
ENDIF()
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Jreen
|
||||
REQUIRED_VARS JREEN_LIBRARIES JREEN_INCLUDE_DIR
|
||||
VERSION_VAR PC_JREEN_VERSION)
|
||||
if(LIBJREEN_INCLUDE_DIR AND LIBJREEN_LIBRARY)
|
||||
set(LIBJREEN_FOUND TRUE)
|
||||
message(STATUS "Found libjreen: ${LIBJREEN_INCLUDE_DIR}, ${LIBJREEN_LIBRARY}")
|
||||
else(LIBJREEN_INCLUDE_DIR AND LIBJREEN_LIBRARY)
|
||||
set(LIBJREEN_FOUND FALSE)
|
||||
if (LIBJREEN_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could NOT find required package libjreen")
|
||||
endif(LIBJREEN_FIND_REQUIRED)
|
||||
endif(LIBJREEN_INCLUDE_DIR AND LIBJREEN_LIBRARY)
|
||||
|
||||
MARK_AS_ADVANCED(JREEN_INCLUDE_DIR JREEN_LIBRARIES)
|
||||
mark_as_advanced(LIBJREEN_INCLUDE_DIR LIBJREEN_LIBRARY)
|
||||
|
@@ -38,9 +38,7 @@ else (QCA2_INCLUDE_DIR AND QCA2_LIBRARIES)
|
||||
|
||||
find_path(QCA2_INCLUDE_DIR qca.h
|
||||
HINTS ${PC_QCA2_INCLUDEDIR} ${PC_QCA2_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES QtCrypto
|
||||
PATHS /usr/local/lib/qca.framework/Headers/
|
||||
)
|
||||
PATH_SUFFIXES QtCrypto)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(QCA2 DEFAULT_MSG QCA2_LIBRARIES QCA2_INCLUDE_DIR)
|
||||
|
@@ -280,8 +280,7 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
File "${INSTALL_PATH}\bin\libtomahawk_portfwd.dll"
|
||||
File "${INSTALL_PATH}\bin\libtomahawk_lastfm2.dll"
|
||||
File "${INSTALL_PATH}\bin\libtomahawklib.dll"
|
||||
; plugins
|
||||
File "${INSTALL_PATH}\lib\libtomahawk_*_*.dll"
|
||||
File "${INSTALL_PATH}\lib\libtomahawk_sip*.dll"
|
||||
!endif
|
||||
!ifndef INSTALL_PATH
|
||||
;Main executable.
|
||||
@@ -294,8 +293,7 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
|
||||
File "${BUILD_PATH}\libqxtweb-standalone.dll"
|
||||
File "${BUILD_PATH}\libtomahawk_portfwd.dll"
|
||||
File "${BUILD_PATH}\libtomahawk_lastfm2.dll"
|
||||
; plugins
|
||||
File "${BUILD_PATH}\libtomahawk_*_*.dll"
|
||||
File "${BUILD_PATH}\libtomahawk_sip*.dll"
|
||||
!endif
|
||||
|
||||
;License & release notes.
|
||||
|
13
ChangeLog
@@ -1,15 +1,6 @@
|
||||
Version 0.5.0:
|
||||
* Added "Stop playback after this track" context menu items.
|
||||
* You can now import your entire Last.fm playback history into Tomahawk.
|
||||
* Support for multimedia keys (Play, Pause, Next etc.) on Windows & Linux.
|
||||
* When listening privately scrobbling to Last.fm is now disabled.
|
||||
* Added a toolbar with page back / forward buttons and the global search.
|
||||
* New grid view with direct playback controls.
|
||||
* Added a track page showing a song's lyrics and other similar tracks.
|
||||
* Separate Loved Tracks and Recently Played views per source.
|
||||
|
||||
Version 0.4.2:
|
||||
* Fix ZeroConf protocol showing IP addresses instead of host names.
|
||||
Sometimes. Full fix coming later.
|
||||
* Updated translations for various languages.
|
||||
* Resuming playback restores correct volume settings.
|
||||
* Reduced CPU usage during playback.
|
||||
@@ -31,7 +22,7 @@ Version 0.4.0:
|
||||
* 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.
|
||||
* 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.
|
||||
|
8
README
@@ -13,7 +13,7 @@ Compiling Tomahawk
|
||||
|
||||
Detailed building instructions for Ubuntu
|
||||
-----------------------------------------
|
||||
See: http://wiki.tomahawk-player.org/mediawiki/index.php/Building_Ubuntu_Binary_on_Precise_(12.04)
|
||||
See: http://wiki.tomahawk-player.org/mediawiki/index.php/Building_Ubuntu_Binary_on_Maverick_(10.10)
|
||||
|
||||
Detailed building instructions for OS X
|
||||
---------------------------------------
|
||||
@@ -27,7 +27,7 @@ Doxygen Documentation
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
CMake 2.8.6 - http://www.cmake.org/
|
||||
CMake 2.8.0 - http://www.cmake.org/
|
||||
Qt 4.7.0 - http://qt.nokia.com/
|
||||
QJson 0.7.1 - http://qjson.sourceforge.net/
|
||||
SQLite 3.6.22 - http://www.sqlite.org/
|
||||
@@ -38,9 +38,9 @@ Dependencies
|
||||
|
||||
The following dependencies are optional, but recommended:
|
||||
|
||||
Attica 0.3.0 - ftp://ftp.kde.org/pub/kde/stable/attica/
|
||||
Attica 0.2.0 - ftp://ftp.kde.org/pub/kde/stable/attica/
|
||||
QuaZip 0.4.3 - http://quazip.sourceforge.net/
|
||||
Jreen 1.0.5 - http://qutim.org/jreen / https://github.com/euroelessar/jreen
|
||||
Jreen 1.0.3 - https://github.com/euroelessar/jreen
|
||||
QTweetLib 0.5.0 - https://github.com/minimoog/QTweetLib
|
||||
|
||||
Third party libraries that we ship with our source:
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/python
|
||||
# This file is part of Tomahawk.
|
||||
# It was inspired in large part by the macdeploy script in Clementine.
|
||||
|
||||
# This file is part of Clementine.
|
||||
#
|
||||
# Clementine is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -199,10 +199,11 @@ QT_PLUGINS = [
|
||||
]
|
||||
|
||||
TOMAHAWK_PLUGINS = [
|
||||
'libtomahawk_account_xmpp.so',
|
||||
'libtomahawk_account_google.so',
|
||||
'libtomahawk_account_twitter.so',
|
||||
'libtomahawk_account_zeroconf.so',
|
||||
'libtomahawk_sipjabber.dylib',
|
||||
'libtomahawk_sipgoogle.dylib',
|
||||
'libtomahawk_siptwitter.dylib',
|
||||
'libtomahawk_sipzeroconf.dylib',
|
||||
'libtomahawk_qtweetlib.dylib',
|
||||
]
|
||||
|
||||
QT_PLUGINS_SEARCH_PATH=[
|
||||
@@ -495,6 +496,11 @@ for plugin in VLC_PLUGINS:
|
||||
for plugin in TOMAHAWK_PLUGINS:
|
||||
FixPlugin(plugin, '../MacOS')
|
||||
|
||||
try:
|
||||
FixPlugin('spotify_tomahawkresolver', '../MacOS')
|
||||
except:
|
||||
print 'Failed to find spotify resolver'
|
||||
|
||||
try:
|
||||
FixPlugin('tomahawk_crash_reporter', '../MacOS')
|
||||
except:
|
||||
|
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 356 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 8.3 KiB |
BIN
data/images/avatar-dude-plus.png
Normal file
After Width: | Height: | Size: 339 B |
BIN
data/images/avatar-dude.png
Normal file
After Width: | Height: | Size: 286 B |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 4.4 KiB |
BIN
data/images/collapse.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 68 KiB |
BIN
data/images/create-playlist.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
BIN
data/images/home.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 5.2 KiB |
BIN
data/images/post.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@@ -1,20 +0,0 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIDOzCCAi0GByqGSM44BAEwggIgAoIBAQDRltnNbKWFroVCsG1nTSdlTDmo7fjl
|
||||
tgOuQ0YB2s0a1bcqgQ5YJRE59pFvF/z2pkHEHdyBA6USd9N7/T9lolwNcJoByJpO
|
||||
MobUNs04elqZXliriaAdoSb2g6ZpxiedppbbyNP/BlK6o+zpyn0LVYXDI/OwJFzS
|
||||
xjGXM+rBEWdUJnogZxV31gF9W3yD1Quz6icBulT9V/Soo6me9Mc60ooKSYj4Zgqd
|
||||
3ln8tG90RFnWfbb0nbrITvR3ll6XXLfn081tjhymcXqHcgvaaqcmpKWL6ZWwX1mH
|
||||
3t1pImnif/tSSZPG21KGE3FtuQ/+YFo19apQ6U6l8kaSFxqcDLAYzBy9AhUA/QfN
|
||||
8WEIvzOEZ9uSWT7lYy64mUkCggEABsUmcs3kwjrmszIAAmPIowA0DBrxWZL03JBV
|
||||
bDKT6tNHZaFFlCufVSjiL1EFZjRARC16OWYaDcElUsZYFMcsNIIa8LyDQaq6+SSm
|
||||
quhMO5heeJiYPrutDiJzbJr0+HoY77Ll+Q4/cEkl0UAN4Ovp18WKwaq6GpHAvBnv
|
||||
71LunLGAKsVb5joXBQ8In6zQkibJhgiBJwzLK90/j0OTiDaaOwM3PsAegORBVlVE
|
||||
TAk4AQmawmF8nBGLzTyKXl83J571ku1Mm2JTl16jMYziKARKXYBmkcP1at0YddVK
|
||||
WWpAwRKSxOucVJYfV58JqmjZqst8BBeH6esQKr5dklUvvDMaEwOCAQYAAoIBAQCw
|
||||
5mo+8/R3S9cNYg9o8JNJGdSbMhSkurILHh9WNElsIC3RNtPcpijmAnWtXTVDhe6w
|
||||
77wLj37tUuFGbsu2qPXtZoup35emf9DDshZ5w5UOclPaZ9HYjlC1H64c6d66Rllk
|
||||
fY6FRDv9qVfjT84APbvMDrk6csJ5YHxFPDaqeQaFB0nxFiCMVwjEx+ZSvQNK1jJ2
|
||||
o2gtuOvSPVSphsMeJ72DDNxO+SRRVnOmWaxg9rlmFuGle6Z+UJ2FItfmPEvhSBMY
|
||||
hzndUbC7Wi4sIpBzbm9O5MiPYMv0VmN+0t1156EiC9uR4f7AKH2S94dnQob/YeY0
|
||||
jMH+XxU/wzGUCmsOx1lx
|
||||
-----END PUBLIC KEY-----
|
3819
lang/tomahawk_ar.ts
1879
lang/tomahawk_bg.ts
3838
lang/tomahawk_ca.ts
1904
lang/tomahawk_de.ts
1732
lang/tomahawk_en.ts
2110
lang/tomahawk_es.ts
3843
lang/tomahawk_fr.ts
@@ -1,14 +1,11 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/lang">
|
||||
<file>tomahawk_en.qm</file>
|
||||
<file>tomahawk_bg.qm</file>
|
||||
<file>tomahawk_de.qm</file>
|
||||
<file>tomahawk_fr.qm</file>
|
||||
<file>tomahawk_sv.qm</file>
|
||||
<file>tomahawk_es.qm</file>
|
||||
<file>tomahawk_bg.qm</file>
|
||||
<file>tomahawk_pl.qm</file>
|
||||
<file>tomahawk_pt_BR.qm</file>
|
||||
<file>tomahawk_ru.qm</file>
|
||||
<file>tomahawk_es.qm</file>
|
||||
<file>tomahawk_sv.qm</file>
|
||||
<file>tomahawk_ja.qm</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
3817
lang/tomahawk_ja.ts
1935
lang/tomahawk_pl.ts
3832
lang/tomahawk_ru.ts
1727
lang/tomahawk_sv.ts
3815
lang/tomahawk_tr.ts
@@ -1,5 +1,7 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>data/images/avatar-dude-plus.png</file>
|
||||
<file>data/images/avatar-dude.png</file>
|
||||
<file>data/images/back-pressed.png</file>
|
||||
<file>data/images/back-rest.png</file>
|
||||
<file>data/images/filter.png</file>
|
||||
@@ -7,8 +9,6 @@
|
||||
<file>data/images/not-loved.png</file>
|
||||
<file>data/images/no-album-art-placeholder.png</file>
|
||||
<file>data/images/no-artist-image-placeholder.png</file>
|
||||
<file>data/images/artist-placeholder-grid.png</file>
|
||||
<file>data/images/album-placeholder-grid.png</file>
|
||||
<file>data/images/track-placeholder.png</file>
|
||||
<file>data/images/now-playing-panel.png</file>
|
||||
<file>data/images/now-playing-speaker.png</file>
|
||||
@@ -66,10 +66,12 @@
|
||||
<file>data/images/echonest_logo.png</file>
|
||||
<file>data/images/loading-animation.gif</file>
|
||||
<file>data/images/info.png</file>
|
||||
<file>data/images/home.png</file>
|
||||
<file>data/images/back.png</file>
|
||||
<file>data/images/forward.png</file>
|
||||
<file>data/images/music-icon.png</file>
|
||||
<file>data/images/configure.png</file>
|
||||
<file>data/images/create-playlist.png</file>
|
||||
<file>data/images/private-listening.png</file>
|
||||
<file>data/images/add.png</file>
|
||||
<file>data/images/recently-played.png</file>
|
||||
@@ -85,7 +87,6 @@
|
||||
<file>data/images/station.png</file>
|
||||
<file>data/images/new-additions.png</file>
|
||||
<file>data/images/charts.png</file>
|
||||
<file>data/images/new-releases.png</file>
|
||||
<file>data/images/loved_playlist.png</file>
|
||||
<file>data/images/dashboard.png</file>
|
||||
<file>data/images/artist-icon.png</file>
|
||||
@@ -133,14 +134,7 @@
|
||||
<file>data/images/no-album-no-case.png</file>
|
||||
<file>data/images/rdio.png</file>
|
||||
<file>data/images/grooveshark.png</file>
|
||||
<file>data/images/lastfm-icon.png</file>
|
||||
<file>data/images/spotifycore-logo.png</file>
|
||||
<file>data/images/playlist-header-tiled.png</file>
|
||||
<file>data/images/share.png</file>
|
||||
<file>data/sql/dbmigrate-27_to_28.sql</file>
|
||||
<file>data/images/process-stop.png</file>
|
||||
<file>data/icons/tomahawk-icon-128x128-grayscale.png</file>
|
||||
<file>data/images/collection.png</file>
|
||||
<file>data/misc/tomahawk_pubkey.pem</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -1,784 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://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
|
||||
* 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 "AccountDelegate.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "accounts/AccountModel.h"
|
||||
#include "accounts/Account.h"
|
||||
#include "accounts/AccountManager.h"
|
||||
|
||||
#include "utils/TomahawkUtils.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/AnimatedSpinner.h"
|
||||
#include "utils/Closure.h"
|
||||
#include "Source.h"
|
||||
|
||||
#define CHILD_ACCOUNT_HEIGHT 24
|
||||
|
||||
#define PADDING 4
|
||||
#define PADDING_BETWEEN_STARS 2
|
||||
#define STAR_SIZE 12
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#define ROW_HEIGHT_MULTIPLIER 4.9
|
||||
#else
|
||||
#define ROW_HEIGHT_MULTIPLIER 5.7
|
||||
#endif
|
||||
|
||||
#define ICONSIZE 40
|
||||
#define WRENCH_SIZE 24
|
||||
#define SMALL_WRENCH_SIZE 16
|
||||
#define STATUS_ICON_SIZE 13
|
||||
#define CHECK_LEFT_EDGE 8
|
||||
#define REMOVE_ICON_SIZE 12
|
||||
|
||||
using namespace Tomahawk;
|
||||
using namespace Accounts;
|
||||
|
||||
AccountDelegate::AccountDelegate( QObject* parent )
|
||||
: QStyledItemDelegate ( parent )
|
||||
, m_accountRowHeight( -1 )
|
||||
, m_model( 0 )
|
||||
{
|
||||
|
||||
m_defaultCover.load( RESPATH "images/sipplugin-online.png" );
|
||||
m_ratingStarPositive.load( RESPATH "images/starred.png" );
|
||||
m_ratingStarNegative.load( RESPATH "images/star-unstarred.png" );
|
||||
m_onHoverStar.load( RESPATH "images/star-hover.png" );
|
||||
m_onlineIcon.load( RESPATH "images/sipplugin-online.png" );
|
||||
m_offlineIcon.load( RESPATH "images/sipplugin-offline.png" );
|
||||
m_removeIcon.load( RESPATH "images/list-remove.png" );
|
||||
|
||||
m_ratingStarPositive = m_ratingStarPositive.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_ratingStarNegative = m_ratingStarNegative.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_onlineIcon = m_onlineIcon.scaled( STATUS_ICON_SIZE, STATUS_ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_offlineIcon = m_offlineIcon.scaled( STATUS_ICON_SIZE, STATUS_ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_onHoverStar = m_onHoverStar.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_removeIcon = m_removeIcon.scaled( REMOVE_ICON_SIZE, REMOVE_ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
m_defaultCover = m_defaultCover.scaled( ICONSIZE, ICONSIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
}
|
||||
|
||||
|
||||
QSize
|
||||
AccountDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
AccountModel::RowType rowType = static_cast< AccountModel::RowType >( index.data( AccountModel::RowTypeRole ).toInt() );
|
||||
if ( m_accountRowHeight < 0 )
|
||||
{
|
||||
// Haven't calculated normal item height yet, do it once and save it
|
||||
QStyleOptionViewItemV4 opt( option );
|
||||
initStyleOption( &opt, index );
|
||||
m_accountRowHeight = ROW_HEIGHT_MULTIPLIER * opt.fontMetrics.height();
|
||||
}
|
||||
|
||||
if ( rowType == AccountModel::TopLevelAccount || rowType == AccountModel::UniqueFactory || rowType == AccountModel::CustomAccount )
|
||||
{
|
||||
|
||||
return QSize( 200, m_accountRowHeight );
|
||||
}
|
||||
else if ( rowType == AccountModel::TopLevelFactory )
|
||||
{
|
||||
// Make more space for each account we have to show.
|
||||
AccountFactory* fac = qobject_cast< AccountFactory* >( index.data( AccountModel::AccountData ).value< QObject* >() );
|
||||
if ( fac->isUnique() )
|
||||
return QSize( 200, m_accountRowHeight );
|
||||
|
||||
const QList< Account* > accts = index.data( AccountModel::ChildrenOfFactoryRole ).value< QList< Tomahawk::Accounts::Account* > >();
|
||||
const QSize s = QSize( 200, m_accountRowHeight + 12 * accts.size()-1 );
|
||||
|
||||
if ( s != m_sizeHints[ index ] )
|
||||
const_cast< AccountDelegate* >( this )->sizeHintChanged( index ); // FU KTHBBQ
|
||||
|
||||
m_sizeHints[ index ] = s;
|
||||
return s;
|
||||
}
|
||||
|
||||
return QSize();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
QStyleOptionViewItemV4 opt = option;
|
||||
initStyleOption( &opt, index );
|
||||
|
||||
// draw the background
|
||||
const QWidget* w = opt.widget;
|
||||
QStyle* style = w ? w->style() : QApplication::style();
|
||||
style->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, w );
|
||||
|
||||
painter->setRenderHint( QPainter::Antialiasing );
|
||||
|
||||
if ( m_model == 0 || m_model != index.model() )
|
||||
m_model = const_cast<QAbstractItemModel*>( index.model() );
|
||||
|
||||
QFont titleFont = opt.font;
|
||||
titleFont.setBold( true );
|
||||
titleFont.setPointSize( titleFont.pointSize() + 2 );
|
||||
const QFontMetrics titleMetrics( titleFont );
|
||||
|
||||
QFont authorFont = opt.font;
|
||||
authorFont.setItalic( true );
|
||||
authorFont.setPointSize( authorFont.pointSize() - 1 );
|
||||
#ifdef Q_OS_MAC
|
||||
authorFont.setPointSize( authorFont.pointSize() - 1 );
|
||||
#endif
|
||||
const QFontMetrics authorMetrics( authorFont );
|
||||
|
||||
QFont descFont = authorFont;
|
||||
descFont.setItalic( false );
|
||||
const QFontMetrics descMetrics( descFont );
|
||||
|
||||
QFont installFont = opt.font;
|
||||
installFont.setPointSize( installFont.pointSize() - 1 );
|
||||
const QFontMetrics installMetrics( descFont );
|
||||
|
||||
const int height = opt.rect.height();
|
||||
const int center = height / 2 + opt.rect.top();
|
||||
|
||||
// Left account enable/disable checkbox
|
||||
const AccountModel::RowType rowType = static_cast< AccountModel::RowType >( index.data( AccountModel::RowTypeRole ).toInt() );
|
||||
int leftEdge = PADDING;
|
||||
// draw checkbox first
|
||||
const int checkboxYPos = ( center ) - ( WRENCH_SIZE / 2 );
|
||||
QRect checkRect = QRect( leftEdge, checkboxYPos, WRENCH_SIZE, WRENCH_SIZE );
|
||||
QStyleOptionViewItemV4 opt2 = opt;
|
||||
opt2.rect = checkRect;
|
||||
|
||||
if ( !m_loadingSpinners.contains( index ) )
|
||||
{
|
||||
drawCheckBox( opt2, painter, opt.widget );
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_ASSERT( m_loadingSpinners[ index ] );
|
||||
if ( m_loadingSpinners[ index ] )
|
||||
{
|
||||
const QPixmap pm = m_loadingSpinners[index]->pixmap();
|
||||
painter->drawPixmap( checkRect, pm );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
leftEdge += WRENCH_SIZE + PADDING / 2;
|
||||
|
||||
// Pixmap
|
||||
QPixmap p = index.data( Qt::DecorationRole ).value< QPixmap >();
|
||||
QRect pixmapRect( leftEdge + PADDING, center - ICONSIZE/2, ICONSIZE, ICONSIZE );
|
||||
if ( p.isNull() ) // default image... TODO
|
||||
p = m_defaultCover;
|
||||
else
|
||||
p = p.scaled( pixmapRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
painter->drawPixmap( pixmapRect, p );
|
||||
|
||||
// Draw config wrench if there is one
|
||||
const bool hasConfigWrench = index.data( AccountModel::HasConfig ).toBool();
|
||||
int rightEdge = opt.rect.right();
|
||||
m_cachedConfigRects[ index ] = QRect();
|
||||
if ( hasConfigWrench )
|
||||
{
|
||||
const QRect confRect = QRect( rightEdge - 2*PADDING - WRENCH_SIZE, center - WRENCH_SIZE / 2, WRENCH_SIZE, WRENCH_SIZE );
|
||||
QStyleOptionToolButton topt;
|
||||
topt.rect = confRect;
|
||||
topt.pos = confRect.topLeft();
|
||||
|
||||
drawConfigWrench( painter, opt, topt );
|
||||
|
||||
m_cachedConfigRects[ index ] = confRect;
|
||||
rightEdge = confRect.left();
|
||||
|
||||
}
|
||||
|
||||
// Draw individual accounts and add account button for factories
|
||||
m_cachedButtonRects[ index ] = QRect();
|
||||
|
||||
bool canDelete = index.data( AccountModel::CanDeleteRole ) .toBool();
|
||||
if ( rowType == Tomahawk::Accounts::AccountModel::TopLevelFactory )
|
||||
{
|
||||
const QList< Account* > accts = index.data( AccountModel::ChildrenOfFactoryRole ).value< QList< Tomahawk::Accounts::Account* > >();
|
||||
|
||||
QRect btnRect;
|
||||
const QString btnText = tr( "Add Account" );
|
||||
const int btnWidth = installMetrics.width( btnText ) + 2*PADDING;
|
||||
|
||||
if ( accts.isEmpty() )
|
||||
{
|
||||
Q_ASSERT( !hasConfigWrench );
|
||||
|
||||
// Draw button in center of row
|
||||
btnRect= QRect( opt.rect.right() - PADDING - btnWidth, center - ( installMetrics.height() + 4 ) / 2, btnWidth, installMetrics.height() + 2*PADDING );
|
||||
rightEdge = btnRect.left();
|
||||
}
|
||||
else
|
||||
{
|
||||
painter->save();
|
||||
painter->setFont( installFont );
|
||||
rightEdge = drawAccountList( painter, opt, accts, rightEdge );
|
||||
painter->restore();
|
||||
|
||||
btnRect = QRect( opt.rect.right() - PADDING - btnWidth, opt.rect.bottom() - installMetrics.height() - 3*PADDING, btnWidth, installMetrics.height() + 2*PADDING );
|
||||
#ifdef Q_WS_MAC
|
||||
btnRect.adjust( -4, 0, 4, 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
leftEdge = btnRect.left();
|
||||
m_cachedButtonRects[ index ] = btnRect;
|
||||
|
||||
painter->save();
|
||||
painter->setPen( opt.palette.color( QPalette::Active, QPalette::AlternateBase ) );
|
||||
|
||||
drawRoundedButton( painter, btnRect );
|
||||
|
||||
painter->setFont( installFont );
|
||||
painter->drawText( btnRect, Qt::AlignCenter, btnText );
|
||||
painter->restore();
|
||||
}
|
||||
else if ( rowType == AccountModel::UniqueFactory )
|
||||
{
|
||||
// Display as usual, except if it has an account, show the status.
|
||||
const QList< Account* > accts = index.data( AccountModel::ChildrenOfFactoryRole ).value< QList< Tomahawk::Accounts::Account* > >();
|
||||
if ( !accts.isEmpty() )
|
||||
{
|
||||
Q_ASSERT( accts.size() == 1 );
|
||||
|
||||
rightEdge = drawStatus( painter, QPointF( rightEdge, center - painter->fontMetrics().height()/2 ), accts.first(), true );
|
||||
}
|
||||
|
||||
}
|
||||
else if ( canDelete )
|
||||
{
|
||||
const QString btnText = tr( "Remove Account" );
|
||||
const int btnWidth = installMetrics.width( btnText ) + 2*PADDING;
|
||||
QRect btnRect;
|
||||
|
||||
if ( hasConfigWrench )
|
||||
btnRect = QRect( opt.rect.right() - PADDING - btnWidth, opt.rect.bottom() - installMetrics.height() - 3*PADDING, btnWidth, installMetrics.height() + 2*PADDING );
|
||||
else
|
||||
btnRect = QRect( opt.rect.right() - PADDING - btnWidth, center - ( installMetrics.height() + 4 ) / 2, btnWidth, installMetrics.height() + 2*PADDING );
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
btnRect.adjust( -4, 2, 4, -2 );
|
||||
#endif
|
||||
leftEdge = btnRect.left();
|
||||
m_cachedButtonRects[ index ] = btnRect;
|
||||
|
||||
painter->save();
|
||||
painter->setPen( opt.palette.color( QPalette::Active, QPalette::AlternateBase ) );
|
||||
|
||||
drawRoundedButton( painter, btnRect, true );
|
||||
|
||||
painter->setFont( installFont );
|
||||
painter->drawText( btnRect, Qt::AlignCenter, btnText );
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
// Draw the title and description
|
||||
// title
|
||||
QString title = index.data( Qt::DisplayRole ).toString();
|
||||
const int rightTitleEdge = rightEdge - PADDING;
|
||||
const int leftTitleEdge = pixmapRect.right() + PADDING;
|
||||
painter->setFont( titleFont );
|
||||
QRect textRect;
|
||||
const bool canRate = index.data( AccountModel::CanRateRole ).toBool();
|
||||
if ( canRate )
|
||||
{
|
||||
textRect = QRect( leftTitleEdge, opt.rect.top() + PADDING, rightTitleEdge - leftTitleEdge, painter->fontMetrics().height() );
|
||||
}
|
||||
else
|
||||
{
|
||||
textRect = QRect( leftTitleEdge, opt.rect.top() + PADDING, rightTitleEdge - leftTitleEdge, center - opt.rect.top() - PADDING );
|
||||
}
|
||||
painter->drawText( textRect, Qt::AlignVCenter | Qt::AlignLeft, title );
|
||||
|
||||
// author
|
||||
QString author = index.data( AccountModel::AuthorRole ).toString();
|
||||
int runningBottom = textRect.bottom();
|
||||
if ( !author.isEmpty() && canRate )
|
||||
{
|
||||
painter->save();
|
||||
painter->setFont( authorFont );
|
||||
painter->setPen( QColor( Qt::gray ).darker( 150 ) );
|
||||
const int authorWidth = authorMetrics.width( author );
|
||||
const QRect authorRect( textRect.left(), textRect.bottom() + PADDING/2, authorWidth + 6, authorMetrics.height() );
|
||||
painter->drawText( authorRect, Qt::AlignLeft | Qt::AlignVCenter, author );
|
||||
painter->restore();
|
||||
|
||||
runningBottom = authorRect.bottom();
|
||||
}
|
||||
|
||||
// description
|
||||
QString desc = index.data( AccountModel::DescriptionRole ).toString();
|
||||
const int descWidth = rightEdge - leftTitleEdge - PADDING;
|
||||
painter->setFont( descFont );
|
||||
const QRect descRect( leftTitleEdge, runningBottom + PADDING, descWidth, painter->fontMetrics().height() );
|
||||
desc = painter->fontMetrics().elidedText( desc, Qt::ElideRight, descWidth );
|
||||
painter->drawText( descRect, Qt::AlignLeft | Qt::TextWordWrap | Qt::AlignTop, desc );
|
||||
runningBottom = descRect.bottom();
|
||||
|
||||
if ( index.data( AccountModel::CanRateRole ).toBool() )
|
||||
{
|
||||
// rating stars
|
||||
const int rating = index.data( AccountModel::RatingRole ).toInt();
|
||||
|
||||
// int runningEdge = opt.rect.right() - 2*PADDING - ratingWidth;
|
||||
int runningEdge = textRect.left();
|
||||
// int starsTop = opt.rect.bottom() - 3*PADDING - m_ratingStarNegative.height();
|
||||
int starsTop = runningBottom + PADDING;
|
||||
for ( int i = 1; i < 6; i++ )
|
||||
{
|
||||
QRect r( runningEdge, starsTop, m_ratingStarPositive.width(), m_ratingStarPositive.height() );
|
||||
// QRect r( runningEdge, opt.rect.top() + PADDING, m_ratingStarPositive.width(), m_ratingStarPositive.height() );
|
||||
if ( i == 1 )
|
||||
m_cachedStarRects[ index ] = r;
|
||||
|
||||
const bool userHasRated = index.data( AccountModel::UserHasRatedRole ).toBool();
|
||||
if ( !userHasRated && // Show on-hover animation if the user hasn't rated it yet, and is hovering over it
|
||||
m_hoveringOver > -1 &&
|
||||
m_hoveringItem == index )
|
||||
{
|
||||
if ( i <= m_hoveringOver ) // positive star
|
||||
painter->drawPixmap( r, m_onHoverStar );
|
||||
else
|
||||
painter->drawPixmap( r, m_ratingStarNegative );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( i <= rating ) // positive or rated star
|
||||
{
|
||||
if ( userHasRated )
|
||||
painter->drawPixmap( r, m_onHoverStar );
|
||||
else
|
||||
painter->drawPixmap( r, m_ratingStarPositive );
|
||||
}
|
||||
else
|
||||
painter->drawPixmap( r, m_ratingStarNegative );
|
||||
}
|
||||
runningEdge += m_ratingStarPositive.width() + PADDING_BETWEEN_STARS;
|
||||
}
|
||||
|
||||
// downloaded num times
|
||||
QString count = tr( "%1 downloads" ).arg( index.data( AccountModel::DownloadCounterRole ).toInt() );
|
||||
painter->setFont( descFont );
|
||||
const int countW = painter->fontMetrics().width( count );
|
||||
const QRect countRect( runningEdge + 50, starsTop, countW, painter->fontMetrics().height() );
|
||||
count = painter->fontMetrics().elidedText( count, Qt::ElideRight, rightEdge - PADDING - countRect.left() );
|
||||
painter->drawText( countRect, Qt::AlignLeft | Qt::TextWordWrap, count );
|
||||
// runningEdge = authorRect.x();
|
||||
}
|
||||
|
||||
// Title and description!
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
AccountDelegate::drawAccountList( QPainter* painter, QStyleOptionViewItemV4& opt, const QList< Account* > accts, int rightEdge ) const
|
||||
{
|
||||
// list each account name, and show the online, offline icon
|
||||
const int textHeight = painter->fontMetrics().height() + 1;
|
||||
const int mid = opt.rect.bottom() - opt.rect.height() / 2;
|
||||
int runningRightEdge = rightEdge;
|
||||
int current = 0;
|
||||
|
||||
int leftOfAccounts = rightEdge;
|
||||
|
||||
if ( accts.size() % 2 == 1 )
|
||||
{
|
||||
// If there's an odd number, the center one is centered
|
||||
current = mid - ((textHeight + PADDING/2) * (accts.size()/2) ) - textHeight / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Even number, center between the middle ones
|
||||
current = mid - ((textHeight + PADDING/2) * (accts.size()/2) );
|
||||
}
|
||||
|
||||
for ( int i = 0; i < accts.size(); i++ )
|
||||
{
|
||||
// draw lightbulb and text
|
||||
runningRightEdge = drawStatus( painter, QPointF( rightEdge - PADDING, current), accts.at( i ) );
|
||||
|
||||
const QString label = accts.at( i )->accountFriendlyName();
|
||||
const QPoint textTopLeft( runningRightEdge - PADDING - painter->fontMetrics().width( label ), current);
|
||||
painter->drawText( QRect( textTopLeft, QSize( painter->fontMetrics().width( label ) + 1, textHeight ) ), label );
|
||||
|
||||
current += textHeight + PADDING/2;
|
||||
|
||||
leftOfAccounts = qMin( leftOfAccounts, textTopLeft.x() );
|
||||
}
|
||||
|
||||
return leftOfAccounts;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AccountDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
|
||||
{
|
||||
if ( event->type() != QEvent::MouseButtonPress &&
|
||||
event->type() != QEvent::MouseButtonRelease &&
|
||||
event->type() != QEvent::MouseButtonDblClick &&
|
||||
event->type() != QEvent::MouseMove )
|
||||
return false;
|
||||
|
||||
if ( event->type() == QEvent::MouseButtonPress )
|
||||
{
|
||||
// Show the config wrench as depressed on click
|
||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||
if ( me->button() == Qt::LeftButton && m_cachedConfigRects.contains( index ) && m_cachedConfigRects[ index ].contains( me->pos() ) )
|
||||
{
|
||||
m_configPressed = index;
|
||||
|
||||
const AccountModel::RowType rowType = static_cast< AccountModel::RowType >( index.data( AccountModel::RowTypeRole ).toInt() );
|
||||
if ( rowType == AccountModel::TopLevelAccount ||
|
||||
rowType == AccountModel::CustomAccount )
|
||||
{
|
||||
Account* acct = qobject_cast< Account* >( index.data( AccountModel::AccountData ).value< QObject* >() );
|
||||
Q_ASSERT( acct ); // Should not be showing a config wrench if there is no account!
|
||||
|
||||
emit openConfig( acct );
|
||||
}
|
||||
else if ( rowType == AccountModel::TopLevelFactory )
|
||||
{
|
||||
AccountFactory* fac = qobject_cast< AccountFactory* >( index.data( AccountModel::AccountData ).value< QObject* >() );
|
||||
Q_ASSERT( fac ); // Should not be showing a config wrench if there is no account!
|
||||
emit openConfig( fac );
|
||||
}
|
||||
else if ( rowType == AccountModel::UniqueFactory )
|
||||
{
|
||||
const QList< Account* > accts = index.data( AccountModel::ChildrenOfFactoryRole ).value< QList< Tomahawk::Accounts::Account* > >();
|
||||
|
||||
Q_ASSERT( !accts.isEmpty() ); // If there's no account, why is there a config widget for this factory?
|
||||
Q_ASSERT( accts.size() == 1 );
|
||||
emit openConfig( accts.first() );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if ( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick )
|
||||
{
|
||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||
if ( m_configPressed.isValid() )
|
||||
emit update( m_configPressed );
|
||||
|
||||
m_configPressed = QModelIndex();
|
||||
|
||||
if ( checkRectForIndex( option, index ).contains( me->pos() ) )
|
||||
{
|
||||
// Check box for this row
|
||||
|
||||
// eat the double click events inside the check rect
|
||||
if( event->type() == QEvent::MouseButtonDblClick ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Qt::CheckState curState = static_cast< Qt::CheckState >( index.data( Qt::CheckStateRole ).toInt() );
|
||||
Qt::CheckState newState = curState == Qt::Checked ? Qt::Unchecked : Qt::Checked;
|
||||
return model->setData( index, newState, AccountModel::CheckboxClickedRole );
|
||||
}
|
||||
else if ( m_cachedButtonRects.contains( index ) && m_cachedButtonRects[ index ].contains( me->pos() ) )
|
||||
{
|
||||
// Install/create/etc button for this row
|
||||
model->setData( index, true, AccountModel::CustomButtonRole );
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_cachedStarRects.contains( index ) )
|
||||
{
|
||||
QRect fullStars = m_cachedStarRects[ index ];
|
||||
const int starsWidth = 5 * ( m_ratingStarPositive.width() + PADDING_BETWEEN_STARS );
|
||||
fullStars.setWidth( starsWidth );
|
||||
|
||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||
|
||||
if ( fullStars.contains( me->pos() ) )
|
||||
{
|
||||
const int eachStar = starsWidth / 5;
|
||||
const int clickOffset = me->pos().x() - fullStars.x();
|
||||
const int whichStar = (clickOffset / eachStar) + 1;
|
||||
|
||||
if ( event->type() == QEvent::MouseButtonRelease )
|
||||
{
|
||||
model->setData( index, whichStar, AccountModel::RatingRole );
|
||||
}
|
||||
else if ( event->type() == QEvent::MouseMove )
|
||||
{
|
||||
// 0-indexed
|
||||
m_hoveringOver = whichStar;
|
||||
m_hoveringItem = index;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_hoveringOver > -1 )
|
||||
{
|
||||
emit update( m_hoveringItem );
|
||||
m_hoveringOver = -1;
|
||||
m_hoveringItem = QPersistentModelIndex();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountDelegate::drawRoundedButton( QPainter* painter, const QRect& btnRect, bool red ) const
|
||||
{
|
||||
QPainterPath btnPath;
|
||||
const int radius = 3;
|
||||
// draw top half gradient
|
||||
const int btnCenter = btnRect.bottom() - ( btnRect.height() / 2 );
|
||||
btnPath.moveTo( btnRect.left(), btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnRect.top() + radius );
|
||||
btnPath.quadTo( QPoint( btnRect.topLeft() ), QPoint( btnRect.left() + radius, btnRect.top() ) );
|
||||
btnPath.lineTo( btnRect.right() - radius, btnRect.top() );
|
||||
btnPath.quadTo( QPoint( btnRect.topRight() ), QPoint( btnRect.right(), btnRect.top() + radius ) );
|
||||
btnPath.lineTo( btnRect.right(),btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnCenter );
|
||||
|
||||
QLinearGradient g;
|
||||
if ( !red )
|
||||
{
|
||||
g.setColorAt( 0, QColor(54, 127, 211) );
|
||||
g.setColorAt( 0.5, QColor(43, 104, 182) );
|
||||
}
|
||||
else
|
||||
{
|
||||
g.setColorAt( 0, QColor(206, 63, 63) );
|
||||
g.setColorAt( 0.5, QColor(170, 52, 52) );
|
||||
}
|
||||
//painter->setPen( bg.darker() );
|
||||
painter->fillPath( btnPath, g );
|
||||
//painter->drawPath( btnPath );
|
||||
|
||||
btnPath = QPainterPath();
|
||||
btnPath.moveTo( btnRect.left(), btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnRect.bottom() - radius );
|
||||
btnPath.quadTo( QPoint( btnRect.bottomLeft() ), QPoint( btnRect.left() + radius, btnRect.bottom() ) );
|
||||
btnPath.lineTo( btnRect.right() - radius, btnRect.bottom() );
|
||||
btnPath.quadTo( QPoint( btnRect.bottomRight() ), QPoint( btnRect.right(), btnRect.bottom() - radius ) );
|
||||
btnPath.lineTo( btnRect.right(), btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnCenter );
|
||||
|
||||
if ( !red )
|
||||
{
|
||||
g.setColorAt( 0, QColor(34, 85, 159) );
|
||||
g.setColorAt( 0.5, QColor(35, 79, 147) );
|
||||
}
|
||||
else
|
||||
{
|
||||
g.setColorAt( 0, QColor(150, 50, 50) );
|
||||
g.setColorAt( 0.5, QColor(130, 40, 40) );
|
||||
}
|
||||
painter->fillPath( btnPath, g );
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
AccountDelegate::drawStatus( QPainter* painter, const QPointF& rightTopEdge, Account* acct, bool drawText ) const
|
||||
{
|
||||
QPixmap p;
|
||||
QString statusText;
|
||||
const Account::ConnectionState state = acct->connectionState();
|
||||
if ( state == Account::Connected )
|
||||
{
|
||||
p = m_onlineIcon;
|
||||
statusText = tr( "Online" );
|
||||
}
|
||||
else if ( state == Account::Connecting )
|
||||
{
|
||||
p = m_offlineIcon;
|
||||
statusText = tr( "Connecting..." );
|
||||
}
|
||||
else
|
||||
{
|
||||
p = m_offlineIcon;
|
||||
statusText = tr( "Offline" );
|
||||
}
|
||||
|
||||
const int yPos = rightTopEdge.y();
|
||||
const QRect connectIconRect( rightTopEdge.x() - STATUS_ICON_SIZE, yPos, STATUS_ICON_SIZE, STATUS_ICON_SIZE );
|
||||
|
||||
if ( state == Account::Connecting )
|
||||
{
|
||||
if ( !m_connectingSpinners.contains( acct ) )
|
||||
{
|
||||
AnimatedSpinner* anim = new AnimatedSpinner( connectIconRect.size(), true );
|
||||
_detail::Closure* closure = new _detail::Closure( anim, SIGNAL( requestUpdate() ), const_cast<AccountDelegate*>(this), SLOT( doUpdateIndexWithAccount( Tomahawk::Accounts::Account* ) ), C_ARG( Tomahawk::Accounts::Account*, acct ) );
|
||||
closure->setAutoDelete( false );
|
||||
|
||||
m_connectingSpinners[ acct ] = anim;
|
||||
}
|
||||
|
||||
const QPixmap pm = m_connectingSpinners[acct]->pixmap();
|
||||
painter->drawPixmap( connectIconRect, pm );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_connectingSpinners.contains( acct ) )
|
||||
delete m_connectingSpinners.take( acct );
|
||||
|
||||
painter->drawPixmap( connectIconRect, p );
|
||||
}
|
||||
|
||||
|
||||
int leftEdge = connectIconRect.x();
|
||||
if ( drawText )
|
||||
{
|
||||
int width = painter->fontMetrics().width( statusText );
|
||||
int statusTextX = connectIconRect.x() - PADDING - width;
|
||||
painter->drawText( QRect( statusTextX, yPos, width, painter->fontMetrics().height() ), statusText );
|
||||
|
||||
leftEdge = statusTextX;
|
||||
}
|
||||
|
||||
return leftEdge;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountDelegate::drawCheckBox( QStyleOptionViewItemV4& opt, QPainter* p, const QWidget* w ) const
|
||||
{
|
||||
QStyle* style = w ? w->style() : QApplication::style();
|
||||
opt.checkState == Qt::Checked ? opt.state |= QStyle::State_On : opt.state |= QStyle::State_Off;
|
||||
style->drawPrimitive( QStyle::PE_IndicatorViewItemCheck, &opt, p, w );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountDelegate::drawConfigWrench ( QPainter* painter, QStyleOptionViewItemV4& opt, QStyleOptionToolButton& topt ) const
|
||||
{
|
||||
const QWidget* w = opt.widget;
|
||||
QStyle* style = w ? w->style() : QApplication::style();
|
||||
|
||||
// draw it the same size as the check belox
|
||||
topt.font = opt.font;
|
||||
topt.icon = QIcon( RESPATH "images/configure.png" );
|
||||
topt.iconSize = QSize( 14, 14 );
|
||||
topt.subControls = QStyle::SC_ToolButton;
|
||||
topt.activeSubControls = QStyle::SC_None;
|
||||
topt.features = QStyleOptionToolButton::None;
|
||||
bool pressed = ( m_configPressed == opt.index );
|
||||
topt.state = pressed ? QStyle::State_On : QStyle::State_Raised;
|
||||
if( opt.state & QStyle::State_MouseOver || pressed )
|
||||
topt.state |= QStyle::State_HasFocus;
|
||||
style->drawComplexControl( QStyle::CC_ToolButton, &topt, painter, w );
|
||||
}
|
||||
|
||||
|
||||
|
||||
QRect
|
||||
AccountDelegate::checkRectForIndex( const QStyleOptionViewItem& option, const QModelIndex& idx ) const
|
||||
{
|
||||
QStyleOptionViewItemV4 opt = option;
|
||||
initStyleOption( &opt, idx );
|
||||
|
||||
// Top level item, return the corresponding rect
|
||||
const int ypos = ( opt.rect.top() + opt.rect.height() / 2 ) - ( WRENCH_SIZE / 2 );
|
||||
const QRect checkRect = QRect( PADDING, ypos, WRENCH_SIZE, WRENCH_SIZE );
|
||||
|
||||
return checkRect;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
AccountDelegate::startInstalling( const QPersistentModelIndex& idx )
|
||||
{
|
||||
qDebug() << "START INSTALLING:" << idx.data( Qt::DisplayRole ).toString();
|
||||
QStyleOptionViewItemV4 opt;
|
||||
initStyleOption( &opt, idx );
|
||||
|
||||
AnimatedSpinner* anim = new AnimatedSpinner( checkRectForIndex( opt, idx ).size(), true );
|
||||
_detail::Closure* closure = NewClosure( anim, SIGNAL( requestUpdate() ), this, SLOT( doUpdateIndex( const QPersistentModelIndex& ) ), idx );
|
||||
closure->setAutoDelete( false );
|
||||
|
||||
m_loadingSpinners[ idx ] = anim;
|
||||
|
||||
update( idx );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountDelegate::doneInstalling ( const QPersistentModelIndex& idx )
|
||||
{
|
||||
qDebug() << "STOP INSTALLING:" << idx.data( Qt::DisplayRole ).toString();
|
||||
Q_ASSERT( m_loadingSpinners.contains( idx ) );
|
||||
if ( !m_loadingSpinners.contains( idx ) )
|
||||
return;
|
||||
|
||||
delete m_loadingSpinners.take( idx );
|
||||
|
||||
update( idx );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountDelegate::errorInstalling( const QPersistentModelIndex& idx )
|
||||
{
|
||||
// Just hide the loading spinner as we do after a successful install
|
||||
qDebug() << "ERROR INSTALLING index:" << idx;
|
||||
doneInstalling( idx );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountDelegate::doUpdateIndex( const QPersistentModelIndex& idx )
|
||||
{
|
||||
emit update( idx );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountDelegate::doUpdateIndexWithAccount( Account* account )
|
||||
{
|
||||
// Urgh, have to go through the list and check based on the type
|
||||
for ( int i = 0; i < m_model->rowCount(); i++ )
|
||||
{
|
||||
const QModelIndex index = m_model->index( i, 0, QModelIndex() );
|
||||
const AccountModel::RowType rowType = static_cast< AccountModel::RowType >( index.data( AccountModel::RowTypeRole ).toInt() );
|
||||
if ( rowType == AccountModel::TopLevelAccount ||
|
||||
rowType == AccountModel::CustomAccount )
|
||||
{
|
||||
Account* acct = qobject_cast< Account* >( index.data( AccountModel::AccountData ).value< QObject* >() );
|
||||
|
||||
if ( account == acct )
|
||||
{
|
||||
emit update( index );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( rowType == AccountModel::TopLevelFactory || rowType == AccountModel::UniqueFactory )
|
||||
{
|
||||
const QList< Account* > accts = index.data( AccountModel::ChildrenOfFactoryRole ).value< QList< Tomahawk::Accounts::Account* > >();
|
||||
if ( accts.contains( account ) )
|
||||
{
|
||||
emit update( index );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,90 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://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
|
||||
* 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 ACCOUNTDELEGATE_H
|
||||
#define ACCOUNTDELEGATE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
#include "accounts/AccountModel.h"
|
||||
|
||||
class AnimatedSpinner;
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
namespace Accounts
|
||||
{
|
||||
|
||||
class Account;
|
||||
|
||||
class AccountDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AccountDelegate( QObject* parent = 0);
|
||||
|
||||
virtual void paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
virtual QSize sizeHint ( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
|
||||
public slots:
|
||||
void startInstalling( const QPersistentModelIndex& idx );
|
||||
void doneInstalling ( const QPersistentModelIndex& idx );
|
||||
void errorInstalling ( const QPersistentModelIndex& idx );
|
||||
|
||||
|
||||
void doUpdateIndex( const QPersistentModelIndex& idx );
|
||||
|
||||
protected:
|
||||
virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
|
||||
|
||||
signals:
|
||||
void update( const QModelIndex& idx );
|
||||
void openConfig( Tomahawk::Accounts::Account* );
|
||||
void openConfig( Tomahawk::Accounts::AccountFactory* );
|
||||
|
||||
private slots:
|
||||
void doUpdateIndexWithAccount( Tomahawk::Accounts::Account* account );
|
||||
|
||||
private:
|
||||
void drawRoundedButton( QPainter* painter, const QRect& buttonRect, bool red = false ) const;
|
||||
// Returns new left edge
|
||||
int drawStatus( QPainter* painter, const QPointF& rightTopEdge, Account* acct, bool drawText = false ) const;
|
||||
void drawCheckBox( QStyleOptionViewItemV4& opt, QPainter* p, const QWidget* w ) const;
|
||||
void drawConfigWrench( QPainter* painter, QStyleOptionViewItemV4& option, QStyleOptionToolButton& topt ) const;
|
||||
// returns new left edge
|
||||
int drawAccountList( QPainter* painter, QStyleOptionViewItemV4& option, const QList< Account* > accounts, int rightEdge ) const;
|
||||
|
||||
QRect checkRectForIndex( const QStyleOptionViewItem &option, const QModelIndex &idx ) const;
|
||||
|
||||
QPixmap m_offlineIcon, m_onlineIcon, m_defaultCover, m_onHoverStar, m_ratingStarPositive, m_ratingStarNegative, m_removeIcon;
|
||||
int m_hoveringOver;
|
||||
QPersistentModelIndex m_hoveringItem, m_configPressed;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_cachedButtonRects;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_cachedStarRects;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_cachedConfigRects;
|
||||
mutable QHash< QPersistentModelIndex, QSize > m_sizeHints;
|
||||
mutable QHash< QPersistentModelIndex, AnimatedSpinner* > m_loadingSpinners;
|
||||
mutable QHash< Account*, AnimatedSpinner* > m_connectingSpinners;
|
||||
mutable int m_accountRowHeight;
|
||||
|
||||
mutable QAbstractItemModel* m_model;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ACCOUNTDELEGATE_H
|
@@ -1,138 +0,0 @@
|
||||
/* === 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 "AccountFactoryWrapper.h"
|
||||
|
||||
#include "accounts/Account.h"
|
||||
#include "accounts/AccountManager.h"
|
||||
#include "GuiHelpers.h"
|
||||
#include "AccountFactoryWrapperDelegate.h"
|
||||
#include "DelegateConfigWrapper.h"
|
||||
#include "ui_AccountFactoryWrapper.h"
|
||||
#include "Source.h"
|
||||
|
||||
using namespace Tomahawk::Accounts;
|
||||
AccountFactoryWrapper::AccountFactoryWrapper( AccountFactory* factory, QWidget* parent )
|
||||
: QDialog( parent, Qt::Sheet )
|
||||
, m_factory( factory )
|
||||
, m_ui( new Ui_AccountFactoryWrapper )
|
||||
{
|
||||
m_ui->setupUi( this );
|
||||
|
||||
setWindowTitle( factory->prettyName() );
|
||||
|
||||
m_ui->factoryIcon->setPixmap( factory->icon() );
|
||||
m_ui->factoryDescription->setText( factory->description() );
|
||||
|
||||
m_addButton = m_ui->buttonBox->addButton( tr( "Add Account" ), QDialogButtonBox::ActionRole );
|
||||
|
||||
AccountFactoryWrapperDelegate* del = new AccountFactoryWrapperDelegate( m_ui->accountsList );
|
||||
m_ui->accountsList->setItemDelegate( del );
|
||||
|
||||
connect( del, SIGNAL( openConfig( Tomahawk::Accounts::Account* ) ), this, SLOT( openAccountConfig( Tomahawk::Accounts::Account* ) ) );
|
||||
connect( del, SIGNAL( removeAccount( Tomahawk::Accounts::Account* ) ), this, SLOT( removeAccount( Tomahawk::Accounts::Account* ) ) );
|
||||
connect( del, SIGNAL( checkOrUncheck( QModelIndex, Tomahawk::Accounts::Account* , Qt::CheckState ) ), this, SLOT( accountCheckedOrUnchecked( QModelIndex ,Tomahawk::Accounts::Account* ,Qt::CheckState ) ) );
|
||||
load();
|
||||
|
||||
connect( m_ui->buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
|
||||
connect( m_ui->buttonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
|
||||
connect( m_ui->buttonBox, SIGNAL( clicked( QAbstractButton*) ), this, SLOT( buttonClicked( QAbstractButton* ) ) );
|
||||
|
||||
|
||||
connect ( AccountManager::instance(), SIGNAL( added( Tomahawk::Accounts::Account* ) ), this, SLOT( load() ) );
|
||||
connect ( AccountManager::instance(), SIGNAL( removed( Tomahawk::Accounts::Account* ) ), this, SLOT( load() ) );
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
setContentsMargins( 0, 0, 0, 0 );
|
||||
m_ui->verticalLayout->setSpacing( 6 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
AccountFactoryWrapper::load()
|
||||
{
|
||||
m_ui->accountsList->clear();
|
||||
foreach ( Account* acc, AccountManager::instance()->accounts() )
|
||||
{
|
||||
if ( AccountManager::instance()->factoryForAccount( acc ) == m_factory )
|
||||
{
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem( m_ui->accountsList );
|
||||
item->setData( 0, AccountRole, QVariant::fromValue< QObject *>( acc ) );
|
||||
item->setCheckState( 0, acc->enabled() ? Qt::Checked : Qt::Unchecked );
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_ui->accountsList->model()->rowCount() == 0 )
|
||||
accept();
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
const int padding = 7;
|
||||
#else
|
||||
const int padding = 8;
|
||||
#endif
|
||||
const int height = m_ui->accountsList->model()->rowCount( QModelIndex() ) * ACCOUNT_ROW_HEIGHT + padding;
|
||||
|
||||
m_ui->accountsList->setFixedHeight( height );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountFactoryWrapper::openAccountConfig( Account* account )
|
||||
{
|
||||
TomahawkUtils::openAccountConfig( account, this, false );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountFactoryWrapper::removeAccount( Tomahawk::Accounts::Account* acct )
|
||||
{
|
||||
AccountManager::instance()->removeAccount( acct );
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
void
|
||||
AccountFactoryWrapper::accountCheckedOrUnchecked( const QModelIndex& index, Account* acct, Qt::CheckState newstate )
|
||||
{
|
||||
QTreeWidgetItem* item = m_ui->accountsList->topLevelItem( index.row() );
|
||||
Q_ASSERT( item );
|
||||
|
||||
if ( newstate == Qt::Checked )
|
||||
{
|
||||
item->setCheckState( 0, Qt::Checked );
|
||||
AccountManager::instance()->enableAccount( acct );
|
||||
}
|
||||
else if ( newstate == Qt::Unchecked )
|
||||
{
|
||||
item->setCheckState( 0, Qt::Unchecked );
|
||||
AccountManager::instance()->disableAccount( acct );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AccountFactoryWrapper::buttonClicked( QAbstractButton* button )
|
||||
{
|
||||
if ( button == m_addButton )
|
||||
{
|
||||
TomahawkUtils::createAccountFromFactory( m_factory, this );
|
||||
}
|
||||
else
|
||||
reject();
|
||||
}
|
||||
|
@@ -1,62 +0,0 @@
|
||||
/* === 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 ACCOUNTFACTORYWRAPPER_H
|
||||
#define ACCOUNTFACTORYWRAPPER_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QModelIndex>
|
||||
|
||||
class QAbstractButton;
|
||||
namespace Tomahawk {
|
||||
namespace Accounts {
|
||||
class AccountFactory;
|
||||
class Account;
|
||||
}
|
||||
}
|
||||
|
||||
class Ui_AccountFactoryWrapper;
|
||||
|
||||
// class AccountFactoryWrapper_
|
||||
class AccountFactoryWrapper : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ExtraRoles {
|
||||
AccountRole = Qt::UserRole + 140
|
||||
};
|
||||
|
||||
explicit AccountFactoryWrapper( Tomahawk::Accounts::AccountFactory* factory, QWidget* parent = 0 );
|
||||
virtual ~AccountFactoryWrapper() {}
|
||||
|
||||
public slots:
|
||||
void openAccountConfig( Tomahawk::Accounts::Account* );
|
||||
void removeAccount( Tomahawk::Accounts::Account* );
|
||||
void accountCheckedOrUnchecked( const QModelIndex& , Tomahawk::Accounts::Account* , Qt::CheckState );
|
||||
|
||||
private slots:
|
||||
void buttonClicked( QAbstractButton* );
|
||||
void load();
|
||||
|
||||
private:
|
||||
Tomahawk::Accounts::AccountFactory* m_factory;
|
||||
Ui_AccountFactoryWrapper* m_ui;
|
||||
QPushButton* m_addButton;
|
||||
};
|
||||
|
||||
#endif // ACCOUNTFACTORYWRAPPER_H
|
@@ -1,110 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AccountFactoryWrapper</class>
|
||||
<widget class="QDialog" name="AccountFactoryWrapper">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>507</width>
|
||||
<height>150</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="factoryIcon">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="factoryDescription">
|
||||
<property name="text">
|
||||
<string>Description goes here</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="accountsList">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="autoScroll">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerItem</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="headerHidden">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="expandsOnDoubleClick">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@@ -1,187 +0,0 @@
|
||||
/* === 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 "AccountFactoryWrapperDelegate.h"
|
||||
#include "accounts/Account.h"
|
||||
#include "AccountFactoryWrapper.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
#include "Source.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
|
||||
using namespace Tomahawk::Accounts;
|
||||
|
||||
#define ICON_SIZE 15
|
||||
#define CONFIG_WRENCH_SIZE 20
|
||||
#define PADDING 4
|
||||
|
||||
AccountFactoryWrapperDelegate::AccountFactoryWrapperDelegate( QObject* parent )
|
||||
: QStyledItemDelegate( parent )
|
||||
{
|
||||
m_removePixmap.load( RESPATH "images/list-remove.png" );
|
||||
m_onlineIcon.load( RESPATH "images/sipplugin-online.png" );
|
||||
m_offlineIcon.load( RESPATH "images/sipplugin-offline.png" );
|
||||
|
||||
m_removePixmap = m_removePixmap.scaled( ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_onlineIcon = m_onlineIcon.scaled( ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_offlineIcon = m_offlineIcon.scaled( ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
m_configIcon.addFile( RESPATH "images/configure.png", QSize( CONFIG_WRENCH_SIZE - 8, CONFIG_WRENCH_SIZE - 8 ) );
|
||||
}
|
||||
|
||||
void
|
||||
AccountFactoryWrapperDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
QStyleOptionViewItemV4 opt = option;
|
||||
initStyleOption( &opt, index );
|
||||
|
||||
const int center = opt.rect.height() / 2 + opt.rect.top();
|
||||
const int topIcon = center - ICON_SIZE/2;
|
||||
|
||||
// draw the background
|
||||
const QWidget* w = opt.widget;
|
||||
QStyle* style = w ? w->style() : QApplication::style();
|
||||
style->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, w );
|
||||
|
||||
Account* acc = qobject_cast< Account* >( index.data( AccountFactoryWrapper::AccountRole ).value< QObject* >() );
|
||||
Q_ASSERT( acc );
|
||||
|
||||
// Checkbox on left edge, then text
|
||||
const QRect checkRect( PADDING/4, PADDING/4 + opt.rect.top(), opt.rect.height() - PADDING/4, opt.rect.height() - PADDING/4 );
|
||||
m_cachedCheckRects[ index ] = checkRect;
|
||||
QStyleOptionViewItemV4 opt2 = opt;
|
||||
opt2.rect = checkRect;
|
||||
opt.checkState == Qt::Checked ? opt2.state |= QStyle::State_On : opt2.state |= QStyle::State_Off;
|
||||
style->drawPrimitive( QStyle::PE_IndicatorViewItemCheck, &opt2, painter, w );
|
||||
|
||||
// name on left
|
||||
painter->drawText( opt.rect.adjusted( checkRect.right() + PADDING, PADDING, -PADDING, -PADDING ), Qt::AlignLeft | Qt::AlignVCenter, acc->accountFriendlyName() );
|
||||
|
||||
// remove, config, status on right
|
||||
const QRect pmRect( opt.rect.right() - PADDING - m_removePixmap.width(), topIcon, ICON_SIZE, ICON_SIZE );
|
||||
painter->drawPixmap( pmRect, m_removePixmap );
|
||||
m_cachedButtonRects[ index ] = pmRect;
|
||||
|
||||
const QRect confRect( pmRect.left() - PADDING - CONFIG_WRENCH_SIZE, center - CONFIG_WRENCH_SIZE/2, CONFIG_WRENCH_SIZE, CONFIG_WRENCH_SIZE );
|
||||
|
||||
QStyleOptionToolButton topt;
|
||||
topt.rect = confRect;
|
||||
topt.pos = confRect.topLeft();
|
||||
topt.font = opt.font;
|
||||
topt.icon = m_configIcon;
|
||||
topt.iconSize = QSize( CONFIG_WRENCH_SIZE - 8, CONFIG_WRENCH_SIZE - 8 );
|
||||
topt.subControls = QStyle::SC_ToolButton;
|
||||
topt.activeSubControls = QStyle::SC_None;
|
||||
topt.features = QStyleOptionToolButton::None;
|
||||
bool pressed = ( m_configPressed == opt.index );
|
||||
topt.state = pressed ? QStyle::State_On : QStyle::State_Raised;
|
||||
if( opt.state & QStyle::State_MouseOver || pressed )
|
||||
topt.state |= QStyle::State_HasFocus;
|
||||
style->drawComplexControl( QStyle::CC_ToolButton, &topt, painter, w );
|
||||
m_cachedConfigRects[ index ] = confRect;
|
||||
|
||||
QPixmap p;
|
||||
QString statusText;
|
||||
Account::ConnectionState state = acc->connectionState();
|
||||
if ( state == Account::Connected )
|
||||
{
|
||||
p = m_onlineIcon;
|
||||
statusText = tr( "Online" );
|
||||
}
|
||||
else if ( state == Account::Connecting )
|
||||
{
|
||||
p = m_offlineIcon;
|
||||
statusText = tr( "Connecting..." );
|
||||
}
|
||||
else
|
||||
{
|
||||
p = m_offlineIcon;
|
||||
statusText = tr( "Offline" );
|
||||
}
|
||||
|
||||
const QRect connectIconRect( confRect.left() - PADDING - ICON_SIZE, topIcon, ICON_SIZE, ICON_SIZE );
|
||||
painter->drawPixmap( connectIconRect, p );
|
||||
|
||||
int width = painter->fontMetrics().width( statusText );
|
||||
painter->drawText( QRect( connectIconRect.left() - PADDING - width, center - painter->fontMetrics().height()/2, width, painter->fontMetrics().height() ), statusText );
|
||||
|
||||
}
|
||||
|
||||
QSize
|
||||
AccountFactoryWrapperDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const
|
||||
{
|
||||
return QSize( 200, ACCOUNT_ROW_HEIGHT );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AccountFactoryWrapperDelegate::editorEvent( QEvent* event, QAbstractItemModel*, const QStyleOptionViewItem&, const QModelIndex& index )
|
||||
{
|
||||
if ( event->type() != QEvent::MouseButtonPress &&
|
||||
event->type() != QEvent::MouseButtonRelease &&
|
||||
event->type() != QEvent::MouseButtonDblClick &&
|
||||
event->type() != QEvent::MouseMove )
|
||||
return false;
|
||||
|
||||
if ( event->type() == QEvent::MouseButtonPress )
|
||||
{
|
||||
// Show the config wrench as depressed on click
|
||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||
if ( me->button() == Qt::LeftButton && m_cachedConfigRects.contains( index ) && m_cachedConfigRects[ index ].contains( me->pos() ) )
|
||||
{
|
||||
m_configPressed = index;
|
||||
Account* acct = qobject_cast< Account* >( index.data( AccountFactoryWrapper::AccountRole ).value< QObject* >() );
|
||||
Q_ASSERT( acct ); // Should not be showing a config wrench if there is no account!
|
||||
|
||||
emit openConfig( acct );
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if ( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick )
|
||||
{
|
||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||
if ( m_configPressed.isValid() )
|
||||
emit update( m_configPressed );
|
||||
|
||||
m_configPressed = QModelIndex();
|
||||
Account* acct = qobject_cast< Account* >( index.data( AccountFactoryWrapper::AccountRole ).value< QObject* >() );
|
||||
|
||||
if ( m_cachedCheckRects.contains( index ) && m_cachedCheckRects[ index ].contains( me->pos() ) )
|
||||
{
|
||||
// Check box for this row
|
||||
// eat the double click events inside the check rect
|
||||
if( event->type() == QEvent::MouseButtonDblClick ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Qt::CheckState curState = static_cast< Qt::CheckState >( index.data( Qt::CheckStateRole ).toInt() );
|
||||
Qt::CheckState newState = curState == Qt::Checked ? Qt::Unchecked : Qt::Checked;
|
||||
emit checkOrUncheck( index, acct, newState );
|
||||
}
|
||||
if ( m_cachedButtonRects.contains( index ) && m_cachedButtonRects[ index ].contains( me->pos() ) )
|
||||
{
|
||||
emit removeAccount( acct );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -1,61 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-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 ACCOUNTFACTORYWRAPPERDELEGATE_H
|
||||
#define ACCOUNTFACTORYWRAPPERDELEGATE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
#define ACCOUNT_ROW_HEIGHT 20
|
||||
|
||||
namespace Tomahawk {
|
||||
namespace Accounts {
|
||||
class Account;
|
||||
}
|
||||
}
|
||||
|
||||
class AccountFactoryWrapperDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AccountFactoryWrapperDelegate( QObject* parent = 0 );
|
||||
|
||||
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
|
||||
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
virtual bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index);
|
||||
|
||||
signals:
|
||||
void update( const QModelIndex& );
|
||||
|
||||
void openConfig( Tomahawk::Accounts::Account* );
|
||||
void removeAccount( Tomahawk::Accounts::Account* );
|
||||
|
||||
void checkOrUncheck( const QModelIndex& row, Tomahawk::Accounts::Account* account, Qt::CheckState newState );
|
||||
|
||||
private:
|
||||
QPixmap m_removePixmap, m_offlineIcon, m_onlineIcon;
|
||||
QIcon m_configIcon;
|
||||
QModelIndex m_configPressed;
|
||||
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_cachedCheckRects;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_cachedButtonRects;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_cachedConfigRects;
|
||||
};
|
||||
|
||||
#endif // ACCOUNTFACTORYWRAPPERDELEGATE_H
|
@@ -37,78 +37,115 @@ ENDIF()
|
||||
#ENDFOREACH( moddir )
|
||||
|
||||
SET( tomahawkSources ${tomahawkSources}
|
||||
web/Api_v1.cpp
|
||||
web/api_v1.cpp
|
||||
|
||||
MusicScanner.cpp
|
||||
ShortcutHandler.cpp
|
||||
ScanManager.cpp
|
||||
UbuntuUnityHack.cpp
|
||||
TomahawkApp.cpp
|
||||
musicscanner.cpp
|
||||
shortcuthandler.cpp
|
||||
scanmanager.cpp
|
||||
ubuntuunityhack.cpp
|
||||
tomahawkapp.cpp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
IF(LIBLASTFM_FOUND)
|
||||
SET(tomahawkSources ${tomahawkSources}
|
||||
Scrobbler.cpp
|
||||
scrobbler.cpp
|
||||
)
|
||||
ENDIF(LIBLASTFM_FOUND)
|
||||
|
||||
SET( tomahawkSourcesGui ${tomahawkSourcesGui}
|
||||
sourcetree/SourcesModel.cpp
|
||||
sourcetree/SourcesProxyModel.cpp
|
||||
sourcetree/SourceTreeView.cpp
|
||||
sourcetree/SourceDelegate.cpp
|
||||
sourcetree/AnimationHelper.cpp
|
||||
sourcetree/items/SourceTreeItem.cpp
|
||||
sourcetree/items/SourceItem.cpp
|
||||
sourcetree/items/PlaylistItems.cpp
|
||||
sourcetree/items/CategoryItems.cpp
|
||||
sourcetree/items/GenericPageItems.cpp
|
||||
sourcetree/items/TemporaryPageItem.cpp
|
||||
sourcetree/items/GroupItem.cpp
|
||||
sourcetree/items/HistoryItem.cpp
|
||||
sourcetree/sourcesmodel.cpp
|
||||
sourcetree/sourcesproxymodel.cpp
|
||||
sourcetree/sourcetreeview.cpp
|
||||
sourcetree/sourcedelegate.cpp
|
||||
sourcetree/animationhelper.cpp
|
||||
sourcetree/items/sourcetreeitem.cpp
|
||||
sourcetree/items/sourceitem.cpp
|
||||
sourcetree/items/playlistitems.cpp
|
||||
sourcetree/items/categoryitems.cpp
|
||||
sourcetree/items/genericpageitems.cpp
|
||||
sourcetree/items/temporarypageitem.cpp
|
||||
sourcetree/items/groupitem.cpp
|
||||
sourcetree/items/historyitem.cpp
|
||||
|
||||
utils/GuiHelpers.cpp
|
||||
breakpad/BreakPad.cpp
|
||||
|
||||
accounts/lastfm/LastFmAccount.cpp
|
||||
accounts/lastfm/LastFmConfig.cpp
|
||||
accounts/lastfm/LastFmInfoPlugin.cpp
|
||||
|
||||
accounts/spotify/SpotifyAccount.cpp
|
||||
accounts/spotify/SpotifyAccountConfig.cpp
|
||||
accounts/spotify/SpotifyPlaylistUpdater.cpp
|
||||
|
||||
TomahawkTrayIcon.cpp
|
||||
AudioControls.cpp
|
||||
SettingsDialog.cpp
|
||||
DiagnosticsDialog.cpp
|
||||
AccountDelegate.cpp
|
||||
SettingsListDelegate.cpp
|
||||
DelegateConfigWrapper.cpp
|
||||
TomahawkWindow.cpp
|
||||
tomahawktrayicon.cpp
|
||||
audiocontrols.cpp
|
||||
settingsdialog.cpp
|
||||
diagnosticsdialog.cpp
|
||||
configdelegatebase.cpp
|
||||
sipconfigdelegate.cpp
|
||||
resolverconfigdelegate.cpp
|
||||
settingslistdelegate.cpp
|
||||
resolversmodel.cpp
|
||||
tomahawkwindow.cpp
|
||||
LoadXSPFDialog.cpp
|
||||
AccountFactoryWrapper.cpp
|
||||
AccountFactoryWrapperDelegate.cpp
|
||||
SocialWidget.cpp
|
||||
)
|
||||
|
||||
IF( WITH_BREAKPAD )
|
||||
LIST(APPEND tomahawkSourcesGui breakpad/BreakPad.cpp)
|
||||
ENDIF()
|
||||
SET( tomahawkHeaders ${tomahawkHeaders}
|
||||
tomahawkapp.h
|
||||
|
||||
web/api_v1.h
|
||||
|
||||
musicscanner.h
|
||||
scanmanager.h
|
||||
ubuntuunityhack.h
|
||||
shortcuthandler.h
|
||||
)
|
||||
|
||||
IF(LIBLASTFM_FOUND)
|
||||
SET(tomahawkHeaders ${tomahawkHeaders}
|
||||
scrobbler.h
|
||||
)
|
||||
ENDIF(LIBLASTFM_FOUND)
|
||||
|
||||
IF(LIBATTICA_FOUND)
|
||||
SET( tomahawkSourcesGui ${tomahawkSourcesGui} GetNewStuffDialog.cpp GetNewStuffDelegate.cpp GetNewStuffModel.cpp )
|
||||
SET( tomahawkHeadersGui ${tomahawkHeadersGui} GetNewStuffDialog.h GetNewStuffDelegate.h GetNewStuffModel.h )
|
||||
INCLUDE_DIRECTORIES( ${LIBATTICA_INCLUDE_DIR} )
|
||||
ENDIF(LIBATTICA_FOUND)
|
||||
|
||||
|
||||
SET( tomahawkHeadersGui ${tomahawkHeadersGui}
|
||||
sourcetree/sourcesmodel.h
|
||||
sourcetree/sourcesproxymodel.h
|
||||
sourcetree/sourcetreeview.h
|
||||
sourcetree/sourcedelegate.h
|
||||
sourcetree/animationhelper.h
|
||||
sourcetree/items/sourcetreeitem.h
|
||||
sourcetree/items/sourceitem.h
|
||||
sourcetree/items/playlistitems.h
|
||||
sourcetree/items/categoryitems.h
|
||||
sourcetree/items/genericpageitems.h
|
||||
sourcetree/items/temporarypageitem.h
|
||||
sourcetree/items/groupitem.h
|
||||
sourcetree/items/historyitem.h
|
||||
|
||||
tomahawktrayicon.h
|
||||
audiocontrols.h
|
||||
settingsdialog.h
|
||||
diagnosticsdialog.h
|
||||
configdelegatebase.h
|
||||
resolverconfigdelegate.h
|
||||
sipconfigdelegate.h
|
||||
settingslistdelegate.h
|
||||
resolversmodel.h
|
||||
delegateconfigwrapper.h
|
||||
tomahawkwindow.h
|
||||
LoadXSPFDialog.h
|
||||
)
|
||||
|
||||
SET( tomahawkUI ${tomahawkUI}
|
||||
TomahawkWindow.ui
|
||||
DiagnosticsDialog.ui
|
||||
StackedSettingsDialog.ui
|
||||
ProxyDialog.ui
|
||||
tomahawkwindow.ui
|
||||
diagnosticsdialog.ui
|
||||
stackedsettingsdialog.ui
|
||||
proxydialog.ui
|
||||
|
||||
accounts/lastfm/LastFmConfig.ui
|
||||
accounts/spotify/SpotifyAccountConfig.ui
|
||||
audiocontrols.ui
|
||||
|
||||
AudioControls.ui
|
||||
GetNewStuffDialog.ui
|
||||
LoadXSPFDialog.ui
|
||||
AccountFactoryWrapper.ui
|
||||
SocialWidget.ui
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
@@ -134,7 +171,6 @@ INCLUDE_DIRECTORIES(
|
||||
${TAGLIB_INCLUDES}
|
||||
${PHONON_INCLUDES}
|
||||
${QJSON_INCLUDE_DIR}
|
||||
${LIBATTICA_INCLUDE_DIR}
|
||||
${LIBECHONEST_INCLUDE_DIR}
|
||||
${LIBECHONEST_INCLUDE_DIR}/..
|
||||
)
|
||||
@@ -151,41 +187,42 @@ ENDIF( UNIX )
|
||||
IF( APPLE )
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/thirdparty/SPMediaKeyTap )
|
||||
|
||||
SET( tomahawkSources ${tomahawkSources} mac/TomahawkApp_Mac.mm mac/MacShortcutHandler.cpp )
|
||||
SET( tomahawkHeaders ${tomahawkHeaders} mac/tomahawkapp_mac.h mac/macshortcuthandler.h )
|
||||
SET( tomahawkSources ${tomahawkSources} mac/tomahawkapp_mac.mm mac/macshortcuthandler.cpp )
|
||||
|
||||
IF(HAVE_SPARKLE)
|
||||
SET( tomahawkHeaders ${tomahawkHeaders} ${SPARKLE}/Headers )
|
||||
ENDIF(HAVE_SPARKLE)
|
||||
ENDIF( APPLE )
|
||||
|
||||
IF(GLOOX_FOUND)
|
||||
INCLUDE_DIRECTORIES( ${GLOOX_INCLUDE_DIR} )
|
||||
SET( tomahawkSources ${tomahawkSources} xmppbot/XmppBot.cpp )
|
||||
SET( tomahawkHeaders ${tomahawkHeaders} xmppbot/xmppbot.h )
|
||||
SET( tomahawkSources ${tomahawkSources} xmppbot/xmppbot.cpp )
|
||||
ENDIF(GLOOX_FOUND)
|
||||
|
||||
ADD_SUBDIRECTORY( accounts )
|
||||
ADD_SUBDIRECTORY( infoplugins )
|
||||
ADD_SUBDIRECTORY( sip )
|
||||
|
||||
IF(QCA2_FOUND)
|
||||
INCLUDE_DIRECTORIES( ${QCA2_INCLUDE_DIR} )
|
||||
ENDIF(QCA2_FOUND)
|
||||
|
||||
INCLUDE(GNUInstallDirs)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.h.in
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
|
||||
include( ${CMAKE_SOURCE_DIR}/lang/translations.cmake )
|
||||
|
||||
SET( final_src ${final_src} ${tomahawkMoc} ${tomahawkSources} ${trans_outfile})
|
||||
SET( final_src ${final_src} ${tomahawkMoc} ${tomahawkSources} ${tomahawkHeaders} ${trans_outfile})
|
||||
|
||||
IF( BUILD_GUI )
|
||||
LIST(APPEND tomahawkHeaders ${tomahawkHeadersGui})
|
||||
LIST(APPEND tomahawkSources ${tomahawkSourcesGui})
|
||||
qt4_wrap_ui( tomahawkUI_H ${tomahawkUI} )
|
||||
|
||||
IF( WITH_CRASHREPORTER )
|
||||
ADD_SUBDIRECTORY( breakpad/CrashReporter )
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
kde4_add_app_icon( tomahawkSources "${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon-*.png" )
|
||||
qt4_add_resources( RC_SRCS "../resources.qrc" )
|
||||
|
||||
qt4_wrap_cpp( tomahawkMoc ${tomahawkHeaders} )
|
||||
SET( final_src ${final_src} ${tomahawkUI_H} ${tomahawkMoc} ${tomahawkSources} ${RC_SRCS} )
|
||||
|
||||
IF( UNIX AND NOT APPLE )
|
||||
@@ -193,14 +230,13 @@ IF( UNIX AND NOT APPLE )
|
||||
ENDIF( UNIX AND NOT APPLE )
|
||||
IF( APPLE )
|
||||
ADD_EXECUTABLE( tomahawk MACOSX_BUNDLE ${final_src} )
|
||||
SET_TARGET_PROPERTIES(tomahawk PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_BINARY_DIR}/Info.plist")
|
||||
SET_TARGET_PROPERTIES(tomahawk PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_BINARY_DIR}/Info.plist"
|
||||
)
|
||||
ENDIF( APPLE )
|
||||
IF( WIN32 )
|
||||
ADD_EXECUTABLE( tomahawk WIN32 ${final_src} )
|
||||
ENDIF( WIN32 )
|
||||
|
||||
SET_TARGET_PROPERTIES(tomahawk PROPERTIES AUTOMOC TRUE)
|
||||
|
||||
MESSAGE( STATUS "OS_SPECIFIC_LINK_LIBRARIES: ${OS_SPECIFIC_LINK_LIBRARIES}" )
|
||||
|
||||
SET(LINK_LIBRARIES "")
|
||||
@@ -213,11 +249,9 @@ ENDIF(GLOOX_FOUND)
|
||||
IF(QCA2_FOUND)
|
||||
SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} )
|
||||
ENDIF(QCA2_FOUND)
|
||||
IF(WITH_BREAKPAD)
|
||||
SET(LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_breakpad)
|
||||
ENDIF()
|
||||
|
||||
TARGET_LINK_LIBRARIES( tomahawk
|
||||
tomahawk_breakpad
|
||||
${LINK_LIBRARIES}
|
||||
${TOMAHAWK_LIBRARIES}
|
||||
${PHONON_LIBS}
|
||||
|
@@ -1,158 +0,0 @@
|
||||
/* === 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 "DelegateConfigWrapper.h"
|
||||
#include <QMessageBox>
|
||||
|
||||
|
||||
DelegateConfigWrapper::DelegateConfigWrapper( QWidget* conf, QWidget* aboutWidget, const QString& title, QWidget* parent, Qt::WindowFlags flags )
|
||||
: QDialog( parent, flags )
|
||||
, m_widget( conf )
|
||||
, m_aboutW( aboutWidget )
|
||||
, m_deleted( false )
|
||||
{
|
||||
m_widget->setWindowFlags( Qt::Sheet );
|
||||
#ifdef Q_WS_MAC
|
||||
m_widget->setVisible( true );
|
||||
#endif
|
||||
setWindowTitle( title );
|
||||
QVBoxLayout* v = new QVBoxLayout( this );
|
||||
v->setContentsMargins( 0, 0, 0, 0 );
|
||||
v->addWidget( m_widget );
|
||||
|
||||
QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Ok | QDialogButtonBox::Cancel;
|
||||
if ( m_aboutW )
|
||||
{
|
||||
m_aboutW->hide();
|
||||
buttons |= QDialogButtonBox::Help;
|
||||
}
|
||||
|
||||
m_buttons = new QDialogButtonBox( buttons, Qt::Horizontal, this );
|
||||
m_okButton = m_buttons->button( QDialogButtonBox::Ok );
|
||||
connect( m_buttons, SIGNAL( clicked( QAbstractButton*) ), this, SLOT( closed( QAbstractButton* ) ) );
|
||||
connect( this, SIGNAL( rejected() ), this, SLOT( rejected() ) );
|
||||
|
||||
if ( m_aboutW )
|
||||
{
|
||||
connect( m_buttons->button( QDialogButtonBox::Help ), SIGNAL( clicked( bool ) ), this, SLOT( aboutClicked( bool ) ) );
|
||||
m_buttons->button( QDialogButtonBox::Help )->setText( tr( "About" ) );
|
||||
}
|
||||
|
||||
v->addWidget( m_buttons );
|
||||
|
||||
setLayout( v );
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
setSizeGripEnabled( false );
|
||||
setMinimumSize( sizeHint() );
|
||||
setMaximumSize( sizeHint() ); // to remove the resize grip on osx this is the only way
|
||||
|
||||
if( conf->metaObject()->indexOfSignal( "sizeHintChanged()" ) > -1 )
|
||||
connect( conf, SIGNAL( sizeHintChanged() ), this, SLOT( updateSizeHint() ) );
|
||||
#else
|
||||
m_widget->setVisible( true );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DelegateConfigWrapper::setShowDelete( bool del )
|
||||
{
|
||||
if ( del )
|
||||
m_deleteButton = m_buttons->addButton( tr( "Delete Account" ), QDialogButtonBox::DestructiveRole );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DelegateConfigWrapper::toggleOkButton( bool dataError )
|
||||
{
|
||||
// if dataError is True we want to set the button enabled to false
|
||||
m_okButton->setEnabled( !dataError );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DelegateConfigWrapper::closed( QAbstractButton* b )
|
||||
{
|
||||
QDialogButtonBox* buttons = qobject_cast< QDialogButtonBox* >( sender() );
|
||||
|
||||
if ( buttons->standardButton( b ) == QDialogButtonBox::Help )
|
||||
return;
|
||||
|
||||
// let the config widget live to see another day
|
||||
layout()->removeWidget( m_widget );
|
||||
m_widget->setParent( 0 );
|
||||
m_widget->setVisible( false );
|
||||
|
||||
if ( buttons->standardButton( b ) == QDialogButtonBox::Ok )
|
||||
done( QDialog::Accepted );
|
||||
else if ( b == m_deleteButton )
|
||||
{
|
||||
m_deleted = true;
|
||||
emit closedWithDelete();
|
||||
reject();
|
||||
}
|
||||
else
|
||||
done( QDialog::Rejected );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DelegateConfigWrapper::rejected()
|
||||
{
|
||||
layout()->removeWidget( m_widget );
|
||||
m_widget->setParent( 0 );
|
||||
m_widget->setVisible( false );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DelegateConfigWrapper::updateSizeHint()
|
||||
{
|
||||
hide();
|
||||
setSizeGripEnabled( false );
|
||||
setMinimumSize( sizeHint() );
|
||||
setMaximumSize( sizeHint() );
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DelegateConfigWrapper::aboutClicked( bool )
|
||||
{
|
||||
Q_ASSERT( m_aboutW );
|
||||
m_aboutW->show();
|
||||
|
||||
QDialog d( this );
|
||||
d.setWindowTitle( tr( "About this Account" ) );
|
||||
QVBoxLayout* v = new QVBoxLayout( &d );
|
||||
v->addWidget( m_aboutW );
|
||||
QDialogButtonBox* bbox = new QDialogButtonBox( QDialogButtonBox::Ok, Qt::Horizontal, &d );
|
||||
v->addWidget( bbox );
|
||||
|
||||
d.setLayout( v );
|
||||
connect( bbox, SIGNAL( clicked( QAbstractButton* ) ), &d, SLOT( accept() ) );
|
||||
d.exec();
|
||||
v->removeWidget( m_aboutW );
|
||||
|
||||
m_aboutW->setParent( 0 );
|
||||
m_aboutW->hide();
|
||||
|
||||
}
|
||||
|
@@ -1,61 +0,0 @@
|
||||
/* === 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 RESOLVER_CONFIG_WRAPPER
|
||||
#define RESOLVER_CONFIG_WRAPPER
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QDebug>
|
||||
|
||||
class DelegateConfigWrapper : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DelegateConfigWrapper( QWidget* conf, QWidget* aboutWidget, const QString& title, QWidget* parent, Qt::WindowFlags flags = 0 );
|
||||
|
||||
~DelegateConfigWrapper() {}
|
||||
|
||||
void setShowDelete( bool del );
|
||||
|
||||
bool deleted() const { return m_deleted; }
|
||||
|
||||
public slots:
|
||||
void toggleOkButton( bool dataError );
|
||||
void closed( QAbstractButton* b );
|
||||
|
||||
// we get a rejected() signal emitted if the user presses escape (and no clicked() signal )
|
||||
void rejected();
|
||||
|
||||
void updateSizeHint();
|
||||
|
||||
signals:
|
||||
void closedWithDelete();
|
||||
|
||||
private slots:
|
||||
void aboutClicked( bool );
|
||||
|
||||
private:
|
||||
QDialogButtonBox* m_buttons;
|
||||
QWidget* m_widget, *m_aboutW;
|
||||
QPushButton *m_okButton, *m_deleteButton;
|
||||
bool m_deleted;
|
||||
};
|
||||
|
||||
#endif
|
323
src/GetNewStuffDelegate.cpp
Normal file
@@ -0,0 +1,323 @@
|
||||
/* === 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 "GetNewStuffDelegate.h"
|
||||
|
||||
#include "GetNewStuffModel.h"
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <QtGui/QPainter>
|
||||
#include <QApplication>
|
||||
#include <QMouseEvent>
|
||||
#include "AtticaManager.h"
|
||||
|
||||
#define PADDING 4
|
||||
#define PADDING_BETWEEN_STARS 2
|
||||
#define STAR_SIZE 12
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
#define SIZEHINT_HEIGHT 70
|
||||
#else
|
||||
#define SIZEHINT_HEIGHT 60
|
||||
#endif
|
||||
|
||||
GetNewStuffDelegate::GetNewStuffDelegate( QObject* parent )
|
||||
: QStyledItemDelegate ( parent )
|
||||
, m_widestTextWidth( 0 )
|
||||
, m_hoveringOver( -1 )
|
||||
{
|
||||
m_defaultCover.load( RESPATH "images/sipplugin-online.png" );
|
||||
m_ratingStarPositive.load( RESPATH "images/starred.png" );
|
||||
m_ratingStarNegative.load( RESPATH "images/star-unstarred.png" );
|
||||
m_onHoverStar.load( RESPATH "images/star-hover.png" );
|
||||
|
||||
m_ratingStarPositive = m_ratingStarPositive.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_ratingStarNegative = m_ratingStarNegative.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
m_onHoverStar = m_onHoverStar.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
const int w = SIZEHINT_HEIGHT - 2*PADDING;
|
||||
m_defaultCover = m_defaultCover.scaled( w, w, Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
// save the widest wifth
|
||||
QFont f( QApplication::font() );
|
||||
f.setPointSize( f.pointSize() - 1 );
|
||||
QFontMetrics fm( f );
|
||||
QStringList l = QStringList() << tr( "Installed" ) << tr( "Installing" ) << tr( "Failed" ) << tr( "Uninstalling" );
|
||||
foreach ( const QString& str, l )
|
||||
{
|
||||
if ( fm.width( str ) > m_widestTextWidth )
|
||||
m_widestTextWidth = fm.width( str );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetNewStuffDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
QStyleOptionViewItemV4 opt = option;
|
||||
initStyleOption( &opt, index );
|
||||
|
||||
QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget );
|
||||
|
||||
painter->setRenderHint( QPainter::Antialiasing );
|
||||
|
||||
QFont titleFont = opt.font;
|
||||
titleFont.setBold( true );
|
||||
titleFont.setPointSize( titleFont.pointSize() + 2 );
|
||||
QFontMetrics titleMetrics( titleFont );
|
||||
|
||||
QFont authorFont = opt.font;
|
||||
authorFont.setItalic( true );
|
||||
authorFont.setPointSize( authorFont.pointSize() - 1 );
|
||||
QFontMetrics authorMetrics( authorFont );
|
||||
|
||||
QFont descFont = authorFont;
|
||||
descFont.setItalic( false );
|
||||
QFontMetrics descMetrics( descFont );
|
||||
|
||||
QFont installFont = opt.font;
|
||||
installFont.setPointSize( installFont.pointSize() - 1 );
|
||||
QFontMetrics installMetrics( descFont );
|
||||
|
||||
const int height = opt.rect.height();
|
||||
const int center = height / 2 + opt.rect.top();
|
||||
|
||||
// Pixmap
|
||||
QPixmap p = index.data( Qt::DecorationRole ).value< QPixmap >();
|
||||
const int pixmapWidth = height - 2*PADDING;
|
||||
QRect pixmapRect( PADDING, PADDING + opt.rect.top(), pixmapWidth, pixmapWidth );
|
||||
if ( p.isNull() ) // default image... TODO
|
||||
p = m_defaultCover;
|
||||
else
|
||||
p = p.scaled( pixmapRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
|
||||
|
||||
painter->drawPixmap( pixmapRect, p );
|
||||
|
||||
// Go from right edge now, stars, install button, and downloaded info
|
||||
|
||||
// install / status button
|
||||
AtticaManager::ResolverState state = static_cast< AtticaManager::ResolverState >( index.data( GetNewStuffModel::StateRole ).toInt() );
|
||||
QString actionText;
|
||||
switch( state )
|
||||
{
|
||||
case AtticaManager::Uninstalled:
|
||||
actionText = tr( "Install" );
|
||||
break;
|
||||
case AtticaManager::Installing:
|
||||
actionText = tr( "Installing" );
|
||||
break;
|
||||
case AtticaManager::Upgrading:
|
||||
actionText = tr( "Upgrading" );
|
||||
break;
|
||||
case AtticaManager::Failed:
|
||||
actionText = tr( "Failed" );
|
||||
break;
|
||||
case AtticaManager::Installed:
|
||||
actionText = tr( "Uninstall" );
|
||||
break;
|
||||
case AtticaManager::NeedsUpgrade:
|
||||
actionText = tr( "Upgrade" );
|
||||
break;
|
||||
}
|
||||
|
||||
const int btnWidth = m_widestTextWidth + 7;
|
||||
const int leftEdge = opt.rect.width() - PADDING - btnWidth - 3;
|
||||
const QRect btnRect( leftEdge, center - ( installMetrics.height() + 4 ) / 2, btnWidth, installMetrics.height() + 4 );
|
||||
m_cachedButtonRects[ QPair<int, int>(index.row(), index.column()) ] = btnRect;
|
||||
|
||||
QPen saved = painter->pen();
|
||||
painter->setPen( opt.palette.color( QPalette::Active, QPalette::AlternateBase ) );
|
||||
|
||||
QPainterPath btnPath;
|
||||
const int radius = 3;
|
||||
//btnPath.addRoundedRect( btnRect, 3, 3 );
|
||||
// draw top half gradient
|
||||
const int btnCenter = btnRect.bottom() - ( btnRect.height() / 2 );
|
||||
btnPath.moveTo( btnRect.left(), btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnRect.top() + radius );
|
||||
btnPath.quadTo( QPoint( btnRect.topLeft() ), QPoint( btnRect.left() + radius, btnRect.top() ) );
|
||||
btnPath.lineTo( btnRect.right() - radius, btnRect.top() );
|
||||
btnPath.quadTo( QPoint( btnRect.topRight() ), QPoint( btnRect.right(), btnRect.top() + radius ) );
|
||||
btnPath.lineTo( btnRect.right(),btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnCenter );
|
||||
|
||||
QLinearGradient g;
|
||||
g.setColorAt( 0, QColor(54, 127, 211) );
|
||||
g.setColorAt( 0.5, QColor(43, 104, 182) );
|
||||
//painter->setPen( bg.darker() );
|
||||
painter->fillPath( btnPath, g );
|
||||
//painter->drawPath( btnPath );
|
||||
|
||||
btnPath = QPainterPath();
|
||||
btnPath.moveTo( btnRect.left(), btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnRect.bottom() - radius );
|
||||
btnPath.quadTo( QPoint( btnRect.bottomLeft() ), QPoint( btnRect.left() + radius, btnRect.bottom() ) );
|
||||
btnPath.lineTo( btnRect.right() - radius, btnRect.bottom() );
|
||||
btnPath.quadTo( QPoint( btnRect.bottomRight() ), QPoint( btnRect.right(), btnRect.bottom() - radius ) );
|
||||
btnPath.lineTo( btnRect.right(), btnCenter );
|
||||
btnPath.lineTo( btnRect.left(), btnCenter );
|
||||
|
||||
g.setColorAt( 0, QColor(34, 85, 159) );
|
||||
g.setColorAt( 0.5, QColor(35, 79, 147) );
|
||||
painter->fillPath( btnPath, g );
|
||||
|
||||
painter->setFont( installFont );
|
||||
painter->drawText( btnRect, Qt::AlignCenter, actionText );
|
||||
|
||||
painter->setPen( saved );
|
||||
|
||||
// rating stars
|
||||
int rating = index.data( GetNewStuffModel::RatingRole ).toInt();
|
||||
const int ratingWidth = 5 * ( m_ratingStarPositive.width() + PADDING_BETWEEN_STARS );
|
||||
int runningEdge = ( btnRect.right() - btnRect.width() / 2 ) - ratingWidth / 2;
|
||||
for ( int i = 1; i < 6; i++ )
|
||||
{
|
||||
QRect r( runningEdge, btnRect.top() - m_ratingStarPositive.height() - PADDING, m_ratingStarPositive.width(), m_ratingStarPositive.height() );
|
||||
if ( i == 1 )
|
||||
m_cachedStarRects[ QPair<int, int>(index.row(), index.column()) ] = r;
|
||||
|
||||
const bool userHasRated = index.data( GetNewStuffModel::UserHasRatedRole ).toBool();
|
||||
if ( !userHasRated && // Show on-hover animation if the user hasn't rated it yet, and is hovering over it
|
||||
m_hoveringOver > -1 &&
|
||||
m_hoveringItem == index )
|
||||
{
|
||||
if ( i <= m_hoveringOver ) // positive star
|
||||
painter->drawPixmap( r, m_onHoverStar );
|
||||
else
|
||||
painter->drawPixmap( r, m_ratingStarNegative );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( i <= rating ) // positive or rated star
|
||||
{
|
||||
if ( userHasRated )
|
||||
painter->drawPixmap( r, m_onHoverStar );
|
||||
else
|
||||
painter->drawPixmap( r, m_ratingStarPositive );
|
||||
}
|
||||
else
|
||||
painter->drawPixmap( r, m_ratingStarNegative );
|
||||
}
|
||||
runningEdge += m_ratingStarPositive.width() + PADDING_BETWEEN_STARS;
|
||||
}
|
||||
|
||||
// downloaded num times, underneath button
|
||||
QString count = tr( "%1 downloads" ).arg( index.data( GetNewStuffModel::DownloadCounterRole ).toInt() );
|
||||
const QRect countRect( btnRect.left(), btnRect.bottom() + PADDING, btnRect.width(), opt.rect.bottom() - PADDING - btnRect.bottom() );
|
||||
QFont countFont = descFont;
|
||||
countFont.setPointSize( countFont.pointSize() - 2 );
|
||||
countFont.setBold( true );
|
||||
painter->setFont( countFont );
|
||||
painter->drawText( countRect, Qt::AlignCenter | Qt::TextWordWrap, count );
|
||||
|
||||
// author and version
|
||||
QString author = index.data( GetNewStuffModel::AuthorRole ).toString();
|
||||
const int authorWidth = authorMetrics.width( author );
|
||||
const int topTextLine = opt.rect.top() + PADDING;
|
||||
const QRect authorRect( btnRect.x() - 3*PADDING - authorWidth, topTextLine, authorWidth + 6, authorMetrics.height() );
|
||||
painter->setFont( authorFont );
|
||||
painter->drawText( authorRect, Qt::AlignCenter, author );
|
||||
|
||||
const QRect versionRect = authorRect.translated( 0, authorRect.height() );
|
||||
QString version = index.data( GetNewStuffModel::VersionRole ).toString();
|
||||
painter->drawText( versionRect, Qt::AlignCenter, version );
|
||||
|
||||
// title
|
||||
QString title = index.data( Qt::DisplayRole ).toString();
|
||||
const int rightTitleEdge = authorRect.left() - PADDING;
|
||||
const int leftTitleEdge = pixmapRect.right() + PADDING;
|
||||
const QRect textRect( leftTitleEdge, topTextLine, rightTitleEdge - leftTitleEdge, versionRect.bottom() - opt.rect.top() - PADDING );
|
||||
painter->setFont( titleFont );
|
||||
painter->drawText( textRect, Qt::AlignVCenter | Qt::AlignLeft, title );
|
||||
|
||||
// description
|
||||
QString desc = index.data( GetNewStuffModel::DescriptionRole ).toString();
|
||||
const int descWidth = btnRect.left() - leftTitleEdge - PADDING;
|
||||
const QRect descRect( leftTitleEdge, versionRect.bottom(), descWidth, opt.rect.bottom() - versionRect.bottom() + PADDING );
|
||||
painter->setFont( descFont );
|
||||
painter->drawText( descRect, Qt::AlignLeft | Qt::TextWordWrap, desc );
|
||||
}
|
||||
|
||||
|
||||
QSize
|
||||
GetNewStuffDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
Q_UNUSED( option );
|
||||
Q_UNUSED( index );
|
||||
return QSize( 200, SIZEHINT_HEIGHT );
|
||||
}
|
||||
|
||||
bool
|
||||
GetNewStuffDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
|
||||
{
|
||||
Q_UNUSED( option );
|
||||
|
||||
if ( event->type() != QEvent::MouseButtonRelease &&
|
||||
event->type() != QEvent::MouseMove )
|
||||
return false;
|
||||
|
||||
if ( event->type() == QEvent::MouseButtonRelease && m_cachedButtonRects.contains( QPair<int, int>( index.row(), index.column() ) ) )
|
||||
{
|
||||
QRect rect = m_cachedButtonRects[ QPair<int, int>( index.row(), index.column() ) ];
|
||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||
|
||||
if ( rect.contains( me->pos() ) )
|
||||
{
|
||||
model->setData( index, true );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_cachedStarRects.contains( QPair<int, int>( index.row(), index.column() ) ) )
|
||||
{
|
||||
QRect fullStars = m_cachedStarRects[ QPair<int, int>( index.row(), index.column() ) ];
|
||||
const int starsWidth = 5 * ( m_ratingStarPositive.width() + PADDING_BETWEEN_STARS );
|
||||
fullStars.setWidth( starsWidth );
|
||||
|
||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||
|
||||
if ( fullStars.contains( me->pos() ) )
|
||||
{
|
||||
const int eachStar = starsWidth / 5;
|
||||
const int clickOffset = me->pos().x() - fullStars.x();
|
||||
const int whichStar = (clickOffset / eachStar) + 1;
|
||||
|
||||
if ( event->type() == QEvent::MouseButtonRelease )
|
||||
{
|
||||
model->setData( index, whichStar, GetNewStuffModel::RatingRole );
|
||||
}
|
||||
else if ( event->type() == QEvent::MouseMove )
|
||||
{
|
||||
// 0-indexed
|
||||
m_hoveringOver = whichStar;
|
||||
m_hoveringItem = index;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_hoveringOver > -1 )
|
||||
{
|
||||
emit update( m_hoveringItem );
|
||||
m_hoveringOver = -1;
|
||||
m_hoveringItem = QPersistentModelIndex();
|
||||
}
|
||||
return false;
|
||||
}
|
50
src/GetNewStuffDelegate.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* === 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 GETNEWSTUFFDELEGATE_H
|
||||
#define GETNEWSTUFFDELEGATE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
|
||||
class
|
||||
GetNewStuffDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GetNewStuffDelegate( QObject* parent = 0 );
|
||||
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
|
||||
signals:
|
||||
void update( const QModelIndex& idx );
|
||||
|
||||
protected:
|
||||
virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
|
||||
|
||||
private:
|
||||
QPixmap m_defaultCover, m_onHoverStar, m_ratingStarPositive, m_ratingStarNegative;
|
||||
|
||||
int m_widestTextWidth;
|
||||
int m_hoveringOver;
|
||||
QPersistentModelIndex m_hoveringItem;
|
||||
mutable QHash< QPair<int, int>, QRect > m_cachedButtonRects;
|
||||
mutable QHash< QPair<int, int>, QRect > m_cachedStarRects;
|
||||
};
|
||||
|
||||
#endif // GETNEWSTUFFDELEGATE_H
|
54
src/GetNewStuffDialog.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 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 "GetNewStuffDialog.h"
|
||||
|
||||
#include "ui_GetNewStuffDialog.h"
|
||||
#include "GetNewStuffDelegate.h"
|
||||
#include "GetNewStuffModel.h"
|
||||
|
||||
GetNewStuffDialog::GetNewStuffDialog( QWidget* parent, Qt::WindowFlags f )
|
||||
: QDialog( parent, f )
|
||||
, ui( new Ui::GetNewStuffDialog )
|
||||
, m_model( new GetNewStuffModel( this ) )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
|
||||
ui->listView->setModel( m_model );
|
||||
GetNewStuffDelegate* del = new GetNewStuffDelegate( ui->listView );
|
||||
connect( del, SIGNAL( update( QModelIndex ) ), ui->listView, SLOT( update( QModelIndex ) ) );
|
||||
ui->listView->setItemDelegate( del );
|
||||
ui->listView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
|
||||
|
||||
ui->listView->setMouseTracking( true );
|
||||
|
||||
setMinimumSize( 560, 350 );
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
setMaximumSize( 560, 350 );
|
||||
setSizeGripEnabled( false );
|
||||
|
||||
ui->listView->setAttribute( Qt::WA_MacShowFocusRect, false );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
GetNewStuffDialog::~GetNewStuffDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
41
src/GetNewStuffDialog.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 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 GETNEWSTUFFDIALOG_H
|
||||
#define GETNEWSTUFFDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class GetNewStuffModel;
|
||||
namespace Ui {
|
||||
class GetNewStuffDialog;
|
||||
}
|
||||
|
||||
class GetNewStuffDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GetNewStuffDialog( QWidget *parent = 0, Qt::WindowFlags f = 0 );
|
||||
~GetNewStuffDialog();
|
||||
|
||||
private:
|
||||
Ui::GetNewStuffDialog *ui;
|
||||
GetNewStuffModel* m_model;
|
||||
};
|
||||
|
||||
#endif // GETNEWSTUFFDIALOG_H
|
67
src/GetNewStuffDialog.ui
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GetNewStuffDialog</class>
|
||||
<widget class="QDialog" name="GetNewStuffDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>449</width>
|
||||
<height>282</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Download New Resolvers</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QListView" name="listView"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>GetNewStuffDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>GetNewStuffDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
156
src/GetNewStuffModel.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/* === 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 "GetNewStuffModel.h"
|
||||
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QUrl>
|
||||
#include "AtticaManager.h"
|
||||
|
||||
GetNewStuffModel::GetNewStuffModel( QObject* parent )
|
||||
: QAbstractListModel ( parent )
|
||||
{
|
||||
|
||||
if ( AtticaManager::instance()->resolversLoaded() )
|
||||
m_contentList = AtticaManager::instance()->resolvers();
|
||||
|
||||
connect( AtticaManager::instance(), SIGNAL( resolversReloaded( Attica::Content::List ) ), this, SLOT( resolversReloaded( Attica::Content::List ) ) );
|
||||
connect( AtticaManager::instance(), SIGNAL( resolverStateChanged( QString ) ), this, SLOT( resolverStateChanged( QString ) ) );
|
||||
|
||||
}
|
||||
|
||||
GetNewStuffModel::~GetNewStuffModel()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GetNewStuffModel::resolversReloaded( const Attica::Content::List& resolvers )
|
||||
{
|
||||
beginResetModel();
|
||||
m_contentList = resolvers;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void
|
||||
GetNewStuffModel::resolverStateChanged( const QString& resolverId )
|
||||
{
|
||||
for ( int i = 0; i < m_contentList.count(); i++ )
|
||||
{
|
||||
const Attica::Content resolver = m_contentList[ i ];
|
||||
if ( resolver.id() == resolverId )
|
||||
{
|
||||
QModelIndex idx = index( i, 0, QModelIndex() );
|
||||
emit dataChanged( idx, idx );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QVariant
|
||||
GetNewStuffModel::data( const QModelIndex& index, int role ) const
|
||||
{
|
||||
if ( !index.isValid() || !hasIndex( index.row(), index.column(), index.parent() ) )
|
||||
return QVariant();
|
||||
|
||||
Attica::Content resolver = m_contentList[ index.row() ];
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
return resolver.name();
|
||||
case Qt::DecorationRole:
|
||||
return QVariant::fromValue< QPixmap >( AtticaManager::instance()->iconForResolver( resolver ) );
|
||||
case DownloadUrlRole:
|
||||
// TODO
|
||||
return QUrl();
|
||||
case RatingRole:
|
||||
return resolver.rating() / 20; // rating is out of 100
|
||||
case DownloadCounterRole:
|
||||
return resolver.downloads();
|
||||
case VersionRole:
|
||||
return resolver.version();
|
||||
case DescriptionRole:
|
||||
return resolver.description();
|
||||
case TypeRole:
|
||||
return ResolverType;
|
||||
case AuthorRole:
|
||||
return resolver.author();
|
||||
case StateRole:
|
||||
return (int)AtticaManager::instance()->resolverState( resolver );
|
||||
case UserHasRatedRole:
|
||||
return AtticaManager::instance()->userHasRated( resolver );
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int
|
||||
GetNewStuffModel::rowCount( const QModelIndex& parent ) const
|
||||
{
|
||||
Q_UNUSED( parent );
|
||||
return m_contentList.count();
|
||||
}
|
||||
|
||||
bool
|
||||
GetNewStuffModel::setData( const QModelIndex &index, const QVariant &value, int role )
|
||||
{
|
||||
Q_UNUSED( value );
|
||||
if ( !hasIndex( index.row(), index.column(), index.parent() ) )
|
||||
return false;
|
||||
|
||||
|
||||
Attica::Content resolver = m_contentList[ index.row() ];
|
||||
AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( resolver );
|
||||
if ( role == Qt::EditRole )
|
||||
{
|
||||
switch( state )
|
||||
{
|
||||
case AtticaManager::Uninstalled:
|
||||
// install
|
||||
AtticaManager::instance()->installResolver( resolver );
|
||||
break;
|
||||
case AtticaManager::Installing:
|
||||
case AtticaManager::Upgrading:
|
||||
// Do nothing, busy
|
||||
break;
|
||||
case AtticaManager::Installed:
|
||||
// Uninstall
|
||||
AtticaManager::instance()->uninstallResolver( resolver );
|
||||
break;
|
||||
case AtticaManager::NeedsUpgrade:
|
||||
AtticaManager::instance()->upgradeResolver( resolver );
|
||||
break;
|
||||
default:
|
||||
//FIXME -- this handles e.g. Failed
|
||||
break;
|
||||
};
|
||||
} else if ( role == RatingRole )
|
||||
{
|
||||
// For now only allow rating if a resolver is installed!
|
||||
if ( state != AtticaManager::Installed && state != AtticaManager::NeedsUpgrade )
|
||||
return false;
|
||||
if ( AtticaManager::instance()->userHasRated( resolver ) )
|
||||
return false;
|
||||
m_contentList[ index.row() ].setRating( value.toInt() * 20 );
|
||||
AtticaManager::instance()->uploadRating( m_contentList[ index.row() ] );
|
||||
}
|
||||
emit dataChanged( index, index );
|
||||
|
||||
return true;
|
||||
}
|
64
src/GetNewStuffModel.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* === 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 GETNEWSTUFFMODEL_H
|
||||
#define GETNEWSTUFFMODEL_H
|
||||
|
||||
#include <QModelIndex>
|
||||
|
||||
#include <attica/content.h>
|
||||
#include <QPixmap>
|
||||
|
||||
class GetNewStuffModel: public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum NewStuffRoles {
|
||||
// DisplayRole is title
|
||||
// DecorationRole is qicon for item
|
||||
DownloadUrlRole = Qt::UserRole + 1,
|
||||
RatingRole = Qt::UserRole + 2,
|
||||
DownloadCounterRole = Qt::UserRole + 3,
|
||||
VersionRole = Qt::UserRole + 4,
|
||||
DescriptionRole = Qt::UserRole + 5,
|
||||
TypeRole = Qt::UserRole + 6, // Category in attica-speak. What sort of item this is (resolver, etc).
|
||||
AuthorRole = Qt::UserRole + 7,
|
||||
StateRole = Qt::UserRole + 8,
|
||||
UserHasRatedRole = Qt::UserRole + 9
|
||||
};
|
||||
|
||||
enum Types {
|
||||
ResolverType = 0,
|
||||
};
|
||||
|
||||
explicit GetNewStuffModel( QObject* parent = 0 );
|
||||
virtual ~GetNewStuffModel();
|
||||
|
||||
virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
|
||||
virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;
|
||||
virtual bool setData( const QModelIndex &index, const QVariant &value, int role );
|
||||
|
||||
private slots:
|
||||
void resolversReloaded( const Attica::Content::List& );
|
||||
void resolverStateChanged( const QString& resolverId );
|
||||
|
||||
private:
|
||||
Attica::Content::List m_contentList;
|
||||
};
|
||||
|
||||
#endif // GETNEWSTUFFMODEL_H
|
@@ -17,8 +17,6 @@
|
||||
*/
|
||||
|
||||
#include "LoadXSPFDialog.h"
|
||||
#include "TomahawkSettings.h"
|
||||
#include "Source.h"
|
||||
|
||||
#include "ui_LoadXSPFDialog.h"
|
||||
#include <QFileDialog>
|
||||
@@ -46,11 +44,7 @@ LoadXSPFDialog::~LoadXSPFDialog()
|
||||
void
|
||||
LoadXSPFDialog::getLocalFile()
|
||||
{
|
||||
const QString path = TomahawkSettings::instance()->importXspfPath();
|
||||
QString url = QFileDialog::getOpenFileName( this, tr( "Load XSPF File" ), path, tr( "XSPF Files (*.xspf)" ) );
|
||||
if ( !url.isEmpty() )
|
||||
TomahawkSettings::instance()->setImportXspfPath( QFileInfo( url ).absoluteDir().absolutePath() );
|
||||
|
||||
QString url = QFileDialog::getOpenFileName( this, tr( "Load XSPF File" ), QDir::homePath(), tr( "XSPF Files (*.xspf)" ) );
|
||||
m_ui->lineEdit->setText( url );
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Playlist URL</string>
|
||||
<string>Playlist Url</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@@ -22,9 +22,9 @@
|
||||
#include <QHeaderView>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "libtomahawk/Pipeline.h"
|
||||
#include "libtomahawk/pipeline.h"
|
||||
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
@@ -22,9 +22,9 @@
|
||||
|
||||
#include <QTreeWidget>
|
||||
|
||||
#include "Typedefs.h"
|
||||
#include "widgets/AnimatedSplitter.h"
|
||||
#include "Query.h"
|
||||
#include "typedefs.h"
|
||||
#include "widgets/animatedsplitter.h"
|
||||
#include "query.h"
|
||||
|
||||
class StreamConnection;
|
||||
|
||||
|
@@ -1,549 +0,0 @@
|
||||
/* === 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>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SettingsDialog.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGui/QDesktopServices>
|
||||
#include <QtGui/QFileDialog>
|
||||
#include <QtGui/QMessageBox>
|
||||
#include <QtNetwork/QNetworkConfiguration>
|
||||
#include <QtNetwork/QNetworkProxy>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
#include <QtGui/QSizeGrip>
|
||||
|
||||
#include "AtticaManager.h"
|
||||
#include "TomahawkApp.h"
|
||||
#include "TomahawkSettings.h"
|
||||
#include "DelegateConfigWrapper.h"
|
||||
#include "MusicScanner.h"
|
||||
#include "Pipeline.h"
|
||||
#include "Resolver.h"
|
||||
#include "ExternalResolverGui.h"
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "GuiHelpers.h"
|
||||
#include "ScanManager.h"
|
||||
#include "SettingsListDelegate.h"
|
||||
#include "AccountDelegate.h"
|
||||
#include "database/Database.h"
|
||||
#include "network/Servent.h"
|
||||
#include "utils/AnimatedSpinner.h"
|
||||
#include "accounts/AccountModel.h"
|
||||
#include "accounts/Account.h"
|
||||
#include "accounts/AccountManager.h"
|
||||
#include <accounts/AccountModelFilterProxy.h>
|
||||
#include <accounts/ResolverAccount.h>
|
||||
#include "utils/Logger.h"
|
||||
#include "AccountFactoryWrapper.h"
|
||||
#include "accounts/spotify/SpotifyAccount.h"
|
||||
|
||||
#include "ui_ProxyDialog.h"
|
||||
#include "ui_StackedSettingsDialog.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
using namespace Accounts;
|
||||
|
||||
SettingsDialog::SettingsDialog( QWidget *parent )
|
||||
: QDialog( parent )
|
||||
, ui( new Ui_StackedSettingsDialog )
|
||||
, m_proxySettings( this )
|
||||
, m_rejected( false )
|
||||
, m_restartRequired( false )
|
||||
, m_accountModel( 0 )
|
||||
, m_sipSpinner( 0 )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
|
||||
TomahawkUtils::unmarginLayout( layout() );
|
||||
ui->stackedWidget->setContentsMargins( 4, 4, 4, 0 );
|
||||
|
||||
ui->checkBoxReporter->setChecked( s->crashReporterEnabled() );
|
||||
ui->checkBoxHttp->setChecked( s->httpEnabled() );
|
||||
|
||||
|
||||
//Network settings
|
||||
TomahawkSettings::ExternalAddressMode mode = TomahawkSettings::instance()->externalAddressMode();
|
||||
if ( mode == TomahawkSettings::Lan )
|
||||
ui->lanOnlyRadioButton->setChecked( true );
|
||||
else if ( mode == TomahawkSettings::Static )
|
||||
ui->staticIpRadioButton->setChecked( true );
|
||||
else
|
||||
ui->upnpRadioButton->setChecked( true );
|
||||
|
||||
ui->staticHostNamePortLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
|
||||
ui->staticHostName->setEnabled( ui->staticIpRadioButton->isChecked() );
|
||||
ui->staticPort->setEnabled( ui->staticIpRadioButton->isChecked() );
|
||||
ui->staticHostNameLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
|
||||
ui->staticPortLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
|
||||
|
||||
bool useProxy = TomahawkSettings::instance()->proxyType() == QNetworkProxy::Socks5Proxy;
|
||||
ui->enableProxyCheckBox->setChecked( useProxy );
|
||||
ui->proxyButton->setEnabled( useProxy );
|
||||
|
||||
|
||||
createIcons();
|
||||
#ifdef Q_WS_X11
|
||||
ui->listWidget->setFrameShape( QFrame::StyledPanel );
|
||||
ui->listWidget->setFrameShadow( QFrame::Sunken );
|
||||
setContentsMargins( 4, 4, 4, 4 );
|
||||
#else
|
||||
setContentsMargins( 0, 4, 4, 4 );
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
ui->listWidget->setFixedWidth( 83 );
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
// Avoid resize handles on sheets on osx
|
||||
m_proxySettings.setSizeGripEnabled( true );
|
||||
QSizeGrip* p = m_proxySettings.findChild< QSizeGrip* >();
|
||||
p->setFixedSize( 0, 0 );
|
||||
|
||||
ui->groupBoxNetworkAdvanced->layout()->removeItem( ui->verticalSpacer );
|
||||
ui->groupBoxNetworkAdvanced->layout()->removeItem( ui->verticalSpacer_2 );
|
||||
ui->groupBoxNetworkAdvanced->layout()->removeItem( ui->verticalSpacer_4 );
|
||||
delete ui->verticalSpacer;
|
||||
delete ui->verticalSpacer_2;
|
||||
delete ui->verticalSpacer_4;
|
||||
#endif
|
||||
|
||||
// Accounts
|
||||
AccountDelegate* accountDelegate = new AccountDelegate( this );
|
||||
ui->accountsView->setItemDelegate( accountDelegate );
|
||||
ui->accountsView->setContextMenuPolicy( Qt::CustomContextMenu );
|
||||
ui->accountsView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
|
||||
ui->accountsView->setMouseTracking( true );
|
||||
|
||||
connect( accountDelegate, SIGNAL( openConfig( Tomahawk::Accounts::Account* ) ), this, SLOT( openAccountConfig( Tomahawk::Accounts::Account* ) ) );
|
||||
connect( accountDelegate, SIGNAL( openConfig( Tomahawk::Accounts::AccountFactory* ) ), this, SLOT( openAccountFactoryConfig( Tomahawk::Accounts::AccountFactory* ) ) );
|
||||
connect( accountDelegate, SIGNAL( update( QModelIndex ) ), ui->accountsView, SLOT( update( QModelIndex ) ) );
|
||||
|
||||
m_accountModel = new AccountModel( this );
|
||||
m_accountProxy = new AccountModelFilterProxy( m_accountModel );
|
||||
m_accountProxy->setSourceModel( m_accountModel );
|
||||
|
||||
connect( m_accountProxy, SIGNAL( startInstalling( QPersistentModelIndex ) ), accountDelegate, SLOT( startInstalling(QPersistentModelIndex) ) );
|
||||
connect( m_accountProxy, SIGNAL( doneInstalling( QPersistentModelIndex ) ), accountDelegate, SLOT( doneInstalling(QPersistentModelIndex) ) );
|
||||
connect( m_accountProxy, SIGNAL( errorInstalling( QPersistentModelIndex ) ), accountDelegate, SLOT( errorInstalling(QPersistentModelIndex) ) );
|
||||
connect( m_accountProxy, SIGNAL( scrollTo( QModelIndex ) ), this, SLOT( scrollTo( QModelIndex ) ) );
|
||||
|
||||
ui->accountsView->setModel( m_accountProxy );
|
||||
|
||||
connect( ui->installFromFileBtn, SIGNAL( clicked( bool ) ), this, SLOT( installFromFile() ) );
|
||||
connect( m_accountModel, SIGNAL( createAccount( Tomahawk::Accounts::AccountFactory* ) ), this, SLOT( createAccountFromFactory( Tomahawk::Accounts::AccountFactory* ) ) );
|
||||
|
||||
ui->accountsFilterCombo->addItem( tr( "All" ), Accounts::NoType );
|
||||
ui->accountsFilterCombo->addItem( accountTypeToString( SipType ), SipType );
|
||||
ui->accountsFilterCombo->addItem( accountTypeToString( ResolverType ), ResolverType );
|
||||
ui->accountsFilterCombo->addItem( accountTypeToString( StatusPushType ), StatusPushType );
|
||||
|
||||
connect( ui->accountsFilterCombo, SIGNAL( activated( int ) ), this, SLOT( accountsFilterChanged( int ) ) );
|
||||
|
||||
if ( !Servent::instance()->isReady() )
|
||||
{
|
||||
m_sipSpinner = new AnimatedSpinner( ui->accountsView );
|
||||
m_sipSpinner->fadeIn();
|
||||
|
||||
connect( Servent::instance(), SIGNAL( ready() ), this, SLOT( serventReady() ) );
|
||||
}
|
||||
|
||||
// ADVANCED
|
||||
ui->staticHostName->setText( s->externalHostname() );
|
||||
ui->staticPort->setValue( s->externalPort() );
|
||||
ui->proxyButton->setVisible( true );
|
||||
|
||||
ui->checkBoxWatchForChanges->setChecked( s->watchForChanges() );
|
||||
ui->scannerTimeSpinBox->setValue( s->scannerTime() );
|
||||
ui->enableEchonestCatalog->setChecked( s->enableEchonestCatalogs() );
|
||||
|
||||
connect( ui->checkBoxWatchForChanges, SIGNAL( clicked( bool ) ), SLOT( updateScanOptionsView() ) );
|
||||
|
||||
if ( ui->checkBoxWatchForChanges->isChecked() )
|
||||
{
|
||||
ui->scanTimeLabel->show();
|
||||
ui->scannerTimeSpinBox->show();
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->scanTimeLabel->hide();
|
||||
ui->scannerTimeSpinBox->hide();
|
||||
}
|
||||
|
||||
foreach ( const QString& dir, TomahawkSettings::instance()->scannerPaths() )
|
||||
{
|
||||
ui->dirTree->checkPath( dir, Qt::Checked );
|
||||
}
|
||||
|
||||
// NOW PLAYING
|
||||
// #ifdef Q_WS_MAC
|
||||
// ui->checkBoxEnableAdium->setChecked( s->nowPlayingEnabled() );
|
||||
// #else
|
||||
// ui->checkBoxEnableAdium->hide();
|
||||
// #endif
|
||||
|
||||
connect( ui->proxyButton, SIGNAL( clicked() ), SLOT( showProxySettings() ) );
|
||||
connect( ui->lanOnlyRadioButton, SIGNAL( toggled(bool) ), SLOT( requiresRestart() ) );
|
||||
connect( ui->staticIpRadioButton, SIGNAL( toggled(bool) ), SLOT( requiresRestart() ) );
|
||||
connect( ui->upnpRadioButton, SIGNAL( toggled(bool) ), SLOT( requiresRestart() ) );
|
||||
connect( ui->lanOnlyRadioButton, SIGNAL( toggled(bool) ), SLOT( toggleRemoteMode() ) );
|
||||
connect( ui->staticIpRadioButton, SIGNAL( toggled(bool) ), SLOT( toggleRemoteMode() ) );
|
||||
connect( ui->upnpRadioButton, SIGNAL( toggled(bool) ), SLOT( toggleRemoteMode() ) );
|
||||
connect( ui->enableProxyCheckBox, SIGNAL( toggled(bool) ), SLOT( toggleProxyEnabled() ) );
|
||||
connect( this, SIGNAL( rejected() ), SLOT( onRejected() ) );
|
||||
|
||||
ui->listWidget->setCurrentRow( 0 );
|
||||
ui->listWidget->setItemDelegate(new SettingsListDelegate());
|
||||
}
|
||||
|
||||
|
||||
SettingsDialog::~SettingsDialog()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if ( !m_rejected )
|
||||
{
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
|
||||
s->setCrashReporterEnabled( ui->checkBoxReporter->checkState() == Qt::Checked );
|
||||
s->setHttpEnabled( ui->checkBoxHttp->checkState() == Qt::Checked );
|
||||
s->setProxyType( ui->enableProxyCheckBox->isChecked() ? QNetworkProxy::Socks5Proxy : QNetworkProxy::NoProxy );
|
||||
s->setExternalAddressMode( ui->upnpRadioButton->isChecked() ? TomahawkSettings::Upnp : ( ui->lanOnlyRadioButton->isChecked() ? TomahawkSettings::Lan : TomahawkSettings::Static ) );
|
||||
|
||||
s->setExternalHostname( ui->staticHostName->text() );
|
||||
s->setExternalPort( ui->staticPort->value() );
|
||||
|
||||
s->setScannerPaths( ui->dirTree->getCheckedPaths() );
|
||||
s->setWatchForChanges( ui->checkBoxWatchForChanges->isChecked() );
|
||||
s->setScannerTime( ui->scannerTimeSpinBox->value() );
|
||||
s->setEnableEchonestCatalogs( ui->enableEchonestCatalog->isChecked() );
|
||||
|
||||
// s->setNowPlayingEnabled( ui->checkBoxEnableAdium->isChecked() );
|
||||
|
||||
s->applyChanges();
|
||||
s->sync();
|
||||
|
||||
if ( m_restartRequired )
|
||||
QMessageBox::information( this, tr( "Information" ), tr( "Some changed settings will not take effect until Tomahawk is restarted" ) );
|
||||
|
||||
TomahawkUtils::NetworkProxyFactory* proxyFactory = TomahawkUtils::proxyFactory();
|
||||
if ( !ui->enableProxyCheckBox->isChecked() )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "Got NoProxy selected";
|
||||
proxyFactory->setProxy( QNetworkProxy::NoProxy );
|
||||
}
|
||||
else
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "Got Socks5Proxy selected";
|
||||
proxyFactory->setProxy( QNetworkProxy( QNetworkProxy::Socks5Proxy, s->proxyHost(), s->proxyPort(), s->proxyUsername(), s->proxyPassword() ) );
|
||||
if ( !s->proxyNoProxyHosts().isEmpty() )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "noproxy hosts:" << s->proxyNoProxyHosts();
|
||||
tDebug() << Q_FUNC_INFO << "split noproxy line edit is " << s->proxyNoProxyHosts().split( ' ', QString::SkipEmptyParts );
|
||||
proxyFactory->setNoProxyHosts( s->proxyNoProxyHosts().split( ' ', QString::SkipEmptyParts ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
qDebug() << "Settings dialog cancelled, NOT saving prefs.";
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::serventReady()
|
||||
{
|
||||
m_sipSpinner->fadeOut();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::createIcons()
|
||||
{
|
||||
/// Not fun but QListWidget sucks. Do our max-width calculation manually
|
||||
/// so the icons arre lined up.
|
||||
// Resolvers is the longest string... in english. fml.
|
||||
|
||||
ensurePolished();
|
||||
|
||||
int maxlen = 0;
|
||||
QFontMetrics fm( font() );
|
||||
QListWidgetItem *accountsButton = new QListWidgetItem( ui->listWidget );
|
||||
accountsButton->setIcon( QIcon( RESPATH "images/account-settings.png" ) );
|
||||
accountsButton->setText( tr( "Services" ) );
|
||||
accountsButton->setTextAlignment( Qt::AlignHCenter );
|
||||
accountsButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
|
||||
maxlen = fm.width( accountsButton->text() );
|
||||
|
||||
QListWidgetItem *musicButton = new QListWidgetItem( ui->listWidget );
|
||||
musicButton->setIcon( QIcon( RESPATH "images/music-settings.png" ) );
|
||||
musicButton->setText( tr( "Collection" ) );
|
||||
musicButton->setTextAlignment( Qt::AlignHCenter );
|
||||
musicButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
|
||||
maxlen = qMax( fm.width( musicButton->text() ), maxlen );
|
||||
|
||||
QListWidgetItem *advancedButton = new QListWidgetItem( ui->listWidget );
|
||||
advancedButton->setIcon( QIcon( RESPATH "images/advanced-settings.png" ) );
|
||||
advancedButton->setText( tr( "Advanced" ) );
|
||||
advancedButton->setTextAlignment( Qt::AlignHCenter );
|
||||
advancedButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
|
||||
maxlen = qMax( fm.width( advancedButton->text() ), maxlen );
|
||||
|
||||
maxlen += 15; // padding
|
||||
accountsButton->setSizeHint( QSize( maxlen, 60 ) );
|
||||
musicButton->setSizeHint( QSize( maxlen, 60 ) );
|
||||
advancedButton->setSizeHint( QSize( maxlen, 60 ) );
|
||||
|
||||
#ifndef Q_WS_MAC
|
||||
// doesn't listen to sizehint...
|
||||
ui->listWidget->setFixedWidth( maxlen + 8 );
|
||||
#endif
|
||||
|
||||
connect( ui->listWidget, SIGNAL( currentItemChanged( QListWidgetItem*, QListWidgetItem* ) ), SLOT( changePage( QListWidgetItem*, QListWidgetItem* ) ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::changePage( QListWidgetItem* current, QListWidgetItem* previous )
|
||||
{
|
||||
if ( !current )
|
||||
current = previous;
|
||||
|
||||
ui->stackedWidget->setCurrentIndex( ui->listWidget->row(current) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::onRejected()
|
||||
{
|
||||
m_rejected = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::changeEvent( QEvent *e )
|
||||
{
|
||||
QDialog::changeEvent( e );
|
||||
switch ( e->type() )
|
||||
{
|
||||
case QEvent::LanguageChange:
|
||||
ui->retranslateUi( this );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::showProxySettings()
|
||||
{
|
||||
m_proxySettings.exec();
|
||||
if ( m_proxySettings.result() == QDialog::Accepted )
|
||||
m_proxySettings.saveSettings();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::toggleRemoteMode()
|
||||
{
|
||||
ui->staticHostNamePortLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
|
||||
ui->staticHostName->setEnabled( ui->staticIpRadioButton->isChecked() );
|
||||
ui->staticPort->setEnabled( ui->staticIpRadioButton->isChecked() );
|
||||
ui->staticHostNameLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
|
||||
ui->staticPortLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::toggleProxyEnabled()
|
||||
{
|
||||
ui->proxyButton->setEnabled( ui->enableProxyCheckBox->isChecked() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::updateScanOptionsView()
|
||||
{
|
||||
if ( ui->checkBoxWatchForChanges->isChecked() )
|
||||
{
|
||||
ui->scanTimeLabel->show();
|
||||
ui->scannerTimeSpinBox->show();
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->scanTimeLabel->hide();
|
||||
ui->scannerTimeSpinBox->hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::accountsFilterChanged( int )
|
||||
{
|
||||
AccountType filter = static_cast< AccountType >( ui->accountsFilterCombo->itemData( ui->accountsFilterCombo->currentIndex() ).toInt() );
|
||||
m_accountProxy->setFilterType( filter );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::openAccountFactoryConfig( AccountFactory* factory )
|
||||
{
|
||||
QList< Account* > accts;
|
||||
foreach ( Account* acct, AccountManager::instance()->accounts() )
|
||||
{
|
||||
if ( AccountManager::instance()->factoryForAccount( acct ) == factory )
|
||||
accts << acct;
|
||||
if ( accts.size() > 1 )
|
||||
break;
|
||||
}
|
||||
Q_ASSERT( accts.size() > 0 ); // Shouldn't have a config wrench if there are no accounts!
|
||||
if ( accts.size() == 1 )
|
||||
{
|
||||
// If there's just one, open the config directly w/ the delete button. Otherwise open the multi dialog
|
||||
openAccountConfig( accts.first(), true );
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
AccountFactoryWrapper dialog( factory, this );
|
||||
QWeakPointer< AccountFactoryWrapper > watcher( &dialog );
|
||||
|
||||
dialog.exec();
|
||||
#else
|
||||
// on osx a sheet needs to be non-modal
|
||||
AccountFactoryWrapper* dialog = new AccountFactoryWrapper( factory, this );
|
||||
dialog->show();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::createAccountFromFactory( AccountFactory* factory )
|
||||
{
|
||||
TomahawkUtils::createAccountFromFactory( factory, this );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::openAccountConfig( Account* account, bool showDelete )
|
||||
{
|
||||
TomahawkUtils::openAccountConfig( account, this, showDelete );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::installFromFile()
|
||||
{
|
||||
const QString resolver = QFileDialog::getOpenFileName( this, tr( "Install resolver from file" ), TomahawkSettings::instance()->scriptDefaultPath() );
|
||||
|
||||
if( !resolver.isEmpty() )
|
||||
{
|
||||
const QFileInfo resolverAbsoluteFilePath( resolver );
|
||||
TomahawkSettings::instance()->setScriptDefaultPath( resolverAbsoluteFilePath.absolutePath() );
|
||||
|
||||
if ( resolverAbsoluteFilePath.baseName() == "spotify_tomahawkresolver" )
|
||||
{
|
||||
// HACK if this is a spotify resolver, we treat is specially.
|
||||
// usually we expect the user to just download the spotify resolver from attica,
|
||||
// however developers, those who build their own tomahawk, can't do that, or linux
|
||||
// users can't do that. However, we have an already-existing SpotifyAccount that we
|
||||
// know exists that we need to use this resolver path.
|
||||
//
|
||||
// Hence, we special-case the spotify resolver and directly set the path on it here.
|
||||
SpotifyAccount* acct = 0;
|
||||
foreach ( Account* account, AccountManager::instance()->accounts() )
|
||||
{
|
||||
if ( SpotifyAccount* spotify = qobject_cast< SpotifyAccount* >( account ) )
|
||||
{
|
||||
acct = spotify;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( acct )
|
||||
{
|
||||
acct->setManualResolverPath( resolver );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Account* acct = AccountManager::instance()->accountFromPath( resolver );
|
||||
|
||||
AccountManager::instance()->addAccount( acct );
|
||||
TomahawkSettings::instance()->addAccount( acct->accountId() );
|
||||
AccountManager::instance()->enableAccount( acct );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::scrollTo( const QModelIndex& idx )
|
||||
{
|
||||
ui->accountsView->scrollTo( idx, QAbstractItemView::PositionAtBottom );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::requiresRestart()
|
||||
{
|
||||
m_restartRequired = true;
|
||||
}
|
||||
|
||||
|
||||
ProxyDialog::ProxyDialog( QWidget *parent )
|
||||
: QDialog( parent )
|
||||
, ui( new Ui::ProxyDialog )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
|
||||
// ugly, I know, but...
|
||||
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
|
||||
ui->hostLineEdit->setText( s->proxyHost() );
|
||||
ui->portSpinBox->setValue( s->proxyPort() );
|
||||
ui->userLineEdit->setText( s->proxyUsername() );
|
||||
ui->passwordLineEdit->setText( s->proxyPassword() );
|
||||
ui->checkBoxUseProxyForDns->setChecked( s->proxyDns() );
|
||||
ui->noHostLineEdit->setText( s->proxyNoProxyHosts() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ProxyDialog::saveSettings()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
//First set settings
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
s->setProxyHost( ui->hostLineEdit->text() );
|
||||
|
||||
int port = ui->portSpinBox->value();
|
||||
s->setProxyPort( port );
|
||||
s->setProxyNoProxyHosts( ui->noHostLineEdit->text() );
|
||||
s->setProxyUsername( ui->userLineEdit->text() );
|
||||
s->setProxyPassword( ui->passwordLineEdit->text() );
|
||||
s->setProxyDns( ui->checkBoxUseProxyForDns->checkState() == Qt::Checked );
|
||||
s->sync();
|
||||
}
|
@@ -1,271 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2012, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SocialWidget.h"
|
||||
#include "ui_SocialWidget.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QDialog>
|
||||
#include <QPropertyAnimation>
|
||||
|
||||
#include "GlobalActionManager.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "Source.h"
|
||||
|
||||
#define CORNER_ROUNDNESS 8.0
|
||||
#define FADING_DURATION 500
|
||||
#define FONT_SIZE 16
|
||||
#define OPACITY 0.70
|
||||
|
||||
|
||||
SocialWidget::SocialWidget( QWidget* parent )
|
||||
: QWidget( parent ) // this is on purpose!
|
||||
, ui( new Ui::SocialWidget )
|
||||
, m_opacity( 0.00 )
|
||||
, m_parent( parent )
|
||||
, m_parentRect( parent->rect() )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
|
||||
setAttribute( Qt::WA_TranslucentBackground, true );
|
||||
setOpacity( m_opacity );
|
||||
|
||||
m_timer.setSingleShot( true );
|
||||
connect( &m_timer, SIGNAL( timeout() ), this, SLOT( hide() ) );
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
QFont f( font() );
|
||||
f.setPointSize( f.pointSize() - 2 );
|
||||
setFont( f );
|
||||
#endif
|
||||
|
||||
ui->charsLeftLabel->setForegroundRole( QPalette::HighlightedText );
|
||||
|
||||
m_parent->installEventFilter( this );
|
||||
|
||||
connect( ui->buttonBox, SIGNAL( accepted() ), SLOT( accept() ) );
|
||||
connect( ui->buttonBox, SIGNAL( rejected() ), SLOT( deleteLater() ) );
|
||||
connect( ui->textEdit, SIGNAL( textChanged() ), SLOT( onChanged() ) );
|
||||
connect( ui->facebookButton, SIGNAL( clicked( bool ) ), SLOT( onChanged() ) );
|
||||
connect( ui->twitterButton, SIGNAL( clicked( bool ) ), SLOT( onChanged() ) );
|
||||
connect( GlobalActionManager::instance(), SIGNAL( shortLinkReady( QUrl, QUrl, QVariant ) ), SLOT( onShortLinkReady( QUrl, QUrl, QVariant ) ) );
|
||||
|
||||
onChanged();
|
||||
}
|
||||
|
||||
|
||||
SocialWidget::~SocialWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SocialWidget::setOpacity( qreal opacity )
|
||||
{
|
||||
m_opacity = opacity;
|
||||
|
||||
if ( m_opacity == 0.00 && !isHidden() )
|
||||
{
|
||||
QWidget::hide();
|
||||
}
|
||||
else if ( m_opacity > 0.00 && isHidden() )
|
||||
{
|
||||
QWidget::show();
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SocialWidget::setPosition( QPoint position )
|
||||
{
|
||||
m_position = position;
|
||||
onGeometryUpdate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SocialWidget::show( int timeoutSecs )
|
||||
{
|
||||
if ( !isEnabled() )
|
||||
return;
|
||||
|
||||
QPropertyAnimation* animation = new QPropertyAnimation( this, "opacity" );
|
||||
animation->setDuration( FADING_DURATION );
|
||||
animation->setEndValue( 1.0 );
|
||||
animation->start();
|
||||
|
||||
if( timeoutSecs > 0 )
|
||||
m_timer.start( timeoutSecs * 1000 );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SocialWidget::hide()
|
||||
{
|
||||
if ( !isEnabled() )
|
||||
return;
|
||||
|
||||
QPropertyAnimation* animation = new QPropertyAnimation( this, "opacity" );
|
||||
animation->setDuration( FADING_DURATION );
|
||||
animation->setEndValue( 0.00 );
|
||||
animation->start();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SocialWidget::shown() const
|
||||
{
|
||||
if ( !isEnabled() )
|
||||
return false;
|
||||
|
||||
return m_opacity == OPACITY;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SocialWidget::paintEvent( QPaintEvent* event )
|
||||
{
|
||||
Q_UNUSED( event );
|
||||
|
||||
QPainter p( this );
|
||||
QRect r = contentsRect();
|
||||
|
||||
p.setBackgroundMode( Qt::TransparentMode );
|
||||
p.setRenderHint( QPainter::Antialiasing );
|
||||
p.setOpacity( m_opacity );
|
||||
|
||||
QPen pen( palette().dark().color(), .5 );
|
||||
p.setPen( pen );
|
||||
p.setBrush( QColor( 30, 30, 30, 255.0 * OPACITY ) );
|
||||
|
||||
p.drawRoundedRect( r, CORNER_ROUNDNESS, CORNER_ROUNDNESS );
|
||||
|
||||
QWidget::paintEvent( event );
|
||||
return;
|
||||
|
||||
QTextOption to( Qt::AlignCenter );
|
||||
to.setWrapMode( QTextOption::WrapAtWordBoundaryOrAnywhere );
|
||||
|
||||
// shrink to fit if needed
|
||||
QFont f( font() );
|
||||
f.setPointSize( FONT_SIZE );
|
||||
f.setBold( true );
|
||||
|
||||
QRectF textRect = r.adjusted( 8, 8, -8, -8 );
|
||||
qreal availHeight = textRect.height();
|
||||
|
||||
QFontMetricsF fm( f );
|
||||
qreal textHeight = fm.boundingRect( textRect, Qt::AlignCenter | Qt::TextWordWrap, "SocialWidget" ).height();
|
||||
while( textHeight > availHeight )
|
||||
{
|
||||
if( f.pointSize() <= 4 ) // don't try harder
|
||||
break;
|
||||
|
||||
f.setPointSize( f.pointSize() - 1 );
|
||||
fm = QFontMetricsF( f );
|
||||
textHeight = fm.boundingRect( textRect, Qt::AlignCenter | Qt::TextWordWrap, "SocialWidget" ).height();
|
||||
}
|
||||
|
||||
p.setFont( f );
|
||||
p.setPen( palette().highlightedText().color() );
|
||||
p.drawText( r.adjusted( 8, 8, -8, -8 ), "SocialWidget", to );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SocialWidget::onShortLinkReady( const QUrl& longUrl, const QUrl& shortUrl, const QVariant& callbackObj )
|
||||
{
|
||||
Q_UNUSED( longUrl );
|
||||
Q_UNUSED( callbackObj );
|
||||
|
||||
if ( m_query->album().isEmpty() )
|
||||
ui->textEdit->setText( tr( "Listening to \"%1\" by %2 and loving it! %3" ).arg( m_query->track() ).arg( m_query->artist() ).arg( shortUrl.toString() ) );
|
||||
else
|
||||
ui->textEdit->setText( tr( "Listening to \"%1\" by %2 on \"%3\" and loving it! %4" ).arg( m_query->track() ).arg( m_query->artist() ).arg( m_query->album() ).arg( shortUrl.toString() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SocialWidget::setQuery( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
m_query = query;
|
||||
ui->coverImage->setPixmap( query->cover( ui->coverImage->size() ) );
|
||||
onShortLinkReady( QString(), QString(), QVariant() );
|
||||
onChanged();
|
||||
|
||||
QUrl longUrl = GlobalActionManager::instance()->openLinkFromQuery( query );
|
||||
GlobalActionManager::instance()->shortenLink( longUrl );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SocialWidget::onChanged()
|
||||
{
|
||||
const int remaining = charsAvailable() - ui->textEdit->toPlainText().length();
|
||||
ui->charsLeftLabel->setText( tr( "%1 characters left" ).arg( remaining ) );
|
||||
ui->buttonBox->button( QDialogButtonBox::Ok )->setEnabled( remaining >= 0 && ( ui->facebookButton->isChecked() || ui->twitterButton->isChecked() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SocialWidget::accept()
|
||||
{
|
||||
tDebug() << "Sharing social link!";
|
||||
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
SocialWidget::charsAvailable() const
|
||||
{
|
||||
if ( ui->twitterButton->isChecked() )
|
||||
return 140;
|
||||
|
||||
return 420; // facebook max length
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SocialWidget::onGeometryUpdate()
|
||||
{
|
||||
QPoint p( m_parent->rect().width() - m_parentRect.width(), m_parent->rect().height() - m_parentRect.height() );
|
||||
m_position += p;
|
||||
m_parentRect = m_parent->rect();
|
||||
|
||||
QPoint position( m_position - QPoint( size().width(), size().height() ) );
|
||||
if ( position != pos() )
|
||||
{
|
||||
move( position );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SocialWidget::eventFilter( QObject* object, QEvent* event )
|
||||
{
|
||||
if ( event->type() == QEvent::Resize )
|
||||
{
|
||||
onGeometryUpdate();
|
||||
}
|
||||
|
||||
return QObject::eventFilter( object, event );
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2012, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SOCIALWIDGET_H
|
||||
#define SOCIALWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QAbstractItemView>
|
||||
#include <QTimer>
|
||||
|
||||
#include "Query.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class SocialWidget;
|
||||
}
|
||||
|
||||
class SocialWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity )
|
||||
|
||||
public:
|
||||
SocialWidget( QWidget* parent );
|
||||
~SocialWidget();
|
||||
|
||||
Tomahawk::query_ptr query() const { return m_query; }
|
||||
void setQuery( const Tomahawk::query_ptr& query );
|
||||
|
||||
qreal opacity() const { return m_opacity; }
|
||||
void setOpacity( qreal opacity );
|
||||
|
||||
QPoint position() const { return m_position; }
|
||||
void setPosition( QPoint position );
|
||||
|
||||
bool shown() const;
|
||||
|
||||
public slots:
|
||||
void show( int timeoutSecs = 0 );
|
||||
void hide();
|
||||
|
||||
protected:
|
||||
// void changeEvent( QEvent* e );
|
||||
void paintEvent( QPaintEvent* event );
|
||||
bool eventFilter( QObject* object, QEvent* event );
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
void onChanged();
|
||||
void onShortLinkReady( const QUrl& longUrl, const QUrl& shortUrl, const QVariant& callbackObj );
|
||||
|
||||
void onGeometryUpdate();
|
||||
|
||||
private:
|
||||
unsigned int charsAvailable() const;
|
||||
|
||||
Ui::SocialWidget* ui;
|
||||
|
||||
Tomahawk::query_ptr m_query;
|
||||
|
||||
qreal m_opacity;
|
||||
QPoint m_position;
|
||||
|
||||
QWidget* m_parent;
|
||||
QRect m_parentRect;
|
||||
QTimer m_timer;
|
||||
};
|
||||
|
||||
#endif // SOCIALWIDGET_H
|
@@ -1,118 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SocialWidget</class>
|
||||
<widget class="QWidget" name="SocialWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>365</width>
|
||||
<height>190</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="facebookButton">
|
||||
<property name="text">
|
||||
<string>Facebook</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="twitterButton">
|
||||
<property name="text">
|
||||
<string>Twitter</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="coverImage">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>96</width>
|
||||
<height>96</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>96</width>
|
||||
<height>96</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cover</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="textEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>96</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="charsLeftLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@@ -1,500 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>StackedSettingsDialog</class>
|
||||
<widget class="QDialog" name="StackedSettingsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>655</width>
|
||||
<height>500</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Tomahawk Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_12">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="autoScroll">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="movement">
|
||||
<enum>QListView::Static</enum>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::Adjust</enum>
|
||||
</property>
|
||||
<property name="layoutMode">
|
||||
<enum>QListView::Batched</enum>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>1</width>
|
||||
<height>4</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="accountsPage">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_11">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Internet Services</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<property name="margin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="installFromFileBtn">
|
||||
<property name="text">
|
||||
<string>Install from file...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Filter by capability:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="accountsFilterCombo"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="accountsView">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="scannerPage">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Local Music Information</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_17">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Path to scan for music files:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="CheckDirTree" name="dirTree"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableEchonestCatalog">
|
||||
<property name="toolTip">
|
||||
<string>The Echo Nest supports keeping track of your catalog metadata
|
||||
and using it to craft personalized radios. Enabling this option
|
||||
will allow you (and all your friends) to create automatic playlists
|
||||
and stations based on your personal taste profile.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Upload collection list to The Echo Nest to enable user radio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxWatchForChanges">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Watch for changes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="scanTimeLabel">
|
||||
<property name="text">
|
||||
<string>Time between scans, in seconds:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="scannerTimeSpinBox">
|
||||
<property name="minimum">
|
||||
<number>60</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="advancedPage">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBoxNetworkAdvanced">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Advanced Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
<property name="margin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="remoteConnectionsGroupBox">
|
||||
<property name="title">
|
||||
<string>Remote Peer Connection Method</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="lanOnlyRadioButton">
|
||||
<property name="text">
|
||||
<string>None (outgoing connections only)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="upnpRadioButton">
|
||||
<property name="text">
|
||||
<string>Use UPnP to establish port forward (recommended)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="staticIpRadioButton">
|
||||
<property name="text">
|
||||
<string>Use static external IP address/host name and port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="staticHostNamePortLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set this to your external IP address or host name. Make sure to forward the port to this host!</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="staticHostNamePortLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="staticHostNameLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Static Host Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="staticHostName"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="staticPortLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Static Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="staticPort">
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50210</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="proxyGroupBox">
|
||||
<property name="title">
|
||||
<string>SOCKS Proxy</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableProxyCheckBox">
|
||||
<property name="text">
|
||||
<string>Use SOCKS Proxy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="proxyButton">
|
||||
<property name="text">
|
||||
<string>Proxy Settings...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="otherSettingsGroupBox">
|
||||
<property name="title">
|
||||
<string>Other Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxHttp">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Allow web browsers to interact with Tomahawk (recommended)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxReporter">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Send reports after Tomahawk crashed</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CheckDirTree</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header location="global">widgets/CheckDirTree.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>StackedSettingsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>222</x>
|
||||
<y>347</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>StackedSettingsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>290</x>
|
||||
<y>353</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@@ -1,33 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ACCOUNTDLLMACRO_H
|
||||
#define ACCOUNTDLLMACRO_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef ACCOUNTDLLEXPORT
|
||||
# if defined (ACCOUNTDLLEXPORT_PRO)
|
||||
# define ACCOUNTDLLEXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define ACCOUNTDLLEXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -1,301 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-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 "LastFmAccount.h"
|
||||
#include "LastFmConfig.h"
|
||||
|
||||
#include "infosystem/InfoSystem.h"
|
||||
#include "LastFmInfoPlugin.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
#include "resolvers/QtScriptResolver.h"
|
||||
#include "AtticaManager.h"
|
||||
#include "Pipeline.h"
|
||||
#include "accounts/AccountManager.h"
|
||||
#include "Source.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
using namespace InfoSystem;
|
||||
using namespace Accounts;
|
||||
|
||||
LastFmAccountFactory::LastFmAccountFactory()
|
||||
{
|
||||
m_icon.load( RESPATH "images/lastfm-icon.png" );
|
||||
}
|
||||
|
||||
|
||||
Account*
|
||||
LastFmAccountFactory::createAccount( const QString& accountId )
|
||||
{
|
||||
return new LastFmAccount( accountId.isEmpty() ? generateId( factoryId() ) : accountId );
|
||||
}
|
||||
|
||||
|
||||
QPixmap
|
||||
LastFmAccountFactory::icon() const
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
|
||||
|
||||
LastFmAccount::LastFmAccount( const QString& accountId )
|
||||
: CustomAtticaAccount( accountId )
|
||||
{
|
||||
setAccountFriendlyName( "Last.Fm" );
|
||||
m_icon.load( RESPATH "images/lastfm-icon.png" );
|
||||
|
||||
AtticaManager::instance()->registerCustomAccount( "lastfm", this );
|
||||
|
||||
connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( resolverInstalled( QString ) ) );
|
||||
|
||||
const Attica::Content res = AtticaManager::instance()->resolverForId( "lastfm" );
|
||||
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
|
||||
|
||||
if ( state == AtticaManager::Installed )
|
||||
{
|
||||
hookupResolver();
|
||||
}
|
||||
|
||||
|
||||
if ( infoPlugin() && Tomahawk::InfoSystem::InfoSystem::instance()->workerThread() )
|
||||
{
|
||||
infoPlugin().data()->moveToThread( Tomahawk::InfoSystem::InfoSystem::instance()->workerThread().data() );
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->addInfoPlugin( infoPlugin() );
|
||||
QMetaObject::invokeMethod( infoPlugin().data(), "init", Qt::QueuedConnection );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LastFmAccount::~LastFmAccount()
|
||||
{
|
||||
if ( m_infoPlugin )
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->removeInfoPlugin( infoPlugin() );
|
||||
|
||||
delete m_resolver.data();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmAccount::authenticate()
|
||||
{
|
||||
if ( !AtticaManager::instance()->resolversLoaded() )
|
||||
{
|
||||
// If we're still waiting to load, wait for the attica resolvers to come down the pipe
|
||||
connect( AtticaManager::instance(), SIGNAL(resolversLoaded(Attica::Content::List)), this, SLOT( atticaLoaded( Attica::Content::List ) ), Qt::UniqueConnection );
|
||||
return;
|
||||
}
|
||||
|
||||
const Attica::Content res = AtticaManager::instance()->resolverForId( "lastfm" );
|
||||
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
|
||||
|
||||
qDebug() << "Last.FM account authenticating...";
|
||||
if ( m_resolver.isNull() && state == AtticaManager::Installed )
|
||||
{
|
||||
hookupResolver();
|
||||
}
|
||||
else if ( m_resolver.isNull() )
|
||||
{
|
||||
qDebug() << "Got null resolver but asked to authenticate, so installing i we have one from attica:" << res.isValid() << res.id();
|
||||
if ( res.isValid() && !res.id().isEmpty() )
|
||||
AtticaManager::instance()->installResolver( res, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_resolver.data()->start();
|
||||
}
|
||||
|
||||
emit connectionStateChanged( connectionState() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmAccount::atticaLoaded( Attica::Content::List )
|
||||
{
|
||||
disconnect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( atticaLoaded( Attica::Content::List ) ) );
|
||||
authenticate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmAccount::deauthenticate()
|
||||
{
|
||||
if ( !m_resolver.isNull() && m_resolver.data()->running() )
|
||||
m_resolver.data()->stop();
|
||||
|
||||
emit connectionStateChanged( connectionState() );
|
||||
}
|
||||
|
||||
|
||||
QWidget*
|
||||
LastFmAccount::configurationWidget()
|
||||
{
|
||||
if ( m_configWidget.isNull() )
|
||||
m_configWidget = QWeakPointer<LastFmConfig>( new LastFmConfig( this ) );
|
||||
|
||||
return m_configWidget.data();
|
||||
}
|
||||
|
||||
|
||||
Account::ConnectionState
|
||||
LastFmAccount::connectionState() const
|
||||
{
|
||||
return (!m_resolver.isNull() && m_resolver.data()->running()) ? Account::Connected : Account::Disconnected;
|
||||
}
|
||||
|
||||
|
||||
QPixmap
|
||||
LastFmAccount::icon() const
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
|
||||
|
||||
InfoPluginPtr
|
||||
LastFmAccount::infoPlugin()
|
||||
{
|
||||
if ( m_infoPlugin.isNull() )
|
||||
m_infoPlugin = QWeakPointer< LastFmInfoPlugin >( new LastFmInfoPlugin( this ) );
|
||||
|
||||
return InfoPluginPtr( m_infoPlugin.data() );
|
||||
}
|
||||
|
||||
bool
|
||||
LastFmAccount::isAuthenticated() const
|
||||
{
|
||||
return !m_resolver.isNull() && m_resolver.data()->running();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmAccount::saveConfig()
|
||||
{
|
||||
if ( !m_configWidget.isNull() )
|
||||
{
|
||||
setUsername( m_configWidget.data()->username() );
|
||||
setPassword( m_configWidget.data()->password() );
|
||||
setScrobble( m_configWidget.data()->scrobble() );
|
||||
}
|
||||
|
||||
sync();
|
||||
|
||||
if ( m_infoPlugin )
|
||||
QTimer::singleShot( 0, m_infoPlugin.data(), SLOT( settingsChanged() ) );
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
LastFmAccount::password() const
|
||||
{
|
||||
return credentials().value( "password" ).toString();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmAccount::setPassword( const QString& password )
|
||||
{
|
||||
QVariantHash creds = credentials();
|
||||
creds[ "password" ] = password;
|
||||
setCredentials( creds );
|
||||
}
|
||||
|
||||
QString
|
||||
LastFmAccount::sessionKey() const
|
||||
{
|
||||
return credentials().value( "sessionkey" ).toString();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmAccount::setSessionKey( const QString& sessionkey )
|
||||
{
|
||||
QVariantHash creds = credentials();
|
||||
creds[ "sessionkey" ] = sessionkey;
|
||||
setCredentials( creds );
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
LastFmAccount::username() const
|
||||
{
|
||||
return credentials().value( "username" ).toString();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmAccount::setUsername( const QString& username )
|
||||
{
|
||||
QVariantHash creds = credentials();
|
||||
creds[ "username" ] = username;
|
||||
setCredentials( creds );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
LastFmAccount::scrobble() const
|
||||
{
|
||||
return configuration().value( "scrobble" ).toBool();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmAccount::setScrobble( bool scrobble )
|
||||
{
|
||||
QVariantHash conf;
|
||||
conf[ "scrobble" ] = scrobble;
|
||||
setConfiguration( conf );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmAccount::resolverInstalled( const QString &resolverId )
|
||||
{
|
||||
if ( resolverId == "lastfm" )
|
||||
{
|
||||
// We requested this install, so we want to launch it
|
||||
hookupResolver();
|
||||
AccountManager::instance()->enableAccount( this );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LastFmAccount::resolverChanged()
|
||||
{
|
||||
emit connectionStateChanged( connectionState() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmAccount::hookupResolver()
|
||||
{
|
||||
// If there is a last.fm resolver from attica installed, create the corresponding ExternalResolver* and hook up to it
|
||||
const Attica::Content res = AtticaManager::instance()->resolverForId( "lastfm" );
|
||||
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
|
||||
Q_ASSERT( state == AtticaManager::Installed );
|
||||
Q_UNUSED( state );
|
||||
|
||||
const AtticaManager::Resolver data = AtticaManager::instance()->resolverData( res.id() );
|
||||
|
||||
m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( data.scriptPath, enabled() ) ) );
|
||||
connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) );
|
||||
}
|
||||
|
||||
|
||||
Attica::Content
|
||||
LastFmAccount::atticaContent() const
|
||||
{
|
||||
return AtticaManager::instance()->resolverForId( "lastfm" );
|
||||
}
|
@@ -1,115 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-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 LASTFMACCOUNT_H
|
||||
#define LASTFMACCOUNT_H
|
||||
|
||||
#include "accounts/Account.h"
|
||||
#include "AtticaManager.h"
|
||||
|
||||
#include <attica/content.h>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace Tomahawk {
|
||||
class ExternalResolverGui;
|
||||
|
||||
namespace InfoSystem {
|
||||
class LastFmInfoPlugin;
|
||||
}
|
||||
|
||||
namespace Accounts {
|
||||
|
||||
class LastFmConfig;
|
||||
|
||||
class LastFmAccountFactory : public AccountFactory
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LastFmAccountFactory();
|
||||
|
||||
virtual Account* createAccount(const QString& accountId = QString());
|
||||
virtual QString description() const { return tr( "Scrobble your tracks to last.fm, and find freely downloadable tracks to play" ); }
|
||||
virtual QString factoryId() const { return "lastfmaccount"; }
|
||||
virtual QString prettyName() const { return "Last.fm"; }
|
||||
virtual AccountTypes types() const { return AccountTypes( InfoType | StatusPushType ); }
|
||||
virtual bool allowUserCreation() const { return false; }
|
||||
virtual QPixmap icon() const;
|
||||
virtual bool isUnique() const { return true; }
|
||||
|
||||
private:
|
||||
QPixmap m_icon;
|
||||
};
|
||||
|
||||
/**
|
||||
* 3.Last.Fm account is special. It is both an attica resolver *and* a InfoPlugin. We always want the infoplugin,
|
||||
* but the user can install the attica resolver on-demand. So we take care of both there.
|
||||
*
|
||||
*/
|
||||
class LastFmAccount : public CustomAtticaAccount
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LastFmAccount( const QString& accountId );
|
||||
~LastFmAccount();
|
||||
|
||||
virtual void deauthenticate();
|
||||
virtual void authenticate();
|
||||
|
||||
virtual SipPlugin* sipPlugin() { return 0; }
|
||||
virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin();
|
||||
|
||||
virtual bool isAuthenticated() const;
|
||||
|
||||
virtual ConnectionState connectionState() const;
|
||||
virtual QPixmap icon() const;
|
||||
virtual QWidget* aclWidget() { return 0; }
|
||||
virtual QWidget* configurationWidget();
|
||||
virtual void saveConfig();
|
||||
|
||||
QString username() const;
|
||||
void setUsername( const QString& );
|
||||
QString password() const;
|
||||
void setPassword( const QString& );
|
||||
QString sessionKey() const;
|
||||
void setSessionKey( const QString& );
|
||||
bool scrobble() const;
|
||||
void setScrobble( bool scrobble );
|
||||
|
||||
Attica::Content atticaContent() const;
|
||||
|
||||
private slots:
|
||||
void atticaLoaded( Attica::Content::List );
|
||||
|
||||
void resolverInstalled( const QString& resolverId );
|
||||
|
||||
void resolverChanged();
|
||||
private:
|
||||
void hookupResolver();
|
||||
|
||||
QWeakPointer<Tomahawk::ExternalResolverGui> m_resolver;
|
||||
QWeakPointer<Tomahawk::InfoSystem::LastFmInfoPlugin> m_infoPlugin;
|
||||
QWeakPointer<LastFmConfig> m_configWidget;
|
||||
QPixmap m_icon;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LASTFMACCOUNT_H
|
@@ -1,232 +0,0 @@
|
||||
/* === 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 "LastFmConfig.h"
|
||||
#include "ui_LastFmConfig.h"
|
||||
|
||||
#include "LastFmAccount.h"
|
||||
#include "database/Database.h"
|
||||
#include "database/DatabaseCommand_LogPlayback.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "lastfm/ws.h"
|
||||
#include "lastfm/User"
|
||||
#include "lastfm/XmlQuery"
|
||||
|
||||
using namespace Tomahawk::Accounts;
|
||||
|
||||
|
||||
LastFmConfig::LastFmConfig( LastFmAccount* account )
|
||||
: QWidget( 0 )
|
||||
, m_account( account )
|
||||
, m_page( 1 )
|
||||
, m_lastTimeStamp( 0 )
|
||||
{
|
||||
m_ui = new Ui_LastFmConfig;
|
||||
m_ui->setupUi( this );
|
||||
|
||||
m_ui->progressBar->hide();
|
||||
|
||||
m_ui->username->setText( m_account->username() );
|
||||
m_ui->password->setText( m_account->password() );
|
||||
m_ui->enable->setChecked( m_account->scrobble() );
|
||||
|
||||
connect( m_ui->testLogin, SIGNAL( clicked( bool ) ), SLOT( testLogin() ) );
|
||||
connect( m_ui->importHistory, SIGNAL( clicked( bool ) ), SLOT( loadHistory() ) );
|
||||
|
||||
connect( m_ui->username, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) );
|
||||
connect( m_ui->password, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) );
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
LastFmConfig::password() const
|
||||
{
|
||||
return m_ui->password->text();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
LastFmConfig::scrobble() const
|
||||
{
|
||||
return m_ui->enable->isChecked();
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
LastFmConfig::username() const
|
||||
{
|
||||
return m_ui->username->text().trimmed();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmConfig::testLogin()
|
||||
{
|
||||
m_ui->testLogin->setEnabled( false );
|
||||
m_ui->testLogin->setText( tr( "Testing..." ) );
|
||||
|
||||
QString authToken = TomahawkUtils::md5( ( m_ui->username->text().toLower() + TomahawkUtils::md5( m_ui->password->text().toUtf8() ) ).toUtf8() );
|
||||
|
||||
// now authenticate w/ last.fm and get our session key
|
||||
QMap<QString, QString> query;
|
||||
query[ "method" ] = "auth.getMobileSession";
|
||||
query[ "username" ] = m_ui->username->text().toLower();
|
||||
query[ "authToken" ] = authToken;
|
||||
|
||||
// ensure they have up-to-date settings
|
||||
lastfm::setNetworkAccessManager( TomahawkUtils::nam() );
|
||||
|
||||
QNetworkReply* authJob = lastfm::ws::post( query );
|
||||
|
||||
connect( authJob, SIGNAL( finished() ), SLOT( onLastFmFinished() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmConfig::enableButton()
|
||||
{
|
||||
m_ui->testLogin->setText( tr( "Test Login" ) );
|
||||
m_ui->testLogin->setEnabled( true );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmConfig::loadHistory()
|
||||
{
|
||||
if ( m_lastTimeStamp )
|
||||
{
|
||||
m_ui->importHistory->setText( tr( "Importing %1", "e.g. Importing 2012/01/01" ).arg( QDateTime::fromTime_t( m_lastTimeStamp ).toString( "MMMM d yyyy" ) ) );
|
||||
}
|
||||
else
|
||||
m_ui->importHistory->setText( tr( "Importing History..." ) );
|
||||
|
||||
m_ui->importHistory->setEnabled( false );
|
||||
m_ui->progressBar->show();
|
||||
|
||||
QNetworkReply* reply = lastfm::User( m_ui->username->text().toLower() ).getRecentTracks( 200, m_page );
|
||||
connect( reply, SIGNAL( finished() ), SLOT( onHistoryLoaded() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmConfig::onHistoryLoaded()
|
||||
{
|
||||
int total = 0;
|
||||
bool finished = false;
|
||||
QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
|
||||
|
||||
try
|
||||
{
|
||||
lastfm::XmlQuery lfm = reply->readAll();
|
||||
|
||||
foreach ( lastfm::XmlQuery e, lfm.children( "track" ) )
|
||||
{
|
||||
// tDebug() << "Found:" << e["artist"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt();
|
||||
Tomahawk::query_ptr query = Query::get( e["artist"].text(), e["name"].text(), QString(), QString(), false );
|
||||
m_lastTimeStamp = e["date"].attribute( "uts" ).toUInt();
|
||||
|
||||
DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( query, DatabaseCommand_LogPlayback::Finished, m_lastTimeStamp );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
|
||||
}
|
||||
|
||||
if ( !lfm.children( "recenttracks" ).isEmpty() )
|
||||
{
|
||||
lastfm::XmlQuery stats = lfm.children( "recenttracks" ).first();
|
||||
|
||||
int page = stats.attribute( "page" ).toInt();
|
||||
total = stats.attribute( "totalPages" ).toInt();
|
||||
|
||||
m_ui->progressBar->setMaximum( total );
|
||||
m_ui->progressBar->setValue( page );
|
||||
|
||||
if ( page < total )
|
||||
{
|
||||
m_page = page + 1;
|
||||
loadHistory();
|
||||
}
|
||||
else
|
||||
finished = true;
|
||||
}
|
||||
else
|
||||
finished = true;
|
||||
}
|
||||
catch( lastfm::ws::ParseError e )
|
||||
{
|
||||
tDebug() << "XmlQuery error:" << e.what();
|
||||
finished = true;
|
||||
}
|
||||
|
||||
if ( finished )
|
||||
{
|
||||
if ( m_page != total )
|
||||
{
|
||||
m_ui->importHistory->setText( tr( "History Incomplete. Resume" ) );
|
||||
m_ui->importHistory->setEnabled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui->importHistory->setText( tr( "Playback History Imported" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LastFmConfig::onLastFmFinished()
|
||||
{
|
||||
QNetworkReply* authJob = dynamic_cast<QNetworkReply*>( sender() );
|
||||
if( !authJob )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "No auth job returned!";
|
||||
return;
|
||||
}
|
||||
if( authJob->error() == QNetworkReply::NoError )
|
||||
{
|
||||
lastfm::XmlQuery lfm = lastfm::XmlQuery( authJob->readAll() );
|
||||
|
||||
if( lfm.children( "error" ).size() > 0 )
|
||||
{
|
||||
qDebug() << "ERROR from last.fm:" << lfm.text();
|
||||
m_ui->testLogin->setText( tr( "Failed" ) );
|
||||
m_ui->testLogin->setEnabled( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui->testLogin->setText( tr( "Success" ) );
|
||||
m_ui->testLogin->setEnabled( false );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( authJob->error() )
|
||||
{
|
||||
case QNetworkReply::ContentOperationNotPermittedError:
|
||||
case QNetworkReply::AuthenticationRequiredError:
|
||||
m_ui->testLogin->setText( tr( "Failed" ) );
|
||||
m_ui->testLogin->setEnabled( true );
|
||||
break;
|
||||
|
||||
default:
|
||||
qDebug() << "Couldn't get last.fm auth result";
|
||||
m_ui->testLogin->setText( tr( "Could not contact server" ) );
|
||||
m_ui->testLogin->setEnabled( true );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
/* === 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 LASTFMCONFIG_H
|
||||
#define LASTFMCONFIG_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class Ui_LastFmConfig;
|
||||
|
||||
namespace Tomahawk {
|
||||
|
||||
namespace Accounts {
|
||||
|
||||
class LastFmAccount;
|
||||
|
||||
class LastFmConfig : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LastFmConfig( LastFmAccount* account );
|
||||
|
||||
QString username() const;
|
||||
QString password() const;
|
||||
bool scrobble() const;
|
||||
|
||||
public slots:
|
||||
void testLogin();
|
||||
void onLastFmFinished();
|
||||
|
||||
private slots:
|
||||
void enableButton();
|
||||
|
||||
void loadHistory();
|
||||
void onHistoryLoaded();
|
||||
|
||||
private:
|
||||
LastFmAccount* m_account;
|
||||
Ui_LastFmConfig* m_ui;
|
||||
|
||||
unsigned int m_page;
|
||||
unsigned int m_lastTimeStamp;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // LASTFMCONFIG_H
|
@@ -1,102 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LastFmConfig</class>
|
||||
<widget class="QWidget" name="LastFmConfig">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>253</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="margin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../../resources.qrc">:/data/images/lastfm-icon.png</pixmap>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enable">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Scrobble tracks to Last.fm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Username:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="username"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Password:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="password">
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="testLogin">
|
||||
<property name="text">
|
||||
<string>Test Login</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="importHistory">
|
||||
<property name="text">
|
||||
<string>Import Playback History</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../../resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
@@ -1,989 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2010-2011, Hugo Lindström <hugolm84@gmail.com>
|
||||
*
|
||||
* 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 "SpotifyAccount.h"
|
||||
#include "Playlist.h"
|
||||
#include "playlist/PlaylistUpdaterInterface.h"
|
||||
#include "SourceList.h"
|
||||
#include "SpotifyAccountConfig.h"
|
||||
#include "SpotifyPlaylistUpdater.h"
|
||||
#include "resolvers/ScriptResolver.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
#include "ActionCollection.h"
|
||||
#include "Pipeline.h"
|
||||
#include "accounts/AccountManager.h"
|
||||
#include "utils/Closure.h"
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#include "jobview/ErrorStatusMessage.h"
|
||||
#endif
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QAction>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
|
||||
using namespace Tomahawk;
|
||||
using namespace Accounts;
|
||||
|
||||
|
||||
static QPixmap* s_icon = 0;
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
static QString s_resolverId = "spotify-osx";
|
||||
#elif defined(Q_OS_WIN)
|
||||
static QString s_resolverId = "spotify-win";
|
||||
#elif defined(Q_OS_LINUX) && defined(__GNUC__) && defined(__x86_64__)
|
||||
static QString s_resolverId = "spotify-linux-x64";
|
||||
#elif defined(Q_OS_LINUX)
|
||||
static QString s_resolverId = "spotify-linux-x86";
|
||||
#else
|
||||
static QString s_resolverId = "spotify-unknown";
|
||||
#endif
|
||||
|
||||
Account*
|
||||
SpotifyAccountFactory::createAccount( const QString& accountId )
|
||||
{
|
||||
return new SpotifyAccount( accountId );
|
||||
}
|
||||
|
||||
|
||||
QPixmap
|
||||
SpotifyAccountFactory::icon() const
|
||||
{
|
||||
if ( !s_icon )
|
||||
s_icon = new QPixmap( RESPATH "images/spotify-logo.png" );
|
||||
|
||||
return *s_icon;
|
||||
}
|
||||
|
||||
|
||||
SpotifyAccount::SpotifyAccount( const QString& accountId )
|
||||
: CustomAtticaAccount( accountId )
|
||||
, m_preventEnabling( false )
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
SpotifyAccount::~SpotifyAccount()
|
||||
{
|
||||
clearUser();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::init()
|
||||
{
|
||||
setAccountFriendlyName( "Spotify" );
|
||||
setAccountServiceName( "spotify" );
|
||||
|
||||
AtticaManager::instance()->registerCustomAccount( s_resolverId, this );
|
||||
qRegisterMetaType< Tomahawk::Accounts::SpotifyPlaylistInfo* >( "Tomahawk::Accounts::SpotifyPlaylist*" );
|
||||
|
||||
if ( !AtticaManager::instance()->resolversLoaded() )
|
||||
{
|
||||
// If we're still waiting to load, wait for the attica resolvers to come down the pipe
|
||||
connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( delayedInit() ), Qt::UniqueConnection );
|
||||
}
|
||||
else
|
||||
{
|
||||
delayedInit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::delayedInit()
|
||||
{
|
||||
|
||||
connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( resolverInstalled( QString ) ) );
|
||||
|
||||
const Attica::Content res = AtticaManager::instance()->resolverForId( s_resolverId );
|
||||
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
|
||||
|
||||
const QString path = configuration().value( "path" ).toString(); // Manual path override
|
||||
if ( !checkForResolver() && state != AtticaManager::Uninstalled )
|
||||
{
|
||||
// If the user manually deleted the resolver, mark it as uninstalled, so we re-fetch for the user
|
||||
AtticaManager::instance()->uninstallResolver( res );
|
||||
}
|
||||
else if ( state == AtticaManager::Installed || !path.isEmpty() )
|
||||
{
|
||||
if ( !path.isEmpty() )
|
||||
{
|
||||
QFileInfo info( path );
|
||||
// Resolver was deleted, so abort.
|
||||
if ( !info.exists() )
|
||||
return;
|
||||
}
|
||||
hookupResolver();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpotifyAccount::hookupResolver()
|
||||
{
|
||||
// initialize the resolver itself. this is called if the account actually has an installed spotify resolver,
|
||||
// as it might not.
|
||||
// If there is a spotify resolver from attica installed, create the corresponding ExternalResolver* and hook up to it
|
||||
QString path = configuration().value( "path" ).toString();
|
||||
if ( path.isEmpty() )
|
||||
{
|
||||
const Attica::Content res = AtticaManager::instance()->resolverForId( s_resolverId );
|
||||
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
|
||||
Q_ASSERT( state == AtticaManager::Installed );
|
||||
Q_UNUSED( state );
|
||||
|
||||
const AtticaManager::Resolver data = AtticaManager::instance()->resolverData( res.id() );
|
||||
path = data.scriptPath;
|
||||
}
|
||||
|
||||
qDebug() << "Starting spotify resolver with path:" << path;
|
||||
m_spotifyResolver = QWeakPointer< ScriptResolver >( qobject_cast< ScriptResolver* >( Pipeline::instance()->addScriptResolver( path, enabled() ) ) );
|
||||
|
||||
connect( m_spotifyResolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) );
|
||||
connect( m_spotifyResolver.data(), SIGNAL( customMessage( QString,QVariantMap ) ), this, SLOT( resolverMessage( QString, QVariantMap ) ) );
|
||||
|
||||
const bool hasMigrated = configuration().value( "hasMigrated" ).toBool();
|
||||
if ( !hasMigrated )
|
||||
{
|
||||
qDebug() << "Getting credentials from spotify resolver to migrate to in-app config";
|
||||
QVariantMap msg;
|
||||
msg[ "_msgtype" ] = "getCredentials";
|
||||
m_spotifyResolver.data()->sendMessage( msg );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SpotifyAccount::checkForResolver()
|
||||
{
|
||||
#if defined(Q_OS_MAC)
|
||||
const QDir path = QCoreApplication::applicationDirPath();
|
||||
QFile file( path.absoluteFilePath( "spotify_tomahawkresolver" ) );
|
||||
return file.exists();
|
||||
#elif defined(Q_OS_WIN)
|
||||
QDir appDataDir = TomahawkUtils::appDataDir();
|
||||
return appDataDir.exists( QString( "atticaresolvers/%1/spotify_tomahawkresolver.exe" ).arg( s_resolverId ) );
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
SpotifyAccount::resolverChanged()
|
||||
{
|
||||
emit connectionStateChanged( connectionState() );
|
||||
}
|
||||
|
||||
|
||||
Attica::Content
|
||||
SpotifyAccount::atticaContent() const
|
||||
{
|
||||
return AtticaManager::instance()->resolverForId( s_resolverId );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::authenticate()
|
||||
{
|
||||
if ( !AtticaManager::instance()->resolversLoaded() )
|
||||
{
|
||||
// If we're still waiting to load, wait for the attica resolvers to come down the pipe
|
||||
connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( atticaLoaded( Attica::Content::List ) ), Qt::UniqueConnection );
|
||||
return;
|
||||
}
|
||||
|
||||
const Attica::Content res = AtticaManager::instance()->resolverForId( s_resolverId );
|
||||
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
|
||||
|
||||
qDebug() << "Spotify account authenticating...";
|
||||
if ( m_spotifyResolver.isNull() && state == AtticaManager::Installed )
|
||||
{
|
||||
// We don;t have the resolver but it has been installed via attica already, so lets just turn it on
|
||||
qDebug() << "No valid spotify resolver running, but attica reports it is installed, so start it up";
|
||||
hookupResolver();
|
||||
}
|
||||
else if ( m_spotifyResolver.isNull() )
|
||||
{
|
||||
qDebug() << "Got null resolver but asked to authenticate, so installing if we have one from attica:" << res.isValid() << res.id();
|
||||
if ( res.isValid() && !res.id().isEmpty() )
|
||||
AtticaManager::instance()->installResolver( res, false );
|
||||
else
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
m_preventEnabling = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if ( !m_spotifyResolver.data()->running() )
|
||||
{
|
||||
qDebug() << "Spotify resolver exists but stopped, starting";
|
||||
m_spotifyResolver.data()->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Spotify resolver exists and is running, ignore authentication attempt";
|
||||
}
|
||||
|
||||
emit connectionStateChanged( connectionState() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::deauthenticate()
|
||||
{
|
||||
if ( !m_spotifyResolver.isNull() && m_spotifyResolver.data()->running() )
|
||||
m_spotifyResolver.data()->stop();
|
||||
|
||||
emit connectionStateChanged( connectionState() );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SpotifyAccount::isAuthenticated() const
|
||||
{
|
||||
return !m_spotifyResolver.isNull() && m_spotifyResolver.data()->running();
|
||||
}
|
||||
|
||||
|
||||
Account::ConnectionState
|
||||
SpotifyAccount::connectionState() const
|
||||
{
|
||||
return (!m_spotifyResolver.isNull() && m_spotifyResolver.data()->running()) ? Account::Connected : Account::Disconnected;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::resolverInstalled(const QString& resolverId)
|
||||
{
|
||||
if ( resolverId == s_resolverId )
|
||||
{
|
||||
// We requested this install, so we want to launch it
|
||||
hookupResolver();
|
||||
AccountManager::instance()->enableAccount( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::atticaLoaded( Attica::Content::List )
|
||||
{
|
||||
disconnect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( atticaLoaded( Attica::Content::List ) ) );
|
||||
authenticate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::setManualResolverPath( const QString &resolverPath )
|
||||
{
|
||||
Q_ASSERT( !resolverPath.isEmpty() );
|
||||
|
||||
QVariantHash conf = configuration();
|
||||
conf[ "path" ] = resolverPath;
|
||||
setConfiguration( conf );
|
||||
sync();
|
||||
|
||||
m_preventEnabling = false;
|
||||
|
||||
if ( !m_spotifyResolver.isNull() )
|
||||
{
|
||||
// replace
|
||||
NewClosure( m_spotifyResolver.data(), SIGNAL( destroyed() ), this, SLOT( hookupAfterDeletion( bool ) ), true );
|
||||
m_spotifyResolver.data()->deleteLater();
|
||||
}
|
||||
else
|
||||
{
|
||||
hookupResolver();
|
||||
AccountManager::instance()->enableAccount( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::hookupAfterDeletion( bool autoEnable )
|
||||
{
|
||||
hookupResolver();
|
||||
if ( autoEnable )
|
||||
AccountManager::instance()->enableAccount( this );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::aboutToShow( QAction* action, const playlist_ptr& playlist )
|
||||
{
|
||||
if ( !m_customActions.contains( action ) )
|
||||
return;
|
||||
|
||||
// If it's not being synced, allow the option to sync
|
||||
bool found = false;
|
||||
QList<PlaylistUpdaterInterface*> updaters = playlist->updaters();
|
||||
foreach ( PlaylistUpdaterInterface* updater, updaters )
|
||||
{
|
||||
if ( SpotifyPlaylistUpdater* spotifyUpdater = qobject_cast< SpotifyPlaylistUpdater* >( updater ) )
|
||||
{
|
||||
if ( spotifyUpdater->sync() )
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !found )
|
||||
{
|
||||
action->setText( tr( "Sync with Spotify" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
action->setText( tr( "Stop syncing with Spotify" ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::syncActionTriggered( bool checked )
|
||||
{
|
||||
Q_UNUSED( checked );
|
||||
QAction* action = qobject_cast< QAction* >( sender() );
|
||||
|
||||
if ( !action || !m_customActions.contains( action ) )
|
||||
return;
|
||||
|
||||
const playlist_ptr playlist = action->property( "payload" ).value< playlist_ptr >();
|
||||
if ( playlist.isNull() )
|
||||
{
|
||||
qWarning() << "Got context menu spotify sync action triggered, but invalid playlist payload!";
|
||||
Q_ASSERT( false );
|
||||
return;
|
||||
}
|
||||
|
||||
SpotifyPlaylistUpdater* updater = 0;
|
||||
QList<PlaylistUpdaterInterface*> updaters = playlist->updaters();
|
||||
foreach ( PlaylistUpdaterInterface* u, updaters )
|
||||
{
|
||||
if ( SpotifyPlaylistUpdater* spotifyUpdater = qobject_cast< SpotifyPlaylistUpdater* >( u ) )
|
||||
{
|
||||
updater = spotifyUpdater;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !updater )
|
||||
{
|
||||
QVariantMap msg;
|
||||
msg[ "_msgtype" ] = "createPlaylist";
|
||||
msg[ "sync" ] = true;
|
||||
msg[ "title" ] = playlist->title();
|
||||
|
||||
QList< query_ptr > queries;
|
||||
foreach ( const plentry_ptr& ple, playlist->entries() )
|
||||
queries << ple->query();
|
||||
QVariantList tracks = SpotifyPlaylistUpdater::queriesToVariant( queries );
|
||||
msg[ "tracks" ] = tracks;
|
||||
|
||||
const QString qid = sendMessage( msg, this, "playlistCreated" );
|
||||
m_waitingForCreateReply[ qid ] = playlist;
|
||||
}
|
||||
else
|
||||
{
|
||||
SpotifyPlaylistInfo* info = 0;
|
||||
foreach ( SpotifyPlaylistInfo* ifo, m_allSpotifyPlaylists )
|
||||
{
|
||||
if ( ifo->plid == updater->spotifyId() )
|
||||
{
|
||||
info = ifo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Q_ASSERT( info );
|
||||
if ( info )
|
||||
info->sync = !updater->sync();
|
||||
|
||||
if ( m_configWidget.data() )
|
||||
m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists );
|
||||
|
||||
if ( !updater->sync() )
|
||||
{
|
||||
startPlaylistSync( info );
|
||||
}
|
||||
else
|
||||
{
|
||||
stopPlaylistSync( info, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg )
|
||||
{
|
||||
if ( msgType == "credentials" )
|
||||
{
|
||||
QVariantHash creds = credentials();
|
||||
|
||||
creds[ "username" ] = msg.value( "username" );
|
||||
creds[ "password" ] = msg.value( "password" );
|
||||
creds[ "highQuality" ] = msg.value( "highQuality" );
|
||||
setCredentials( creds );
|
||||
|
||||
qDebug() << "Set creds:" << creds.value( "username" ) << creds.value( "password" ) << msg.value( "username" ) << msg.value( "password" );
|
||||
|
||||
QVariantHash config = configuration();
|
||||
config[ "hasMigrated" ] = true;
|
||||
setConfiguration( config );
|
||||
sync();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const QString qid = msg.value( "qid" ).toString();
|
||||
if ( m_qidToSlotMap.contains( qid ) )
|
||||
{
|
||||
QObject* receiver = m_qidToSlotMap[ qid ].first;
|
||||
QString slot = m_qidToSlotMap[ qid ].second;
|
||||
m_qidToSlotMap.remove( qid );
|
||||
|
||||
QMetaObject::invokeMethod( receiver, slot.toLatin1(), Q_ARG( QString, msgType ), Q_ARG( QVariantMap, msg ) );
|
||||
}
|
||||
else if ( msgType == "allPlaylists" )
|
||||
{
|
||||
const QVariantList playlists = msg.value( "playlists" ).toList();
|
||||
qDeleteAll( m_allSpotifyPlaylists );
|
||||
m_allSpotifyPlaylists.clear();
|
||||
|
||||
foreach ( const QVariant& playlist, playlists )
|
||||
{
|
||||
const QVariantMap plMap = playlist.toMap();
|
||||
const QString name = plMap.value( "name" ).toString();
|
||||
const QString plid = plMap.value( "id" ).toString();
|
||||
const QString revid = plMap.value( "revid" ).toString();
|
||||
const bool sync = plMap.value( "sync" ).toBool();
|
||||
|
||||
if ( name.isNull() || plid.isNull() || revid.isNull() )
|
||||
{
|
||||
qDebug() << "Did not get name and plid and revid for spotify playlist:" << name << plid << revid << plMap;
|
||||
continue;
|
||||
}
|
||||
m_allSpotifyPlaylists << new SpotifyPlaylistInfo( name, plid, revid, sync );
|
||||
}
|
||||
|
||||
if ( !m_configWidget.isNull() )
|
||||
{
|
||||
m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists );
|
||||
}
|
||||
}
|
||||
else if ( msgType == "tracksAdded" )
|
||||
{
|
||||
const QString plid = msg.value( "playlistid" ).toString();
|
||||
// We should already be syncing this playlist if we get updates for it
|
||||
// Q_ASSERT( m_updaters.contains( plid ) );
|
||||
|
||||
if ( !m_updaters.contains( plid ) )
|
||||
return;
|
||||
|
||||
SpotifyPlaylistUpdater* updater = m_updaters[ plid ];
|
||||
Q_ASSERT( updater->sync() );
|
||||
|
||||
const QString startPos = msg.value( "startPosition" ).toString();
|
||||
const QVariantList tracksList = msg.value( "tracks" ).toList();
|
||||
const QString newRev = msg.value( "revid" ).toString();
|
||||
const QString oldRev = msg.value( "oldRev" ).toString();
|
||||
|
||||
updater->spotifyTracksAdded( tracksList, startPos, newRev, oldRev );
|
||||
}
|
||||
else if ( msgType == "tracksRemoved" )
|
||||
{
|
||||
const QString plid = msg.value( "playlistid" ).toString();
|
||||
// We should already be syncing this playlist if we get updates for it
|
||||
// Q_ASSERT( m_updaters.contains( plid ) );
|
||||
|
||||
if ( !m_updaters.contains( plid ) )
|
||||
return;
|
||||
|
||||
SpotifyPlaylistUpdater* updater = m_updaters[ plid ];
|
||||
|
||||
// If we're not syncing with this, the resolver is quite misinformed.
|
||||
// Q_ASSERT( updater && updater->sync() );
|
||||
if ( !updater || !updater->sync() )
|
||||
return;
|
||||
|
||||
const QVariantList tracksList = msg.value( "trackPositions" ).toList();
|
||||
const QString newRev = msg.value( "revid" ).toString();
|
||||
const QString oldRev = msg.value( "oldRev" ).toString();
|
||||
|
||||
|
||||
updater->spotifyTracksRemoved( tracksList, newRev, oldRev );
|
||||
}
|
||||
else if ( msgType == "tracksMoved" )
|
||||
{
|
||||
const QString plid = msg.value( "playlistid" ).toString();
|
||||
// We should already be syncing this playlist if we get updates for it
|
||||
Q_ASSERT( m_updaters.contains( plid ) );
|
||||
|
||||
if ( !m_updaters.contains( plid ) )
|
||||
return;
|
||||
|
||||
SpotifyPlaylistUpdater* updater = m_updaters[ plid ];
|
||||
Q_ASSERT( updater->sync() );
|
||||
|
||||
const QString newStartPos = msg.value( "newStartPosition" ).toString();
|
||||
const QVariantList tracksList = msg.value( "tracks" ).toList();
|
||||
const QString newRev = msg.value( "revid" ).toString();
|
||||
const QString oldRev = msg.value( "oldRev" ).toString();
|
||||
|
||||
updater->spotifyTracksMoved( tracksList, newStartPos, newRev, oldRev );
|
||||
}
|
||||
else if( msgType == "playlistRenamed" )
|
||||
{
|
||||
const QString plid = msg.value( "id" ).toString();
|
||||
// We should already be syncing this playlist if we get updates for it
|
||||
//Q_ASSERT( m_updaters.contains( plid ) );
|
||||
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if ( !m_updaters.contains( plid ) )
|
||||
return;
|
||||
|
||||
SpotifyPlaylistUpdater* updater = m_updaters[ plid ];
|
||||
Q_ASSERT( updater->sync() );
|
||||
|
||||
qDebug() << "Playlist renamed fetched in tomahawk";
|
||||
const QString title = msg.value( "name" ).toString();
|
||||
const QString newRev = msg.value( "revid" ).toString();
|
||||
const QString oldRev = msg.value( "oldRev" ).toString();
|
||||
|
||||
updater->spotifyPlaylistRenamed( title, newRev, oldRev );
|
||||
}
|
||||
else if( msgType == "spotifyError" )
|
||||
{
|
||||
const QString error = msg.value( "msg" ).toString();
|
||||
if( error.isEmpty() )
|
||||
return;
|
||||
|
||||
if( msg.value( "isDebugMsg" ).toBool() )
|
||||
tDebug( LOGVERBOSE ) << "SpotifyResolverError: " << error;
|
||||
else
|
||||
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( QString( "Spotify: %1" ).arg( error ) ) );
|
||||
}
|
||||
else if( msgType == "userChanged" )
|
||||
{
|
||||
const QString rmsg = msg.value( "msg" ).toString();
|
||||
clearUser( true );
|
||||
|
||||
if ( m_configWidget.data() )
|
||||
m_configWidget.data()->setPlaylists( QList< SpotifyPlaylistInfo* >() );
|
||||
|
||||
qDebug() << "User changed message from spotify:" << rmsg;
|
||||
}
|
||||
else if ( msgType == "loginResponse" )
|
||||
{
|
||||
QVariantHash creds = credentials();
|
||||
creds[ "username" ] = msg.value( "username" ).toString();
|
||||
creds[ "password" ] = msg.value( "password" ).toString();
|
||||
creds[ "highQuality" ] = msg.value( "highQuality" ).toString();
|
||||
setCredentials( creds );
|
||||
sync();
|
||||
|
||||
const bool success = msg.value( "success" ).toBool();
|
||||
|
||||
if ( success )
|
||||
createActions();
|
||||
|
||||
configurationWidget(); // ensure it's created so we can set the login button
|
||||
if ( m_configWidget.data() )
|
||||
{
|
||||
const QString message = msg.value( "message" ).toString();
|
||||
m_configWidget.data()->loginResponse( success, message );
|
||||
}
|
||||
}
|
||||
else if ( msgType == "playlistDeleted" )
|
||||
{
|
||||
const QString plid = msg.value( "playlistid" ).toString();
|
||||
|
||||
if ( !m_updaters.contains( plid ) )
|
||||
return;
|
||||
|
||||
SpotifyPlaylistUpdater* updater = m_updaters.take( plid );
|
||||
updater->remove( false );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::clearUser( bool permanentlyDelete )
|
||||
{
|
||||
foreach( SpotifyPlaylistUpdater* updater, m_updaters.values() )
|
||||
{
|
||||
if ( permanentlyDelete )
|
||||
updater->remove( false );
|
||||
else
|
||||
updater->deleteLater();
|
||||
}
|
||||
|
||||
m_updaters.clear();
|
||||
|
||||
qDeleteAll( m_allSpotifyPlaylists );
|
||||
m_allSpotifyPlaylists.clear();
|
||||
|
||||
m_qidToSlotMap.clear();
|
||||
m_waitingForCreateReply.clear();
|
||||
|
||||
removeActions();
|
||||
}
|
||||
|
||||
|
||||
QPixmap
|
||||
SpotifyAccount::icon() const
|
||||
{
|
||||
if ( !s_icon )
|
||||
s_icon = new QPixmap( RESPATH "images/spotify-logo.png" );
|
||||
|
||||
return *s_icon;
|
||||
}
|
||||
|
||||
|
||||
QWidget*
|
||||
SpotifyAccount::configurationWidget()
|
||||
{
|
||||
if ( m_spotifyResolver.isNull() )
|
||||
return 0;
|
||||
|
||||
if ( m_configWidget.isNull() )
|
||||
{
|
||||
m_configWidget = QWeakPointer< SpotifyAccountConfig >( new SpotifyAccountConfig( this ) );
|
||||
connect( m_configWidget.data(), SIGNAL( login( QString,QString ) ), this, SLOT( login( QString,QString ) ) );
|
||||
m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists );
|
||||
}
|
||||
|
||||
return static_cast< QWidget* >( m_configWidget.data() );
|
||||
}
|
||||
|
||||
|
||||
QWidget*
|
||||
SpotifyAccount::aboutWidget()
|
||||
{
|
||||
if ( m_aboutWidget.isNull() )
|
||||
{
|
||||
QWidget* w = new QWidget();
|
||||
w->hide();
|
||||
|
||||
QHBoxLayout* l = new QHBoxLayout( w );
|
||||
QLabel* pm = new QLabel( w );
|
||||
pm->setPixmap( QPixmap( RESPATH "images/spotifycore-logo" ) );
|
||||
QLabel* text = new QLabel( "This product uses SPOTIFY(R) CORE but is not endorsed, certified or otherwise approved in any way by Spotify. Spotify is the registered trade mark of the Spotify Group.", w );
|
||||
text->setWordWrap( true );
|
||||
l->addWidget( pm );
|
||||
l->addWidget( text );
|
||||
w->setLayout( l );
|
||||
m_aboutWidget = QWeakPointer< QWidget >( w );
|
||||
}
|
||||
|
||||
return m_aboutWidget.data();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::saveConfig()
|
||||
{
|
||||
Q_ASSERT( !m_configWidget.isNull() );
|
||||
if ( m_configWidget.isNull() )
|
||||
return;
|
||||
|
||||
QVariantHash creds = credentials();
|
||||
if ( creds.value( "username" ).toString() != m_configWidget.data()->username() ||
|
||||
creds.value( "password" ).toString() != m_configWidget.data()->password() ||
|
||||
creds.value( "highQuality" ).toBool() != m_configWidget.data()->highQuality() )
|
||||
{
|
||||
creds[ "username" ] = m_configWidget.data()->username();
|
||||
creds[ "password" ] = m_configWidget.data()->password();
|
||||
creds[ "highQuality" ] = m_configWidget.data()->highQuality();
|
||||
setCredentials( creds );
|
||||
|
||||
}
|
||||
|
||||
QVariantHash config = configuration();
|
||||
config[ "deleteOnUnsync" ] = m_configWidget.data()->deleteOnUnsync();
|
||||
setConfiguration( config );
|
||||
|
||||
m_configWidget.data()->saveSettings();
|
||||
foreach ( SpotifyPlaylistInfo* pl, m_allSpotifyPlaylists )
|
||||
{
|
||||
// qDebug() << "Checking changed state:" << pl->changed << pl->name << pl->sync;
|
||||
if ( pl->changed )
|
||||
{
|
||||
pl->changed = false;
|
||||
if ( pl->sync )
|
||||
{
|
||||
// Fetch full playlist contents, then begin the sync
|
||||
startPlaylistSync( pl );
|
||||
}
|
||||
else
|
||||
stopPlaylistSync( pl );
|
||||
}
|
||||
}
|
||||
sync();
|
||||
|
||||
if ( !m_configWidget.data()->loggedInManually() && !m_configWidget.data()->username().isEmpty() && !m_configWidget.data()->password().isEmpty() )
|
||||
{
|
||||
// If the user never pressed log in, he might have just pressed ok or hit enter. So log in anyway
|
||||
login( m_configWidget.data()->username(), m_configWidget.data()->password() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::login( const QString& username, const QString& password )
|
||||
{
|
||||
// Send the result to the resolver
|
||||
QVariantMap msg;
|
||||
msg[ "_msgtype" ] = "login";
|
||||
msg[ "username" ] = username;
|
||||
msg[ "password" ] = password;
|
||||
|
||||
msg[ "highQuality" ] = m_configWidget.data()->highQuality();
|
||||
|
||||
m_spotifyResolver.data()->sendMessage( msg );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::startPlaylistSync( SpotifyPlaylistInfo* playlist )
|
||||
{
|
||||
if ( !playlist )
|
||||
return;
|
||||
|
||||
QVariantMap msg;
|
||||
msg[ "_msgtype" ] = "getPlaylist";
|
||||
msg[ "playlistid" ] = playlist->plid;
|
||||
msg[ "sync" ] = playlist->sync;
|
||||
|
||||
sendMessage( msg, this, "startPlaylistSyncWithPlaylist" );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::startPlaylistSyncWithPlaylist( const QString& msgType, const QVariantMap& msg )
|
||||
{
|
||||
Q_UNUSED( msgType );
|
||||
qDebug() << Q_FUNC_INFO << "Got full spotify playlist body, creating a tomahawk playlist and enabling sync!!";
|
||||
const QString id = msg.value( "id" ).toString();
|
||||
const QString name = msg.value( "name" ).toString();
|
||||
const QString revid = msg.value( "revid" ).toString();
|
||||
|
||||
qDebug() << "Starting sync with pl:" << id << name;
|
||||
QVariantList tracks = msg.value( "tracks" ).toList();
|
||||
|
||||
// create a list of query/plentries directly
|
||||
QList< query_ptr > queries = SpotifyPlaylistUpdater::variantToQueries( tracks );
|
||||
|
||||
/**
|
||||
* Begin syncing a playlist. Two options:
|
||||
* 1) This is a playlist that has never been synced to tomahawk. Create a new one
|
||||
* and attach a new SpotifyPlaylistUpdater to it
|
||||
* 2) This was previously synced, and has since been unsynced. THe playlist is still around
|
||||
* with an inactive SpotifyPlaylistUpdater, so just enable it and bring it up to date by merging current with new
|
||||
* TODO: show a warning( "Do you want to overwrite with spotify's version?" )
|
||||
*/
|
||||
if ( m_updaters.contains( id ) )
|
||||
{
|
||||
Q_ASSERT( m_updaters[ id ]->sync() == false ); /// Should have been unchecked/off before
|
||||
m_updaters[ id ]->setSync( true );
|
||||
// m_updaters[ id ]->
|
||||
// TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
playlist_ptr plPtr = Tomahawk::Playlist::create( SourceList::instance()->getLocal(),
|
||||
uuid(),
|
||||
name,
|
||||
QString(),
|
||||
QString(),
|
||||
false,
|
||||
queries );
|
||||
|
||||
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( this, revid, id, plPtr );
|
||||
updater->setSync( true );
|
||||
m_updaters[ id ] = updater;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::playlistCreated( const QString& msgType, const QVariantMap& msg )
|
||||
{
|
||||
Q_UNUSED( msgType );
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "Got response from our createPlaylist command, now creating updater and attaching";
|
||||
const bool success = msg.value( "success" ).toBool();
|
||||
|
||||
if ( !success )
|
||||
{
|
||||
qWarning() << "Got FAILED return code from spotify resolver createPlaylist command, aborting sync";
|
||||
return;
|
||||
}
|
||||
|
||||
const QString id = msg.value( "playlistid" ).toString();
|
||||
const QString revid = msg.value( "playlistid" ).toString();
|
||||
const QString qid = msg.value( "qid" ).toString();
|
||||
|
||||
if ( !m_waitingForCreateReply.contains( qid ) )
|
||||
{
|
||||
qWarning() << "Got a createPlaylist reply for a playlist/qid we were not waiting for :-/ " << qid << m_waitingForCreateReply;
|
||||
return;
|
||||
}
|
||||
|
||||
playlist_ptr playlist = m_waitingForCreateReply.take( qid );
|
||||
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( this, revid, id, playlist );
|
||||
updater->setSync( true );
|
||||
m_updaters[ id ] = updater;
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
SpotifyAccount::sendMessage( const QVariantMap &m, QObject* obj, const QString& slot )
|
||||
{
|
||||
QVariantMap msg = m;
|
||||
QString qid;
|
||||
|
||||
if ( obj )
|
||||
{
|
||||
qid = QUuid::createUuid().toString().replace( "{", "" ).replace( "}", "" );
|
||||
|
||||
m_qidToSlotMap[ qid ] = qMakePair( obj, slot );
|
||||
msg[ "qid" ] = qid;
|
||||
|
||||
}
|
||||
|
||||
m_spotifyResolver.data()->sendMessage( msg );
|
||||
|
||||
return qid;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::registerUpdaterForPlaylist( const QString& plId, SpotifyPlaylistUpdater* updater )
|
||||
{
|
||||
m_updaters[ plId ] = updater;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::unregisterUpdater( const QString& plid )
|
||||
{
|
||||
m_updaters.remove( plid );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::fetchFullPlaylist( SpotifyPlaylistInfo* playlist )
|
||||
{
|
||||
Q_UNUSED( playlist );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SpotifyAccount::deleteOnUnsync() const
|
||||
{
|
||||
return configuration().value( "deleteOnUnsync", false ).toBool();
|
||||
}
|
||||
|
||||
void
|
||||
SpotifyAccount::stopPlaylistSync( SpotifyPlaylistInfo* playlist, bool forceDontDelete )
|
||||
{
|
||||
if ( !playlist )
|
||||
return;
|
||||
|
||||
QVariantMap msg;
|
||||
msg[ "_msgtype" ] = "removeFromSyncList";
|
||||
msg[ "playlistid" ] = playlist->plid;
|
||||
|
||||
m_spotifyResolver.data()->sendMessage( msg );
|
||||
|
||||
if ( m_updaters.contains( playlist->plid ) )
|
||||
{
|
||||
SpotifyPlaylistUpdater* updater = m_updaters[ playlist->plid ];
|
||||
updater->setSync( false );
|
||||
|
||||
if ( deleteOnUnsync() && !forceDontDelete )
|
||||
{
|
||||
playlist_ptr tomahawkPl = updater->playlist();
|
||||
|
||||
if ( !tomahawkPl.isNull() )
|
||||
Playlist::remove( tomahawkPl );
|
||||
|
||||
updater->deleteLater();
|
||||
|
||||
}
|
||||
|
||||
updater->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::loadPlaylists()
|
||||
{
|
||||
// TODO cache this and only get changed?
|
||||
QVariantMap msg;
|
||||
msg[ "_msgtype" ] = "getAllPlaylists";
|
||||
sendMessage( msg, this, "allPlaylistsLoaded" );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::setSyncForPlaylist( const QString& spotifyPlaylistId, bool sync )
|
||||
{
|
||||
foreach ( SpotifyPlaylistInfo* info, m_allSpotifyPlaylists )
|
||||
{
|
||||
if( info->plid == spotifyPlaylistId )
|
||||
info->sync = sync;
|
||||
}
|
||||
|
||||
if ( !m_configWidget.isNull() )
|
||||
m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::createActions()
|
||||
{
|
||||
if ( !m_customActions.isEmpty() )
|
||||
return;
|
||||
|
||||
QAction* action = new QAction( 0 );
|
||||
action->setIcon( QIcon( RESPATH "images/spotify-logo.png" ) );
|
||||
connect( action, SIGNAL( triggered( bool ) ), this, SLOT( syncActionTriggered( bool ) ) );
|
||||
ActionCollection::instance()->addAction( ActionCollection::LocalPlaylists, action, this );
|
||||
m_customActions.append( action );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::removeActions()
|
||||
{
|
||||
foreach( QAction* action, m_customActions )
|
||||
ActionCollection::instance()->removeAction( action );
|
||||
|
||||
m_customActions.clear();
|
||||
}
|
||||
|
@@ -1,164 +0,0 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2010-2011, Hugo Lindström <hugolm84@gmail.com>
|
||||
*
|
||||
* 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 SpotifyAccount_H
|
||||
#define SpotifyAccount_H
|
||||
|
||||
#include "accounts/ResolverAccount.h"
|
||||
#include "SourceList.h"
|
||||
#include "AtticaManager.h"
|
||||
#include "Playlist.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
#include "utils/SmartPointerList.h"
|
||||
|
||||
class QAction;
|
||||
class SpotifyPlaylistUpdater;
|
||||
class QTimer;
|
||||
|
||||
class ScriptResolver;
|
||||
|
||||
namespace Tomahawk {
|
||||
namespace Accounts {
|
||||
|
||||
class SpotifyAccountConfig;
|
||||
|
||||
// metadata for a playlist
|
||||
struct SpotifyPlaylistInfo {
|
||||
QString name, plid, revid;
|
||||
bool sync, changed;
|
||||
|
||||
|
||||
SpotifyPlaylistInfo( const QString& nname, const QString& pid, const QString& rrevid, bool ssync )
|
||||
: name( nname ), plid( pid ), revid( rrevid ), sync( ssync ), changed( false ) {}
|
||||
|
||||
SpotifyPlaylistInfo() : sync( false ), changed( false ) {}
|
||||
};
|
||||
|
||||
|
||||
class SpotifyAccountFactory : public AccountFactory
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpotifyAccountFactory() {}
|
||||
|
||||
virtual Account* createAccount( const QString& accountId = QString() );
|
||||
virtual QString description() const { return tr( "Play music from and sync your playlists with Spotify Premium" ); }
|
||||
virtual QString factoryId() const { return "spotifyaccount"; }
|
||||
virtual QString prettyName() const { return "Spotify"; }
|
||||
|
||||
virtual AccountTypes types() const { return AccountTypes( ResolverType ); }
|
||||
virtual bool allowUserCreation() const { return false; }
|
||||
virtual QPixmap icon() const;
|
||||
virtual bool isUnique() const { return true; }
|
||||
|
||||
};
|
||||
|
||||
class SpotifyAccount : public CustomAtticaAccount
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpotifyAccount( const QString& accountId );
|
||||
SpotifyAccount( const QString& accountId, const QString& path );
|
||||
virtual ~SpotifyAccount();
|
||||
|
||||
virtual QPixmap icon() const;
|
||||
virtual QWidget* configurationWidget();
|
||||
virtual QWidget* aboutWidget();
|
||||
virtual void saveConfig();
|
||||
virtual Attica::Content atticaContent() const;
|
||||
virtual void authenticate();
|
||||
virtual ConnectionState connectionState() const;
|
||||
virtual bool isAuthenticated() const;
|
||||
virtual void deauthenticate();
|
||||
|
||||
virtual QWidget* aclWidget() { return 0; }
|
||||
virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin() { return Tomahawk::InfoSystem::InfoPluginPtr(); }
|
||||
virtual SipPlugin* sipPlugin() { return 0; }
|
||||
virtual bool preventEnabling() const { return m_preventEnabling; }
|
||||
|
||||
QString sendMessage( const QVariantMap& msg, QObject* receiver = 0, const QString& slot = QString() );
|
||||
|
||||
void registerUpdaterForPlaylist( const QString& plId, SpotifyPlaylistUpdater* updater );
|
||||
void unregisterUpdater( const QString& plid );
|
||||
|
||||
bool deleteOnUnsync() const;
|
||||
|
||||
void setManualResolverPath( const QString& resolverPath );
|
||||
|
||||
public slots:
|
||||
void aboutToShow( QAction* action, const Tomahawk::playlist_ptr& playlist );
|
||||
void syncActionTriggered( bool );
|
||||
void atticaLoaded(Attica::Content::List);
|
||||
|
||||
private slots:
|
||||
void resolverChanged();
|
||||
void resolverInstalled( const QString& resolverId );
|
||||
|
||||
void resolverMessage( const QString& msgType, const QVariantMap& msg );
|
||||
|
||||
void login( const QString& username, const QString& password );
|
||||
// SpotifyResolver message handlers, all take msgtype, msg as argument
|
||||
// void <here>( const QString& msgType, const QVariantMap& msg );
|
||||
void startPlaylistSyncWithPlaylist( const QString& msgType, const QVariantMap& msg );
|
||||
void playlistCreated( const QString& msgType, const QVariantMap& msg );
|
||||
|
||||
void delayedInit();
|
||||
void hookupAfterDeletion( bool autoEnable );
|
||||
|
||||
private:
|
||||
void init();
|
||||
bool checkForResolver();
|
||||
void hookupResolver();
|
||||
|
||||
void loadPlaylists();
|
||||
void clearUser( bool permanentlyDelete = false );
|
||||
|
||||
void startPlaylistSync( SpotifyPlaylistInfo* playlist );
|
||||
void stopPlaylistSync( SpotifyPlaylistInfo* playlist, bool forceDontDelete = false );
|
||||
void fetchFullPlaylist( SpotifyPlaylistInfo* playlist );
|
||||
|
||||
void setSyncForPlaylist( const QString& spotifyPlaylistId, bool sync );
|
||||
|
||||
void createActions();
|
||||
void removeActions();
|
||||
|
||||
QWeakPointer<SpotifyAccountConfig> m_configWidget;
|
||||
QWeakPointer<QWidget> m_aboutWidget;
|
||||
QWeakPointer<ScriptResolver> m_spotifyResolver;
|
||||
|
||||
QMap<QString, QPair<QObject*, QString> > m_qidToSlotMap;
|
||||
|
||||
// List of synced spotify playlists in config UI
|
||||
QList< SpotifyPlaylistInfo* > m_allSpotifyPlaylists;
|
||||
QHash< QString, SpotifyPlaylistUpdater* > m_updaters;
|
||||
|
||||
QHash< QString, playlist_ptr > m_waitingForCreateReply;
|
||||
|
||||
bool m_preventEnabling;
|
||||
|
||||
SmartPointerList< QAction > m_customActions;
|
||||
friend class ::SpotifyPlaylistUpdater;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE( Tomahawk::Accounts::SpotifyPlaylistInfo* );
|
||||
|
||||
#endif // SpotifyAccount_H
|
@@ -1,170 +0,0 @@
|
||||
/* === 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 "SpotifyAccountConfig.h"
|
||||
|
||||
#include "SpotifyAccount.h"
|
||||
#include "utils/AnimatedSpinner.h"
|
||||
#include "ui_SpotifyAccountConfig.h"
|
||||
|
||||
#include <QListWidget>
|
||||
#include <QListWidgetItem>
|
||||
#include <QShowEvent>
|
||||
|
||||
using namespace Tomahawk;
|
||||
using namespace Accounts;
|
||||
|
||||
SpotifyAccountConfig::SpotifyAccountConfig( SpotifyAccount *account )
|
||||
: QWidget( 0 )
|
||||
, m_ui( new Ui::SpotifyConfig )
|
||||
, m_account( account )
|
||||
, m_playlistsLoading( 0 )
|
||||
, m_loggedInManually( false )
|
||||
{
|
||||
m_ui->setupUi( this );
|
||||
|
||||
connect( m_ui->loginButton, SIGNAL( clicked( bool ) ), this, SLOT( doLogin() ) );
|
||||
|
||||
connect( m_ui->usernameEdit, SIGNAL( textChanged( QString ) ), this, SLOT( resetLoginButton() ) );
|
||||
connect( m_ui->passwordEdit, SIGNAL( textChanged( QString ) ), this, SLOT( resetLoginButton() ) );
|
||||
loadFromConfig();
|
||||
|
||||
m_playlistsLoading = new AnimatedSpinner( m_ui->playlistList );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccountConfig::showEvent( QShowEvent *event )
|
||||
{
|
||||
Q_UNUSED( event );
|
||||
|
||||
loadFromConfig();
|
||||
m_loggedInManually = false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccountConfig::loadFromConfig()
|
||||
{
|
||||
m_ui->usernameEdit->setText( m_account->credentials().value( "username" ).toString() );
|
||||
m_ui->passwordEdit->setText( m_account->credentials().value( "password" ).toString() );
|
||||
m_ui->streamingCheckbox->setChecked( m_account->credentials().value( "highQuality" ).toBool() );
|
||||
m_ui->deleteOnUnsync->setChecked( m_account->deleteOnUnsync() );
|
||||
}
|
||||
|
||||
void
|
||||
SpotifyAccountConfig::saveSettings()
|
||||
{
|
||||
for( int i = 0; i < m_ui->playlistList->count(); i++ )
|
||||
{
|
||||
const QListWidgetItem* item = m_ui->playlistList->item( i );
|
||||
|
||||
SpotifyPlaylistInfo* pl = item->data( Qt::UserRole ).value< SpotifyPlaylistInfo* >();
|
||||
const bool toSync = ( item->checkState() == Qt::Checked );
|
||||
if ( pl->sync != toSync )
|
||||
{
|
||||
pl->changed = true;
|
||||
pl->sync = toSync;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
SpotifyAccountConfig::username() const
|
||||
{
|
||||
return m_ui->usernameEdit->text().trimmed();
|
||||
}
|
||||
|
||||
QString
|
||||
SpotifyAccountConfig::password() const
|
||||
{
|
||||
return m_ui->passwordEdit->text().trimmed();
|
||||
}
|
||||
|
||||
bool
|
||||
SpotifyAccountConfig::highQuality() const
|
||||
{
|
||||
return m_ui->streamingCheckbox->isChecked();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SpotifyAccountConfig::deleteOnUnsync() const
|
||||
{
|
||||
return m_ui->deleteOnUnsync->isChecked();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccountConfig::setPlaylists( const QList<SpotifyPlaylistInfo *>& playlists )
|
||||
{
|
||||
// User always has at least 1 playlist (starred tracks)
|
||||
if ( !playlists.isEmpty() )
|
||||
m_playlistsLoading->fadeOut();
|
||||
|
||||
m_ui->playlistList->clear();
|
||||
foreach ( SpotifyPlaylistInfo* pl, playlists )
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem( pl->name, m_ui->playlistList );
|
||||
item->setData( Qt::UserRole, QVariant::fromValue< SpotifyPlaylistInfo* >( pl ) );
|
||||
item->setFlags( Qt::ItemIsUserCheckable | Qt::ItemIsSelectable | Qt::ItemIsEnabled );
|
||||
item->setCheckState( pl->sync ? Qt::Checked : Qt::Unchecked );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccountConfig::doLogin()
|
||||
{
|
||||
m_ui->loginButton->setText( tr( "Logging in..." ) );
|
||||
m_ui->loginButton->setEnabled( false );
|
||||
|
||||
m_playlistsLoading->fadeIn();
|
||||
m_loggedInManually = true;
|
||||
|
||||
emit login( username(), password() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccountConfig::loginResponse( bool success, const QString& msg )
|
||||
{
|
||||
if ( success )
|
||||
{
|
||||
m_ui->loginButton->setText( tr( "Logged in!" ) );
|
||||
m_ui->loginButton->setEnabled( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
setPlaylists( QList< SpotifyPlaylistInfo* >() );
|
||||
m_playlistsLoading->fadeOut();
|
||||
m_ui->loginButton->setText( tr( "Failed: %1" ).arg( msg ) );
|
||||
m_ui->loginButton->setEnabled( true );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccountConfig::resetLoginButton()
|
||||
{
|
||||
m_ui->loginButton->setText( tr( "Log In" ) );
|
||||
m_ui->loginButton->setEnabled( true );
|
||||
}
|
||||
|