1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-09-11 14:40:52 +02:00

Compare commits

..

37 Commits
0.3.0 ... 0.2.2

Author SHA1 Message Date
Jason Herskowitz
13ab10adea Edited ChangeLog via GitHub 2011-08-22 12:29:31 -04:00
Christian Muehlhaeuser
20d2a5ff59 * Bumped version to 0.2.2. 2011-08-22 17:46:55 +02:00
Leo Franchi
6b9eec00fd Changelog 2011-08-22 07:34:47 -04:00
Leo Franchi
d7416ddd57 TWK-415: Don't crash if the trackproxymodel has an invalid current track
(cherry picked from commit 498d7052de)
2011-08-22 07:32:48 -04:00
Leo Franchi
2e9aa7f3b3 Changelog. 2011-08-21 21:41:31 -04:00
Leo Franchi
208393deb0 TWK-401: Only update source stats after addfiles dbcmd is finished, instead of playing a race condition game. Also, refresh recent albums on stats change
(cherry picked from commit 6521198127)
2011-08-21 21:34:26 -04:00
Leo Franchi
b923d4f994 TWK-420: Show resolver wrench immediately after enabling a resolver.
(cherry picked from commit f0a6d4e8bb)
2011-08-21 21:34:20 -04:00
Christian Muehlhaeuser
edbee5a922 * Fixed filtering out unwanted dupes when viewing a local collection. 2011-08-21 22:52:53 +02:00
Michael Zanetti
e0bdc4b8bc TWK-411: Dragging an album/artist to "New Station" creates a station based on that artist instead of all the tracks 2011-08-21 16:00:21 +02:00
Christian Muehlhaeuser
4b53d20663 * Updated ChangeLog. 2011-08-21 04:51:52 +02:00
Christian Muehlhaeuser
74c4f4ddc2 * Fixed TWK-442: Provide stable sort ordering in Track- / TreeProxyModel. 2011-08-21 03:53:42 +02:00
Christian Muehlhaeuser
ec03ece35c * Fixed TWK-435: Don't block pipeline if a resolver times out. 2011-08-21 03:33:32 +02:00
Dominik Schmidt
d217e7fae0 TWK-410: possible fix 2011-08-21 03:33:25 +02:00
Christian Muehlhaeuser
bc3bcc708f * Don't filter out some wanted tracks, e.g. when multiple tracks of an album have the same name, but different tracks numbers. 2011-08-21 02:59:09 +02:00
Christian Muehlhaeuser
7a90ba11bb * Fixed TWK-387: Stop showing a loading spinner, if there are no items to load. 2011-08-21 02:58:59 +02:00
Michael Zanetti
ed219a56cd don't add duplicates when dropping albums or artists and fix losing items when combining synchronous and asynchrounous drop operations 2011-08-20 14:38:43 +02:00
Christian Muehlhaeuser
1537d5b08a * Updated ChangeLog. 2011-08-18 00:05:45 +02:00
Christian Muehlhaeuser
263340a270 * No need for clucene in Tomahawk binary. 2011-08-17 22:13:24 +02:00
Jason Herskowitz
bf54ebf7fe De-decapitate avatar placeholder
(cherry picked from commit 77d60fa02d)
2011-08-17 14:40:04 -04:00
Leo Franchi
bfbac296b0 Fix resolvers on qt 4.8, baseUrl is required for html5 security policy stuff for localStorage
(cherry picked from commit 4abb53ccdf)
2011-08-17 14:36:02 -04:00
Christian Muehlhaeuser
7971e7aadc * More verbose debug output in DBSyncConnection. 2011-08-17 04:15:28 +02:00
Christian Muehlhaeuser
4cc1690dea * Fixed sorting of identical items in Tree- & TrackProxyModel. 2011-08-17 03:34:21 +02:00
Christian Muehlhaeuser
2090d76955 * Fixed sidebar sorting for items with identical names. 2011-08-17 03:20:23 +02:00
Christian Muehlhaeuser
d09397a8ab * Moved the AudioControl QSlider stylesheets into SeekSlider. 2011-08-17 03:20:12 +02:00
Christian Muehlhaeuser
a734cad4e1 * No need for mouse tracking. 2011-08-17 02:27:39 +02:00
Christian Muehlhaeuser
9b433379ee * Fixed TWK-212: Sliders should jump to the position they are clicked on. 2011-08-17 02:27:25 +02:00
Christian Muehlhaeuser
2e11376d01 * Fix sorting for real. 2011-08-17 01:10:56 +02:00
Christian Muehlhaeuser
9ba11290ae * Fixed sidebar sorting. 2011-08-17 01:10:45 +02:00
Leo Franchi
97e0bbaf38 Allow to show the setting dialog always, and disable +/- buttons till loaded
(cherry picked from commit 713243cc5d)
2011-08-16 19:08:03 -04:00
Leo Franchi
eb4242622d Show spinner on initial load while loading sip plugins in preferences. Disable Settings action till servent is loaded
(cherry picked from commit ee8da33e06)
2011-08-16 19:07:57 -04:00
Michael Zanetti
469bea43ba added drag capabilities to albumview ins sourceinfowidget and welcomewidget 2011-08-16 23:49:24 +02:00
Michael Zanetti
f9f3a45a31 fix copyright headers in SettingsListDelegate 2011-08-16 19:53:50 +02:00
Michael Zanetti
0579d63013 fixed copyright headers 2011-08-16 19:53:41 +02:00
Michael Zanetti
1bb115ec6f Created DropJob which will start a query for the dropped items and wait for the results 2011-08-16 19:53:30 +02:00
Michael Zanetti
5f320028b8 more work to be able to drag and drop mixed mimetypes (e.g. an artist and some tracks) 2011-08-16 19:53:15 +02:00
Michael Zanetti
b0d445c262 added drag and drop to playlists for albums and artists 2011-08-16 19:53:06 +02:00
Christian Muehlhaeuser
479a0c469f * Un-regress listen-along. 2011-08-16 03:25:24 +02:00
1821 changed files with 12071 additions and 501554 deletions

2
.gitignore vendored
View File

@@ -16,5 +16,3 @@ thirdparty/qtweetlib/WARNING-twitter-api-keys
clang/
win/
gcc/
tags
.DS_Store

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "thirdparty/jreen"]
path = thirdparty/jreen
url = git://github.com/euroelessar/jreen.git
[submodule "thirdparty/qtweetlib/QTweetLib"]
path = thirdparty/qtweetlib/QTweetLib
url = git://github.com/minimoog/QTweetLib.git

View File

@@ -15,8 +15,8 @@ SET( TOMAHAWK_APPLICATION_NAME "Tomahawk" )
SET( TOMAHAWK_DESCRIPTION_SUMMARY "The social media player" )
SET( TOMAHAWK_VERSION_MAJOR 0 )
SET( TOMAHAWK_VERSION_MINOR 3 )
SET( TOMAHAWK_VERSION_PATCH 0 )
SET( TOMAHAWK_VERSION_MINOR 2 )
SET( TOMAHAWK_VERSION_PATCH 2 )
#SET( TOMAHAWK_VERSION_RC 0 )
@@ -48,6 +48,7 @@ IF( NOT BUILD_RELEASE )
ENDIF()
# set paths
SET( THIRDPARTY_DIR ${CMAKE_SOURCE_DIR}/thirdparty )
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" )
@@ -71,10 +72,6 @@ ELSE()
LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" )
ENDIF()
IF( BUILD_GUI AND UNIX AND NOT APPLE )
FIND_PACKAGE( X11 )
ENDIF()
macro_optional_find_package(Qt4 4.7.0 COMPONENTS ${NEEDED_QT4_COMPONENTS} )
macro_log_feature(QT4_FOUND "Qt" "A cross-platform application and UI framework" "http://qt.nokia.com" TRUE "" "If you see this, although libqt4-devel is installed, check whether \n the qtwebkit-devel package is installed as well")
@@ -84,8 +81,8 @@ if(PHONON_FOUND)
message(STATUS "Phonon found; ensure that phonon-vlc is at least 0.4")
endif()
macro_optional_find_package(LibEchonest 1.1.10)
macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 1.1.10 is needed for dynamic playlists and the infosystem")
macro_optional_find_package(LibEchonest 1.1.7)
macro_log_feature(LIBECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 1.1.8 is needed for dynamic playlists and the infosystem")
macro_optional_find_package(CLucene 0.9.23)
macro_log_feature(CLucene_FOUND "CLucene" "The open-source, C++ search engine" "http://clucene.sf.net" TRUE "" "CLucene is used for indexing the collection")
@@ -101,25 +98,7 @@ check_taglib_filename( COMPLEX_TAGLIB_FILENAME )
macro_optional_find_package(Boost)
macro_log_feature(Boost_FOUND "Boost" "Provides free peer-reviewed portable C++ source libraries" "http://www.boost.org" TRUE "" "") #FIXME: give useful explaination
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" FALSE "" "")
macro_optional_find_package(QuaZip)
macro_log_feature(QuaZip_FOUND "QuaZip" "Provides support for extracting downloaded resolvers autmatically. Will build internal copy instead." "http://quazip.sourceforge.net/" FALSE "" "")
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 )
# 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
@@ -127,16 +106,8 @@ ENDIF()
#macro_log_feature(LIBLASTFM_FOUND "LastFm" "Qt library for the Last.fm webservices" "https://github.com/mxcl/liblastfm" FALSE "" "liblastfm is needed for scrobbling tracks to Last.fm and fetching cover artwork")
set(LIBLASTFM_FOUND true)
#### submodules start
# this installs headers and such and should really be handled in a separate package by packagers
IF( INTERNAL_JREEN )
IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.gitmodules)
EXECUTE_PROCESS(COMMAND git submodule init WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )
EXECUTE_PROCESS(COMMAND git submodule update WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )
ENDIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.gitmodules)
ENDIF()
IF( INTERNAL_JREEN )
ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/jreen )
SET( LIBJREEN_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/include )
@@ -149,9 +120,20 @@ ELSE( INTERNAL_JREEN )
ENDIF( INTERNAL_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\n Use -DINTERNAL_JREEN=ON to build the git submodule inside Tomahawk \n Be aware this installs a full jreen with headers and everything!\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")
#### submodules end
# this installs headers and such and should really be handled in a separate package by packagers
IF( INTERNAL_QTWEETLIB )
ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/qtweetlib )
# copy headers to build/QTweetLib so we can use proper includes inside the code
FILE( COPY ${CMAKE_SOURCE_DIR}/thirdparty/qtweetlib/QTweetLib/src/ DESTINATION ${CMAKE_BINARY_DIR}/QTweetLib )
SET( QTWEETLIB_INCLUDE_DIR ${CMAKE_BINARY_DIR} )
SET( QTWEETLIB_LIBRARY tomahawk_qtweetlib )
SET( QTWEETLIB_LIBRARIES ${QTWEETLIB_LIBRARY} )
SET( QTWEETLIB_FOUND true )
MESSAGE(STATUS "INTERNAL libQTweetLib: ${QTWEETLIB_INCLUDE_DIR}, ${QTWEETLIB_LIBRARY}")
ELSE( INTERNAL_QTWEETLIB )
macro_optional_find_package(QTweetLib)
ENDIF( INTERNAL_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\n Use -DINTERNAL_QTWEETLIB=ON to build the git submodule inside Tomahawk \n")
### libportfwd
SET( LIBPORTFWD_INCLUDE_DIR ${THIRDPARTY_DIR}/libportfwd/include )
@@ -160,8 +142,8 @@ SET( LIBPORTFWD_LIBRARIES ${LIBPORTFWD_LIBRARY} )
ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/libportfwd )
# we need pthreads too
#macro_optional_find_package(Threads)
#macro_log_feature(THREADS_FOUND "Threads" "Threading Library" "" TRUE "" "Platform specific library for threading")
macro_optional_find_package(Threads)
macro_log_feature(THREADS_FOUND "Threads" "Threading Library" "" TRUE "" "Platform specific library for threading")
macro_optional_find_package(KDE4)
macro_optional_find_package(KDE4Installed)
@@ -171,12 +153,9 @@ macro_optional_find_package(KDE4Installed)
# macro_optional_find_package(KDE4)
IF(KDE4_FOUND)
IF( CMAKE_C_FLAGS )
# KDE4 adds and removes some compiler flags that we don't like
# (only for gcc not for clang e.g.)
STRING( REPLACE "-std=iso9899:1990" "" CLEAN_C_FLAGS ${CMAKE_C_FLAGS} )
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions" )
ENDIF()
#KDE4 adds and removes some compiler flags that we don't like
STRING( REPLACE "-std=iso9899:1990" "" CLEAN_C_FLAGS ${CMAKE_C_FLAGS} )
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions" )
ELSE()
SET( CLEAN_C_FLAGS ${CMAKE_C_FLAGS} )
ENDIF()
@@ -211,4 +190,3 @@ ADD_SUBDIRECTORY( src/libtomahawk )
SET( TOMAHAWK_LIBRARIES tomahawklib )
ADD_SUBDIRECTORY( src )
ADD_SUBDIRECTORY( admin )
ADD_SUBDIRECTORY( src/breakpad/CrashReporter )

View File

@@ -12,15 +12,7 @@
INCLUDE(CheckSymbolExists)
INCLUDE(FindLibraryWithDebug)
# try to locate a patched unstable version (for comp's sake *sigh*) first
FIND_PACKAGE(CLuceneUnstable)
IF(CLUCENEUNSTABLE_FOUND)
SET(CLucene_FOUND TRUE)
SET(CLUCENE_INCLUDE_DIR ${CLUCENE_UNSTABLE_INCLUDE_DIRS})
SET(CLUCENE_LIBRARIES ${CLUCENE_UNSTABLE_LIBS})
#MESSAGE(FATAL_ERROR NARF)
ELSE(CLUCENEUNSTABLE_FOUND)
IF(CLucene_FIND_VERSION)
SET(CLUCENE_MIN_VERSION ${CLucene_FIND_VERSION})
ELSEIF()
@@ -107,7 +99,6 @@ ENDIF (CLUCENE_LIBRARY_DIR)
IF(CLUCENE_INCLUDE_DIR AND CLUCENE_LIBRARIES AND CLUCENE_LIBRARY_DIR AND CLUCENE_GOOD_VERSION)
SET(CLucene_FOUND TRUE)
ENDIF(CLUCENE_INCLUDE_DIR AND CLUCENE_LIBRARIES AND CLUCENE_LIBRARY_DIR AND CLUCENE_GOOD_VERSION)
ENDIF(CLUCENEUNSTABLE_FOUND)
IF(CLucene_FOUND)
IF(NOT CLucene_FIND_QUIETLY)

View File

@@ -1,37 +0,0 @@
# - Try to find clucene-unstable
# This is a workaround for distros, that want to ship a recent enough clucene but don't want to replace the old version
#
# CLUCENEUNSTABLE_FOUND - system has clucene-unstable
# CLUCENE_UNSTABLE_INCLUDE_DIR - the clucene-unstable include directories
# CLUCENE_UNSTABLE_LIBS - link these to use clucene-unstable
#
# (c) Dominik Schmidt <dev@dominik-schmidt.de>
#
# Include dir
find_path(CLUCENE_UNSTABLE_INCLUDE_DIR
NAMES CLucene.h
PATH_SUFFIXES clucene-unstable
PATHS ${KDE4_INCLUDE_DIR}
)
# Finally the library itself
find_library(CLUCENE_UNSTABLE_SHARED_LIB
NAMES clucene-unstable-shared
PATHS ${KDE4_LIB_DIR}
)
find_library(CLUCENE_UNSTABLE_CORE_LIB
NAMES clucene-unstable-core
PATHS ${KDE4_LIB_DIR}
)
SET( CLUCENE_UNSTABLE_LIBS ${CLUCENE_UNSTABLE_SHARED_LIB} ${CLUCENE_UNSTABLE_CORE_LIB} )
SET( CLUCENE_UNSTABLE_INCLUDE_DIRS ${CLUCENE_UNSTABLE_INCLUDE_DIR})
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CLuceneUnstable DEFAULT_MSG CLUCENE_UNSTABLE_LIBS CLUCENE_UNSTABLE_INCLUDE_DIRS)
MARK_AS_ADVANCED(CLUCENE_UNSTABLE_LIBS CLUCENE_UNSTABLE_INCLUDE_DIRS)

View File

@@ -1,63 +0,0 @@
# Try to find the Attica library
# Once done this will define
#
# LIBATTICA_FOUND Indicates that Attica was found
# LIBATTICA_LIBRARIES Libraries needed to use Attica
# LIBATTICA_LIBRARY_DIRS Paths needed for linking against Attica
# LIBATTICA_INCLUDE_DIR Path needed for finding Attica include files
#
# The minimum required version of LibAttica can be specified using the
# standard syntax, e.g. find_package(LibAttica 0.20)
# Copyright (c) 2009 Frederik Gladhorn <gladhorn@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# Support LIBATTICA_MIN_VERSION for compatibility:
IF(NOT LibAttica_FIND_VERSION)
SET(LibAttica_FIND_VERSION "${LIBATTICA_MIN_VERSION}")
ENDIF(NOT LibAttica_FIND_VERSION)
# the minimum version of LibAttica we require
IF(NOT LibAttica_FIND_VERSION)
SET(LibAttica_FIND_VERSION "0.1.0")
ENDIF(NOT LibAttica_FIND_VERSION)
IF (NOT WIN32)
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
FIND_PACKAGE(PkgConfig)
PKG_CHECK_MODULES(PC_LIBATTICA QUIET libattica)
SET(LIBATTICA_DEFINITIONS ${PC_ATTICA_CFLAGS_OTHER})
ENDIF (NOT WIN32)
FIND_PATH(LIBATTICA_INCLUDE_DIR attica/provider.h
HINTS
${PC_LIBATTICA_INCLUDEDIR}
${PC_LIBATTICA_INCLUDE_DIRS}
PATH_SUFFIXES attica
)
# Store the version number in the cache, so we don't have to search everytime:
IF(LIBATTICA_INCLUDE_DIR AND NOT LIBATTICA_VERSION)
FILE(READ ${LIBATTICA_INCLUDE_DIR}/attica/version.h LIBATTICA_VERSION_CONTENT)
STRING (REGEX MATCH "LIBATTICA_VERSION_STRING \".*\"\n" LIBATTICA_VERSION_MATCH "${LIBATTICA_VERSION_CONTENT}")
IF(LIBATTICA_VERSION_MATCH)
STRING(REGEX REPLACE "LIBATTICA_VERSION_STRING \"(.*)\"\n" "\\1" _LIBATTICA_VERSION ${LIBATTICA_VERSION_MATCH})
ENDIF(LIBATTICA_VERSION_MATCH)
SET(LIBATTICA_VERSION "${_LIBATTICA_VERSION}" CACHE STRING "Version number of LibAttica" FORCE)
ENDIF(LIBATTICA_INCLUDE_DIR AND NOT LIBATTICA_VERSION)
FIND_LIBRARY(LIBATTICA_LIBRARIES NAMES attica libattica
HINTS
${PC_LIBATTICA_LIBDIR}
${PC_LIBATTICA_LIBRARY_DIRS}
)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibAttica REQUIRED_VARS LIBATTICA_LIBRARIES LIBATTICA_INCLUDE_DIR
VERSION_VAR LIBATTICA_VERSION)
MARK_AS_ADVANCED(LIBATTICA_INCLUDE_DIR LIBATTICA_LIBRARIES)

View File

@@ -19,19 +19,53 @@ macro(_phonon_find_version)
file(READ ${_phonon_namespace_header_file} _phonon_header LIMIT 5000 OFFSET 1000)
string(REGEX MATCH "define PHONON_VERSION_STR \"(4\\.[0-9]+\\.[0-9a-z]+)\"" _phonon_version_match "${_phonon_header}")
set(PHONON_VERSION "${CMAKE_MATCH_1}")
message(STATUS "Phonon Version: ${PHONON_VERSION}")
endmacro(_phonon_find_version)
# the dirs listed with HINTS are searched before the default sets of dirs
find_library(PHONON_LIBRARY NAMES phonon HINTS ${KDE4_LIB_INSTALL_DIR} ${QT_LIBRARY_DIR})
find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h HINTS ${KDE4_INCLUDE_INSTALL_DIR} ${QT_INCLUDE_DIR} ${INCLUDE_INSTALL_DIR} ${QT_LIBRARY_DIR})
if(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)
set(PHONON_LIBS ${phonon_LIB_DEPENDS} ${PHONON_LIBRARY})
set(PHONON_INCLUDES ${PHONON_INCLUDE_DIR}/KDE ${PHONON_INCLUDE_DIR})
if(PHONON_FOUND)
# Already found, nothing more to do except figuring out the version
_phonon_find_version()
endif(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)
else(PHONON_FOUND)
if(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)
set(PHONON_FIND_QUIETLY TRUE)
endif(PHONON_INCLUDE_DIR AND PHONON_LIBRARY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Phonon DEFAULT_MSG PHONON_INCLUDE_DIR PHONON_LIBRARY)
# As discussed on kde-buildsystem: first look at CMAKE_PREFIX_PATH, then at the suggested PATHS (kde4 install dir)
find_library(PHONON_LIBRARY NAMES phonon phonon4 PATHS ${KDE4_LIB_INSTALL_DIR} ${QT_LIBRARY_DIR})
# then at the default system locations (CMAKE_SYSTEM_PREFIX_PATH, i.e. /usr etc.)
find_library(PHONON_LIBRARY NAMES phonon phonon4)
mark_as_advanced(PHONON_INCLUDE_DIR PHONON_LIBRARY)
find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h PATHS ${KDE4_INCLUDE_INSTALL_DIR} ${QT_INCLUDE_DIR} ${INCLUDE_INSTALL_DIR} ${QT_LIBRARY_DIR})
find_path(PHONON_INCLUDE_DIR NAMES phonon/phonon_export.h)
_phonon_find_version()
if(PHONON_INCLUDE_DIR AND PHONON_LIBRARY AND NOT PHONON_VERSION VERSION_LESS ${Phonon_FIND_VERSION})
set(PHONON_LIBS ${phonon_LIB_DEPENDS} ${PHONON_LIBRARY})
set(PHONON_INCLUDES ${PHONON_INCLUDE_DIR}/KDE ${PHONON_INCLUDE_DIR})
set(PHONON_FOUND TRUE)
else(PHONON_INCLUDE_DIR AND PHONON_LIBRARY AND NOT PHONON_VERSION VERSION_LESS ${Phonon_FIND_VERSION})
set(PHONON_FOUND FALSE)
endif(PHONON_INCLUDE_DIR AND PHONON_LIBRARY AND NOT PHONON_VERSION VERSION_LESS ${Phonon_FIND_VERSION})
if(PHONON_FOUND)
if(NOT PHONON_FIND_QUIETLY)
message(STATUS "Found Phonon: ${PHONON_LIBRARY}")
message(STATUS "Found Phonon Includes: ${PHONON_INCLUDES}")
endif(NOT PHONON_FIND_QUIETLY)
else(PHONON_FOUND)
if(Phonon_FIND_REQUIRED)
if(NOT PHONON_INCLUDE_DIR)
message(STATUS "Phonon includes NOT found!")
endif(NOT PHONON_INCLUDE_DIR)
if(NOT PHONON_LIBRARY)
message(STATUS "Phonon library NOT found!")
endif(NOT PHONON_LIBRARY)
message(FATAL_ERROR "Phonon library or includes NOT found!")
else(Phonon_FIND_REQUIRED)
message(STATUS "Unable to find Phonon")
endif(Phonon_FIND_REQUIRED)
endif(PHONON_FOUND)
mark_as_advanced(PHONON_INCLUDE_DIR PHONON_LIBRARY PHONON_INCLUDES)
endif(PHONON_FOUND)

View File

@@ -1,48 +0,0 @@
# - Try to find QCA2 (Qt Cryptography Architecture 2)
# Once done this will define
#
# QCA2_FOUND - system has QCA2
# QCA2_INCLUDE_DIR - the QCA2 include directory
# QCA2_LIBRARIES - the libraries needed to use QCA2
# QCA2_DEFINITIONS - Compiler switches required for using QCA2
#
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
# Copyright (c) 2006, Michael Larouche, <michael.larouche@kdemail.net>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
include(FindLibraryWithDebug)
if (QCA2_INCLUDE_DIR AND QCA2_LIBRARIES)
# in cache already
set(QCA2_FOUND TRUE)
else (QCA2_INCLUDE_DIR AND QCA2_LIBRARIES)
if (NOT WIN32)
find_package(PkgConfig)
pkg_check_modules(PC_QCA2 qca2)
set(QCA2_DEFINITIONS ${PC_QCA2_CFLAGS_OTHER})
endif (NOT WIN32)
find_library_with_debug(QCA2_LIBRARIES
WIN32_DEBUG_POSTFIX d
NAMES qca
HINTS ${PC_QCA2_LIBDIR} ${PC_QCA2_LIBRARY_DIRS}
)
find_path(QCA2_INCLUDE_DIR qca.h
HINTS ${PC_QCA2_INCLUDEDIR} ${PC_QCA2_INCLUDE_DIRS}
PATH_SUFFIXES QtCrypto)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(QCA2 DEFAULT_MSG QCA2_LIBRARIES QCA2_INCLUDE_DIR)
mark_as_advanced(QCA2_INCLUDE_DIR QCA2_LIBRARIES)
endif (QCA2_INCLUDE_DIR AND QCA2_LIBRARIES)

View File

@@ -1,11 +0,0 @@
find_package(Qt4)
find_path(QuaZip_INCLUDE_DIR quazip.h ${CMAKE_INSTALL_PREFIX}/include/quazip ${CMAKE_INSTALL_PREFIX}/include /usr/include/quazip /usr/local/include/quazip ${QT_INCLUDE_DIR}/quazip ${QT_INCLUDE_DIR} ${QUAZIP_DIR}/include/quazip ${QUAZIP_DIR}/quazip ${QUAZIP_DIR}/include)
find_library(QuaZip_LIBRARY NAMES quazip PATHS ${CMAKE_INSTALL_PREFIX}/lib64 ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/Library/Frameworks ${QUAZIP_DIR}/lib64 ${QUAZIP_DIR}/lib ${QUAZIP_DIR}/quazip ${QUAZIP_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(quazip DEFAULT_MSG QuaZip_LIBRARY QuaZip_INCLUDE_DIR)
set(QuaZip_LIBRARIES ${QuaZip_LIBRARY})
mark_as_advanced(QuaZip_LIBRARY QuaZip_INCLUDE_DIR)
if(QuaZip_LIBRARY AND QuaZip_INCLUDE_DIR)
set(QuaZip_FOUND TRUE)
endif()

View File

@@ -273,13 +273,9 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
;Main executable.
File "${INSTALL_PATH}\bin\tomahawk.exe"
File "${INSTALL_PATH}\bin\CrashReporter.exe"
File "${INSTALL_PATH}\bin\libtomahawk_breakpad.dll"
File "${INSTALL_PATH}\bin\libqxtweb-standalone.dll"
File "${INSTALL_PATH}\bin\libtomahawk_portfwd.dll"
File "${INSTALL_PATH}\bin\libtomahawk_lastfm2.dll"
File "${INSTALL_PATH}\bin\libquazip.dll"
File "${INSTALL_PATH}\bin\libtomahawklib.dll"
File "${INSTALL_PATH}\lib\libtomahawk_sip*.dll"
!endif
@@ -287,14 +283,10 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
;Main executable.
File "${BUILD_PATH}\tomahawk.exe"
File "${BUILD_PATH}\CrashReporter.exe"
File "${BUILD_PATH}\libtomahawk_breakpad.dll"
File "${BUILD_PATH}\libtomahawklib.dll"
File "${BUILD_PATH}\libqxtweb-standalone.dll"
File "${BUILD_PATH}\libtomahawk_portfwd.dll"
File "${BUILD_PATH}\libtomahawk_lastfm2.dll"
File "${BUILD_PATH}\libquazip.dll"
File "${BUILD_PATH}\libtomahawk_sip*.dll"
!endif
@@ -354,6 +346,7 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
File "${MING_BIN}\libvorbisenc-2.dll" ; OGG
; Other
File "${MING_BIN}\libqjson.dll"
File "${MING_BIN}\libtag.dll"
@@ -377,7 +370,6 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
File "${MING_LIB}\libclucene-shared.dll"
File "${MING_BIN}\libqtsparkle.dll"
File "${MING_BIN}\libattica.dll"
SectionEnd
SectionGroup "Shortcuts"

View File

@@ -1,91 +1,11 @@
Version 0.3.0:
* Make artist names in the album view clickable.
* Don't start playing if a tomahawk:// link was clicked while Tomahawk
is paused.
* Make artist name clickable in header of Album pages.
* Added a drop shadow to cover images, and put placeholder in jewel case.
* Added shuffle and repeat support to tree view.
* Draw a speaker next to the currently playing playlist.
* Refresh station previews whenever a filter is changed.
* Support and show official releases on album and track pages.
* Filter out duplicates from station previews and upcoming tracks.
* Added YouTube resolver.
* Fixed bug where going offline then online would not re-connect to many
peers.
* Added support for auto-updating live XSPF playlists.
* Don't show an age of 41 years for tracks that have no age information.
* Show config UI for resolvers that have them as soon as you add them.
* Add support for Echo Nest Personal Catalogs and User Radio. Synchronize
your catalog with The Echo Nest and enable personal recommendations
from you and your friends.
* Added support for Grooveshark resolver (requires Grooveshark Anywhere).
* Fixed re-resolving when resolvers or sources go off- / online.
* Correctly sort recently played tracks on the Dashboard.
* Show a Lion full-screen toggle button if running on Lion.
* Show a list of users who are currently listening along to you.
* Show headphone icon in source item to allow users to listen along; paint
headphones red on a source if you are currently listening along to it.
* Added new job status view in the bottom of the source list that displays
current jobs such as resolving, parsing playlists, and loading from
database.
* Parse and convert a Spotify playlist url when dropped anywhere on the
sidebar.
* Convert resolvers to use asynchronous calls to avoid blocking Tomahawk's
UI, greatly increasing responsiveness of Tomahawk while resolving.
* Fixed no playlists overlay not disappearing when playlists were added.
* Add support for parsing itunes track, artist and album links.
* Fixed crash when syncing playlists with peers.
* Add support for browsing, downloading and rating resolvers from within
Tomahawk directly.
* Support multi-folder selection and scanning.
* Fixed handling of special characters in tomahawk:// links
* Improve sidebar performance by caching pixmaps and shrinking them.
* Send updated playlists to peers when tracks are moved/copied.
* Remove splitter handles in sidebar.
* Fixed Tomahawk preventing system shutdown / logout.
* Ignore leading 'The' when sorting artists.
* Added Charts page, which shows various sources' top hits & artists.
* The Collection tree-views can now be filtered.
* Fixed crash when pressing enter in an empty playlist.
* Moved the song queue to the bottom of the sidebar.
* Added Footnotes, a contextual view that you can slide it.
* Show recently added playlists in dashboard rather than recently opened
playlists.
* Fixed seek slider and give it some smooth animation between ticks.
* Fixed Twitter issue where it would repeatedly send DMs to friends.
* Add a new drag and drop menu when dropping items onto playlists,
allowing users to drop the dragged tracks, the whole album, or
the whole artists's tracks.
* Bring Tomahawk window to the front when clicking a Tomahawk link.
* Fixed crash in source list when initially syncing with remote sources.
* Open temporary artist, album, and search playlists as temporary items
in the sidebar.
* Fixed sorting of playlists and items in the artist view.
* Allow dragging and dropping albums and artists to playlists.
* Added MPRIS 2.1 support.
Version 0.2.3:
* Fixed opening Rdio and Spotify links.
* Fixed potential crash in sidebar during syncing of sources.
* When Listening Along, the last song a peer plays is no longer duplicated.
* Fixed an issue where the Twitter plugin could get out of sync if the
database was cleared, leading to eventual crashes when re-connecting.
* Fixed duplicate albums showing up on Dashboard.
* Automatically sort search results by score.
* Fixed stations being stuck not fetching more songs.
* Fixed issue where artist bio could be referring to a different artist.
* Opening a "tomahawk" URL (or other URL with Tomahawk) brings the Tomahawk
window to the foreground.
Version 0.2.2:
* Fixed crash pressing previous and next when playing a song from the Queue.
* Fixed issue where wrench for newly added resolvers would not show up.
* Fixed crash when pressing previous and next when playing a song from the Queue.
* Fixed issue where wrench for newly added resolvers would not show up immediately.
* Fixed sidebar statistics not updating after collection scan finished.
* Fixed omitting a few tracks in the Collection tree-view.
* Fixed sidebar & track sorting issues.
* Seek- & volume sliders now directly jump to the position you clicked on.
* Added ability to drag artists and albums within Tomahawk.
* (OS X) Fixed Ogg Vorbis support.
* Added ability to drag artists and albums within Tomahawk (to playlists, queue, etc.).
Version 0.2.1:
* Fixed crashing trying to play an unavailable track.

27
README
View File

@@ -27,25 +27,18 @@ Doxygen Documentation
Dependencies
------------
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/
TagLib 1.6.2 - http://developer.kde.org/~wheeler/taglib.html
Boost 1.3 - http://www.boost.org/
CLucene 0.9.23 (0.9.21 will fail) - http://clucene.sourceforge.net/download.shtml
libechonest 1.2.0 - http://projects.kde.org/projects/playground/libs/libechonest/
The following dependencies are optional, but recommended:
Attica 0.2.0 - ftp://ftp.kde.org/pub/kde/stable/attica/
jreen (Git) - https://github.com/euroelessar/jreen
QTweetLib 0.3.0 - https://github.com/minimoog/QTweetLib
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/
TagLib 1.6.2 http://developer.kde.org/~wheeler/taglib.html
Boost 1.3x http://www.boost.org/
CLucene 0.9.23 (0.9.21 will fail) http://clucene.sourceforge.net/download.shtml
libechonest 1.1.8 http://projects.kde.org/projects/playground/libs/libechonest/
Third party libraries that we ship with our source:
MiniUPnP 1.6 - http://miniupnp.free.fr/
liblastfm 0.4.0 - http://github.com/jonocole/liblastfm/
QuaZip 0.4.3 - http://quazip.sourceforge.net/
MiniUPnP http://miniupnp.free.fr/
liblastfm 0.4.0 http://github.com/jonocole/liblastfm/
Enjoy!

View File

@@ -1,3 +1,3 @@
IF(WIN32)
INSTALL(DIRECTORY win DESTINATION share/tomahawk/admin )
ENDIF(WIN32)
ENDIF(WIN32)

View File

@@ -1,5 +0,0 @@
#!/bin/sh
DUMPID=`head -n1 $1 | cut -f4 -d' '`
mkdir -p $2/$DUMPID
cp $1 $2/$DUMPID/

View File

@@ -41,7 +41,7 @@ VERSION=$1
header "Copying Sparkle framework"
cp -R /Library/Frameworks/Sparkle.framework Contents/Frameworks
header "Creating DMG"
cd ..

View File

@@ -207,7 +207,7 @@ TOMAHAWK_PLUGINS = [
]
QT_PLUGINS_SEARCH_PATH=[
'/usr/local/Cellar/qt/4.7.4/plugins',
'/usr/local/Cellar/qt/4.7.3/plugins',
]
@@ -500,11 +500,6 @@ try:
FixPlugin('spotify_tomahawkresolver', '../MacOS')
except:
print 'Failed to find spotify resolver'
try:
FixPlugin('CrashReporter', '../MacOS')
except:
print 'Failed to find CrashReporter'
for plugin in QT_PLUGINS:
FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -1,60 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="600px" height="600px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve">
<path fill="#010101" d="M543.773,253.359c0-49.962-19.305-86.572-54.194-104.54C477.84,71.133,405.027,13.418,316.568,13.418
c-86.917,0-159.483,56.481-172.605,132.58c-38.049,16.818-59.889,55.24-59.889,107.361c0,27.029,7.188,51.824,20.321,71.749
c-1.816,1.565-3.444,3.282-4.77,5.239c0,0,2.582,2.359,3.689,3.373c-4.262,2.123-8.22,4.322-11.555,6.67
c0,0,3.021,7.355,5.896,14.353c-11.991,9.688-21.312,18.92-27.553,27.51c0,0,1.611,1.789,2.011,2.225
c-12.354,9.158-22.133,18.205-28.528,27.021c0,0,6.927,7.35,12.408,13.166c-17.824,28.76-43.348,74.85-43.348,102.988
c0,3.278,0.346,6.315,1.093,9.053c1.764,6.443,5.752,11.438,11.229,14.059c15.255,7.312,39.646-6.362,72.589-40.434
c-0.828,8.287-1.457,16.662-1.457,24.736c0,16.805,2.266,32.069,8.77,41.25c4.887,6.895,10.898,9.067,15.084,9.682
c6.723,0.99,26.375,3.797,57.992-61.295c2.678,0.705,5.421,1.178,8.235,1.178c8.798,0,17.065-3.424,23.287-9.639
c4.284-4.287,7.133-9.584,8.562-15.312c7.516-2.129,14.555-6.701,20.779-13.19c19.562,24.86,44.779,37.643,75.38,37.643
c7.317,0,14.474-0.754,21.281-2.242c0.392-0.073,2.555-0.623,2.555-0.623l0.62-0.166c23.05-5.823,42.463-20.409,58-43.254
c7.2,9.23,15.731,15.994,24.849,19.457c1.141,6.658,4.226,12.808,9.102,17.691c6.22,6.213,14.487,9.639,23.288,9.639
c8.798,0,17.063-3.426,23.285-9.639c6.221-6.229,9.647-14.494,9.647-23.293c0-8.797-3.429-17.066-9.647-23.293
c-2.988-2.988-6.478-5.297-10.248-6.924c0.275-2.947,0.611-5.849,0.611-9.009c0-10.028-1.398-20.979-4.19-31.897
c-1.196-4.672-2.757-8.746-4.513-12.568c2.84-6.467,4.807-13.268,4.807-20.426c0-7.316-1.74-14.422-4.706-21.01
C509.263,358.345,543.773,313.068,543.773,253.359z M451.232,150.998c-33.396-54.619-88.048-93.359-134.569-85.472
c-49.022-7.864-102.775,30.64-135.326,85.018c-2.646,0.208-5.276,0.497-7.875,0.88c8.694-54.414,69.431-111.108,143.107-111.108
c74.113,0,135.142,57.197,143.271,112.08C457.013,151.799,454.137,151.348,451.232,150.998z"/>
<path fill="#010101" stroke="#FFFFFF" stroke-width="4.8437" d="M110.937,367.38c-72.03,93.07-97.843,163.349-81.865,170.996
c15.97,7.654,74.912-46.055,139.701-143.287c45.751-68.647,60.797-94.43,45.68-95.922l20.614-43.357l-10.687-6.644l-33.91,33.371
width="841.89px" height="595.28px" viewBox="0 0 841.89 595.28" enable-background="new 0 0 841.89 595.28" xml:space="preserve">
<path fill="#010101" d="M543.773,253.359c0-49.962-19.305-86.572-54.194-104.54C477.838,71.133,405.027,13.418,316.568,13.418
c-86.917,0-159.483,56.481-172.605,132.58c-38.049,16.818-59.889,55.24-59.889,107.361c0,27.029,7.186,51.825,20.321,71.748
c-1.816,1.566-3.444,3.283-4.768,5.24c0,0,2.582,2.36,3.689,3.374c-4.262,2.123-8.22,4.322-11.555,6.669
c0,0,3.022,7.355,5.898,14.352c-11.991,9.687-21.314,18.92-27.553,27.51c0,0,1.612,1.789,2.011,2.224
c-12.355,9.158-22.133,18.206-28.528,27.021c0,0,6.925,7.351,12.408,13.167c-17.824,28.759-43.348,74.85-43.348,102.987
c0,3.281,0.346,6.318,1.093,9.054c1.764,6.442,5.752,11.437,11.229,14.058c15.255,7.311,39.648-6.364,72.589-40.434
c-0.828,8.288-1.457,16.663-1.457,24.737c0,16.804,2.266,32.07,8.77,41.249c4.886,6.895,10.898,9.07,15.084,9.683
c6.721,0.989,26.375,3.796,57.992-61.296c2.678,0.705,5.421,1.179,8.235,1.179c8.798,0,17.067-3.425,23.287-9.639
c4.286-4.288,7.133-9.584,8.562-15.313c7.516-2.129,14.555-6.702,20.779-13.191c19.563,24.861,44.78,37.643,75.38,37.643
c7.318,0,14.474-0.755,21.281-2.243c0.392-0.075,2.555-0.622,2.555-0.622l0.62-0.167c23.05-5.824,42.463-20.41,58-43.254
c7.2,9.231,15.733,15.994,24.849,19.458c1.139,6.658,4.224,12.806,9.1,17.69c6.22,6.214,14.488,9.639,23.288,9.639
c8.798,0,17.065-3.425,23.285-9.639c6.221-6.228,9.649-14.494,9.649-23.292s-3.429-17.066-9.649-23.294
c-2.988-2.988-6.476-5.296-10.248-6.923c0.277-2.947,0.613-5.848,0.613-9.007c0-10.031-1.4-20.982-4.192-31.9
c-1.196-4.672-2.757-8.745-4.511-12.567c2.838-6.467,4.805-13.268,4.805-20.426c0-7.317-1.74-14.422-4.706-21.011
C509.263,358.346,543.773,313.068,543.773,253.359z M451.232,150.998c-33.395-54.619-88.048-93.359-134.569-85.472
c-49.024-7.864-102.777,30.64-135.326,85.018c-2.648,0.208-5.278,0.497-7.875,0.88c8.694-54.414,69.429-111.108,143.107-111.108
c74.113,0,135.141,57.197,143.269,112.08C457.013,151.799,454.137,151.348,451.232,150.998z"/>
<path fill="#010101" stroke="#FFFFFF" stroke-width="4.8437" d="M110.937,367.38c-72.03,93.07-97.843,163.348-81.865,170.997
c15.97,7.654,74.912-46.056,139.701-143.288c45.751-68.648,60.797-94.429,45.68-95.922l20.614-43.357l-10.685-6.644l-33.912,33.371
C179.323,272.615,166.073,296.146,110.937,367.38z"/>
<path fill="#010101" stroke="#FFFFFF" stroke-width="4.8437" d="M140.932,379.755c-39.101,113.041-39.738,189.89-20.813,192.654
c18.912,2.787,59.039-67.617,89.306-182.603c21.383-81.178,27.257-111.029,11.438-108l5.133-48.806l-13.207-3.354l-22.192,42.936
<path fill="#010101" stroke="#FFFFFF" stroke-width="4.8437" d="M140.932,379.755c-39.099,113.042-39.738,189.89-20.813,192.654
c18.912,2.787,59.039-67.616,89.306-182.6c21.381-81.178,27.255-111.03,11.438-108.001l5.133-48.806l-13.207-3.354l-22.194,42.936
C175.736,266.142,170.865,293.244,140.932,379.755z"/>
<circle fill="none" stroke="#010101" stroke-width="4.8437" cx="410.28" cy="388.832" r="37.801"/>
<circle fill="none" stroke="#010101" stroke-width="4.8437" cx="410.28" cy="388.831" r="37.801"/>
<path fill="#ED2224" stroke="#010101" stroke-width="4.8437" d="M475.237,157.792c-7.115-73.197-76.231-130.645-160.495-130.645
c-83.402,0-152.009,56.27-160.306,128.393c-39.811,13.607-58.455,52.219-58.455,97.818c0,56.946,34.681,103.108,89.925,103.108
c35.784,0,67.089-19.432,84.771-48.551c14.01,3.533,28.776,5.463,44.064,5.463c13.16,0,25.934-1.438,38.173-4.076
c17.966,28.357,49.108,47.164,84.604,47.164c55.665,0,90.696-46.162,90.696-103.108
C528.218,210.073,512.209,173.073,475.237,157.792z M314.742,274.908c-10.501,0-20.723-0.878-30.584-2.506
c-83.402,0-152.009,56.27-160.306,128.393c-39.809,13.607-58.455,52.219-58.455,97.818c0,56.947,34.681,103.109,89.925,103.109
c35.784,0,67.089-19.432,84.771-48.551c14.01,3.533,28.778,5.463,44.066,5.463c13.16,0,25.932-1.438,38.173-4.077
c17.966,28.357,49.108,47.165,84.604,47.165c55.665,0,90.696-46.162,90.696-103.109
C528.216,210.073,512.208,173.073,475.237,157.792z M314.742,274.908c-10.501,0-20.723-0.878-30.584-2.506
c1.125-6.177,1.778-12.527,1.778-19.043c0-56.941-44.786-103.104-100.03-103.104c-4.858,0-9.597,0.478-14.271,1.169
c8.692-54.414,69.43-111.108,143.105-111.108c74.113,0,135.144,57.197,143.27,112.08c-6.617-1.398-13.473-2.141-20.49-2.141
c8.694-54.414,69.43-111.108,143.107-111.108c74.113,0,135.142,57.197,143.268,112.08c-6.617-1.398-13.471-2.141-20.49-2.141
c-55.675,0-100.801,46.163-100.801,103.104c0,6.852,0.687,13.536,1.931,20.013C330.872,274.364,322.888,274.908,314.742,274.908z"/>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-1087.6663" y1="191.4385" x2="-992.1917" y2="191.4385" gradientTransform="matrix(-0.3782 -0.8348 1.083 -0.4907 -423.9551 -476.2263)">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-55.6953" y1="95.2363" x2="39.7773" y2="95.2363" gradientTransform="matrix(-0.3782 -0.8348 1.083 -0.4907 70.5233 338.0542)">
<stop offset="0" style="stop-color:#010101"/>
<stop offset="0.2606" style="stop-color:#3E221C"/>
<stop offset="0.7732" style="stop-color:#B03126"/>
<stop offset="1" style="stop-color:#ED2224"/>
</linearGradient>
<path fill="url(#SVGID_1_)" d="M153.69,260.35c31.322-14.19,65.739-18.887,77.129,6.254c11.391,25.14-4.763,57.026-36.091,71.214
c-31.323,14.192-65.948,5.311-77.338-19.83C106,292.849,122.366,274.543,153.69,260.35z"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="-1275.886" y1="215.5034" x2="-1180.4114" y2="215.5034" gradientTransform="matrix(-0.9008 -0.3607 0.555 -1.386 -752.6548 131.7681)">
<path fill="url(#SVGID_1_)" d="M153.69,260.35c31.322-14.19,65.739-18.887,77.129,6.254c11.391,25.14-4.763,57.027-36.091,71.213
c-31.323,14.194-65.948,5.312-77.338-19.829C106,292.849,122.366,274.543,153.69,260.35z"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="-180.8516" y1="181.2642" x2="-85.3789" y2="181.2642" gradientTransform="matrix(-0.9008 -0.3607 0.555 -1.386 252.7537 479.2919)">
<stop offset="0" style="stop-color:#B11F24"/>
<stop offset="0.1017" style="stop-color:#B62024"/>
<stop offset="1" style="stop-color:#ED2224"/>
</linearGradient>
<path fill="url(#SVGID_2_)" d="M427.738,265.165c16.043-40.085,41.342-74.985,68.475-64.122
c27.121,10.86,36.109,52.165,20.056,92.248c-16.053,40.089-51.062,63.773-78.189,52.912
<path fill="url(#SVGID_2_)" d="M427.738,265.165c16.043-40.085,41.342-74.985,68.473-64.122
c27.122,10.86,36.111,52.165,20.056,92.248c-16.053,40.089-51.062,63.772-78.189,52.911
C410.95,335.343,411.683,305.253,427.738,265.165z"/>
<path fill="#010101" stroke="#010101" stroke-width="4.8437" d="M448.219,425.226c7.774,30.396,3.98,62.357-14.521,62.357
c-16.301,0-34.904-17.332-42.675-47.732c-7.777-30.399,4.243-75.016,14.521-62.364C423.584,399.707,440.442,394.826,448.219,425.226
z"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-639.5422" y1="548.502" x2="-691.4051" y2="458.673" gradientTransform="matrix(0.9868 0.0515 0.0515 0.7987 840.2104 72.6462)">
<path fill="#010101" stroke="#010101" stroke-width="4.8437" d="M448.219,425.226c7.776,30.397,3.982,62.358-14.521,62.358
c-16.301,0-34.904-17.333-42.675-47.733c-7.777-30.4,4.243-75.016,14.521-62.365C423.583,399.707,440.442,394.825,448.219,425.226z"
/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="217.0322" y1="557.499" x2="165.1699" y2="467.6709" gradientTransform="matrix(0.9868 0.0515 0.0515 0.7987 -5.5217 21.3475)">
<stop offset="0" style="stop-color:#5B3E1D"/>
<stop offset="0.1121" style="stop-color:#42301B"/>
<stop offset="0.2377" style="stop-color:#2E2316"/>
@@ -64,30 +64,29 @@
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<path fill="url(#SVGID_3_)" stroke="#010101" stroke-width="4.8437" d="M184.076,437.859c-6.111,23.875,1.745,46.508,17.54,50.549
c15.79,4.039,33.552-12.045,39.658-35.924c6.101-23.882-9.153-57.129-24.947-61.17C200.537,387.275,190.178,413.972,184.076,437.859
c15.79,4.039,33.552-12.045,39.658-35.924c6.101-23.881-9.153-57.129-24.947-61.17C200.537,387.275,190.178,413.973,184.076,437.859
z"/>
<path fill="#010101" stroke="#010101" stroke-width="4.8437" d="M314.837,65.525c72.757-12.333,165.505,89.311,165.505,187.528
c0,98.213-74.307,162.833-165.707,162.833"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-664.3811" y1="374.0068" x2="-500.546" y2="90.2362" gradientTransform="matrix(1 0 0 1 858.79 0.3506)">
<path fill="#010101" stroke="#010101" stroke-width="4.8437" d="M314.837,65.525c72.755-12.333,165.503,89.311,165.503,187.528
c0,98.215-74.305,162.834-165.707,162.834"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="194.4072" y1="374.3564" x2="358.2427" y2="90.5851">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#5B3E1D"/>
</linearGradient>
<path fill="url(#SVGID_4_)" stroke="#010101" stroke-width="4.8437" d="M314.635,415.888c-91.402,0-165.299-64.619-165.299-162.833
<path fill="url(#SVGID_4_)" stroke="#010101" stroke-width="4.8437" d="M314.634,415.888c-91.402,0-165.297-64.619-165.297-162.834
c0-98.218,88.615-199.862,165.5-187.528"/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="-760.302" y1="-37.9087" x2="-639.3506" y2="-247.4027" gradientTransform="matrix(-0.6092 0.7802 -0.4118 -0.3216 -240.6183 671.6459)">
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="297.3164" y1="139.4717" x2="418.2684" y2="-70.0234" gradientTransform="matrix(-0.6092 0.7802 -0.4118 -0.3216 476.7253 -96.4624)">
<stop offset="0" style="stop-color:#8B654B"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<path fill="url(#SVGID_5_)" d="M169.611,266.578c-27.578-21.539-16.863-81.354,23.935-133.604
c40.804-52.245,93.81-72.894,126.21-59.689c26.672,10.864,14.476,85.434-26.326,137.681
c40.802-52.245,93.808-72.894,126.21-59.689c26.67,10.864,14.474,85.434-26.328,137.681
C252.63,263.215,197.193,288.112,169.611,266.578z"/>
<circle fill="#010101" cx="214.367" cy="388.832" r="34.682"/>
<circle fill="#010101" cx="214.367" cy="388.831" r="34.682"/>
<g>
<path fill="#F4DFED" d="M131.831,427.708c-23.973,79.734-18.741,132.268-9.011,135.459c10.854,3.564,43.561-47.223,60.839-128.324
c12.189-57.264,11.729-83.75,0.009-81.625l3.505-31.108l-8.899-2.435l-14.271,32.445
C152.554,347.564,150.184,366.689,131.831,427.708z"/>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="-710.6404" y1="319.3252" x2="-710.6405" y2="562.8164" gradientTransform="matrix(1 0 0 1 858.79 0.3506)">
<path fill="#F4DFED" d="M131.831,427.709c-23.973,79.733-18.741,132.267-9.011,135.459c10.855,3.563,43.561-47.223,60.839-128.324
c12.189-57.265,11.727-83.75,0.009-81.625l3.505-31.111l-8.901-2.432l-14.271,32.445
C152.554,347.564,150.184,366.689,131.831,427.709z"/>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="148.1519" y1="319.6758" x2="148.1518" y2="563.168">
<stop offset="0" style="stop-color:#571A54"/>
<stop offset="0.2641" style="stop-color:#7C5378"/>
<stop offset="0.528" style="stop-color:#A78AA3"/>
@@ -95,11 +94,11 @@
<stop offset="0.9095" style="stop-color:#EAE1E8"/>
<stop offset="1" style="stop-color:#F9F3F8"/>
</linearGradient>
<path fill="url(#SVGID_6_)" d="M146.41,479.117l-22.914,19.186l35.325-65.182l4.683-17.371c0,0,3.1-26.758-24.228,14.713
c16.962-56.432,32.317-62.998,32.317-62.998l11.402-46.658l-4.725-1.131l-14.702,30.23c-11.429-4.588-13.859,14.521-32.392,75.483
c-24.226,79.656-20.501,124.087-8.358,137.777L146.41,479.117z"/>
<path fill="url(#SVGID_6_)" d="M146.41,479.117l-22.914,19.186l35.325-65.182l4.683-17.371c0,0,3.098-26.758-24.228,14.713
c16.962-56.432,32.317-62.998,32.317-62.998l11.404-46.658l-4.725-1.131l-14.702,30.23c-11.429-4.588-13.859,14.521-32.392,75.485
c-24.224,79.655-20.501,124.085-8.358,137.776L146.41,479.117z"/>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="-789.3508" y1="444.1797" x2="-821.2424" y2="531.975" gradientTransform="matrix(0.9399 -0.3414 0.3414 0.9399 754.2939 -277.891)">
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="75.7998" y1="402.9658" x2="43.9086" y2="490.7602" gradientTransform="matrix(0.9399 -0.3414 0.3414 0.9399 -44.7892 56.207)">
<stop offset="0" style="stop-color:#802986"/>
<stop offset="0.2641" style="stop-color:#9D66A2"/>
<stop offset="0.528" style="stop-color:#BE9BC2"/>
@@ -107,10 +106,10 @@
<stop offset="0.9095" style="stop-color:#F0E6F1"/>
<stop offset="1" style="stop-color:#F9F3F8"/>
</linearGradient>
<path fill="url(#SVGID_7_)" d="M147.332,501.478l31.839-92.399c0,0,6.608,60.69-7.474,93.406
c1.438-44.879-2.328-36.951-9.176-25.257C159.71,482.031,147.332,501.478,147.332,501.478z"/>
<path fill="url(#SVGID_7_)" d="M147.332,501.478l31.839-92.4c0,0,6.608,60.692-7.474,93.405
c1.438-44.878-2.328-36.951-9.176-25.254C159.71,482.03,147.332,501.478,147.332,501.478z"/>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="-764.8928" y1="411.2344" x2="-797.3259" y2="500.5203" gradientTransform="matrix(0.9399 -0.3414 0.3414 0.9399 754.2939 -277.891)">
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="100.2559" y1="370.0205" x2="67.8228" y2="459.3065" gradientTransform="matrix(0.9399 -0.3414 0.3414 0.9399 -44.7892 56.207)">
<stop offset="0" style="stop-color:#802986"/>
<stop offset="0.2641" style="stop-color:#9D66A2"/>
<stop offset="0.528" style="stop-color:#BE9BC2"/>
@@ -118,10 +117,10 @@
<stop offset="0.9095" style="stop-color:#F0E6F1"/>
<stop offset="1" style="stop-color:#F9F3F8"/>
</linearGradient>
<path fill="url(#SVGID_8_)" d="M156.286,463.716l38.825-93.953c0,0,2.251,62.279-11.831,94.992
c-0.298-44.25-5.388-28.09-8.538-23.508C165.662,454.416,156.286,463.716,156.286,463.716z"/>
<path fill="url(#SVGID_8_)" d="M156.286,463.716l38.825-93.952c0,0,2.251,62.278-11.831,94.991
c-0.298-44.249-5.388-28.089-8.538-23.508C165.662,454.416,156.286,463.716,156.286,463.716z"/>
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="-872.7551" y1="422.8174" x2="-924.3751" y2="475.0038" gradientTransform="matrix(0.711 -0.7032 0.7032 0.711 517.3177 -556.6326)">
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="19.1768" y1="337.1123" x2="-32.4432" y2="389.2988" gradientTransform="matrix(0.711 -0.7032 0.7032 0.711 -56.5767 131.5096)">
<stop offset="0" style="stop-color:#571A54"/>
<stop offset="0.2641" style="stop-color:#7C5378"/>
<stop offset="0.528" style="stop-color:#A78AA3"/>
@@ -129,22 +128,21 @@
<stop offset="0.9095" style="stop-color:#EAE1E8"/>
<stop offset="1" style="stop-color:#F9F3F8"/>
</linearGradient>
<path fill="url(#SVGID_9_)" d="M180.916,431.115l9.787-73.404c0,0,18.589,43.111,16.428,71.426
c-11.771-30.424-13.671-21.049-17.576-14.961C187.396,417.539,180.916,431.115,180.916,431.115z"/>
<path fill="#1E3D73" d="M174.914,335.556L158.76,362.31l-23.24,76.646c0,0,1.211-8.172,1.788-15.883l-18.783,50.772
c0,0,8.386-31.227,3.607-28.383c-4.775,2.84,4.227-21.91-23.102,13.73c5.316-18.517,20.495-39.511,33.324-54.9
c-2.172,0.473-7.102,4.787-18.388,18.373c4.381-15.232,14.956-32.934,25.357-47.898c-1.159-2.682-5.151-3.889-21.234,5.224
C134.366,356.718,174.914,335.556,174.914,335.556z"/>
<path fill="url(#SVGID_9_)" d="M180.916,431.115l9.787-73.404c0,0,18.589,43.111,16.428,71.425
c-11.773-30.423-13.671-21.048-17.578-14.96C187.396,417.538,180.916,431.115,180.916,431.115z"/>
<path fill="#1E3D73" d="M174.914,335.556L158.76,362.31l-23.24,76.647c0,0,1.211-8.173,1.788-15.883l-18.783,50.773
c0,0,8.386-31.226,3.609-28.382c-4.777,2.84,4.225-21.91-23.102,13.729c5.316-18.514,20.495-39.508,33.324-54.9
c-2.172,0.474-7.1,4.788-18.387,18.374c4.38-15.232,14.957-32.934,25.358-47.898c-1.159-2.683-5.151-3.889-21.234,5.221
C134.366,356.719,174.914,335.556,174.914,335.556z"/>
</g>
<g>
<path fill="#F4DFED" d="M94.453,401.164c-49.752,66.752-62.779,117.912-54.719,124.242c8.987,7.059,57.062-29.513,100.989-99.847
c31.011-49.655,39.62-74.709,27.879-76.713l13.916-28.053l-7.539-5.318l-24.483,25.623
C141.291,332.912,132.531,350.072,94.453,401.164z"/>
<path fill="#656B84" d="M90.603,454.464l-28.088,10.205l55.456-49.201l10.331-14.729c0,0,12.047-24.097-27.796,5.559
c35.213-47.256,51.892-48.182,51.892-48.182l26.641-39.957l-4.058-2.683l-24.133,23.4c-9.179-8.223-17.989,8.91-56.226,59.885
c-49.96,66.601-61.634,109.635-54.889,126.646L90.603,454.464z"/>
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="-752.551" y1="484.6816" x2="-736.7991" y2="395.3488" gradientTransform="matrix(1 0 0 1 858.79 0.3506)">
<path fill="#F4DFED" d="M94.453,401.163c-49.752,66.752-62.779,117.913-54.719,124.242c8.987,7.059,57.064-29.51,100.989-99.844
c31.011-49.657,39.62-74.709,27.879-76.714l13.916-28.052l-7.539-5.319L150.496,341.1
C141.291,332.911,132.531,350.072,94.453,401.163z"/>
<path fill="#656B84" d="M90.603,454.464L62.515,464.67l55.456-49.201l10.331-14.731c0,0,12.047-24.096-27.794,5.558
c35.211-47.255,51.89-48.182,51.89-48.182l26.641-39.956l-4.058-2.681l-24.133,23.399c-9.177-8.222-17.989,8.911-56.224,59.885
c-49.96,66.6-61.634,109.635-54.889,126.645L90.603,454.464z"/>
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="106.2383" y1="485.0312" x2="121.9901" y2="395.6984">
<stop offset="0" style="stop-color:#571A54"/>
<stop offset="0.2641" style="stop-color:#7C5378"/>
<stop offset="0.528" style="stop-color:#A78AA3"/>
@@ -152,10 +150,9 @@
<stop offset="0.9095" style="stop-color:#EAE1E8"/>
<stop offset="1" style="stop-color:#F9F3F8"/>
</linearGradient>
<path fill="url(#SVGID_10_)" d="M83.829,475.791l61.476-75.98c0,0-14.509,59.306-38.916,85.248
c16.678-41.694,12.058-33.366,0-26.873C101.491,460.822,83.829,475.791,83.829,475.791z"/>
<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="-727.8064" y1="453.3486" x2="-711.9149" y2="363.2233" gradientTransform="matrix(1 0 0 1 858.79 0.3506)">
<path fill="url(#SVGID_10_)" d="M83.829,475.791l61.474-75.981c0,0-14.507,59.304-38.916,85.248
c16.678-41.696,12.058-33.368,0-26.873C101.491,460.821,83.829,475.791,83.829,475.791z"/>
<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="130.9844" y1="453.7012" x2="146.8758" y2="363.5764">
<stop offset="0" style="stop-color:#571A54"/>
<stop offset="0.2641" style="stop-color:#7C5378"/>
<stop offset="0.528" style="stop-color:#A78AA3"/>
@@ -163,36 +160,37 @@
<stop offset="0.9095" style="stop-color:#EAE1E8"/>
<stop offset="1" style="stop-color:#F9F3F8"/>
</linearGradient>
<path fill="url(#SVGID_11_)" d="M105.143,443.357l68.562-75.052c0,0-19.143,59.297-43.551,85.248
c14.824-41.7,10.567-27.994,0-25.022C124.802,430.041,105.143,443.357,105.143,443.357z"/>
<path fill="#656B84" d="M139.423,421.125l34.262-65.654c0,0,2.748,46.867-8.945,72.74c-0.676-32.615-3.041-28.432-11.413-20.061
C150.5,410.974,139.423,421.125,139.423,421.125z"/>
<path fill="#656B84" d="M166.408,329.255l-24.322,19.631l-48.011,64.111c0,0,3.931-7.273,7.104-14.322L66.185,439.99
c0,0,18.552-26.484,13.089-25.449c-5.464,1.041,11.451-19.148-26.399,5.02c11.313-15.588,32.751-30.137,50.064-40.227
c-2.205-0.299-8.316,2.076-23.552,10.988c9.312-12.818,25.302-25.842,40.183-36.357c-0.175-2.918-3.515-5.416-21.74-2.346
C121.065,335.3,166.408,329.255,166.408,329.255z"/>
<path fill="url(#SVGID_11_)" d="M105.143,443.356l68.564-75.05c0,0-19.143,59.297-43.551,85.248
c14.824-41.701,10.567-27.993,0-25.023C124.802,430.041,105.143,443.356,105.143,443.356z"/>
<path fill="#656B84" d="M139.423,421.124l34.26-65.654c0,0,2.748,46.867-8.945,72.74c-0.676-32.615-3.041-28.432-11.413-20.06
C150.5,410.974,139.423,421.124,139.423,421.124z"/>
<path fill="#656B84" d="M166.408,329.256l-24.322,19.63l-48.011,64.112c0,0,3.931-7.274,7.104-14.322l-34.994,41.313
c0,0,18.552-26.484,13.089-25.448c-5.464,1.04,11.451-19.148-26.399,5.019c11.313-15.587,32.751-30.137,50.064-40.227
c-2.205-0.298-8.316,2.077-23.552,10.989c9.313-12.818,25.302-25.842,40.183-36.357c-0.175-2.919-3.515-5.416-21.74-2.346
C121.065,335.3,166.408,329.256,166.408,329.256z"/>
</g>
<g>
<path fill="#D9AF82" d="M315.05,115.063c-50.514,0-83.218,15.021-109.641,64.839c-2.502,4.713-0.23,14.337-2.796,19.152
c-13.845,26.007-37.089,48.236-37.089,71.707c0,34.335,19.1,65.637,42.505,89.296c12.185,71.646,34.7,151.595,104.339,151.595"/>
<path fill="#010101" d="M203.271,178.766c-1.521,2.855-1.59,6.774-1.656,10.562c-0.062,3.283-0.123,6.677-1.14,8.588
c-4.537,8.519-10.146,16.707-15.577,24.624c-11.21,16.353-21.797,31.798-21.797,48.221c0,30.307,15.166,62.38,42.666,90.412
c12.578,73.607,36.113,150.479,106.6,150.479v-1.547c-67.084,0-89.722-78.556-101.95-150.453l-0.127-0.748l-0.54-0.549
c-26.957-27.257-41.805-58.361-41.805-87.594c0-14.923,10.174-29.766,20.949-45.482c5.501-8.027,11.19-16.327,15.855-25.087
c1.562-2.935,1.638-6.92,1.707-10.773c0.059-3.221,0.118-6.551,1.088-8.381c24.258-45.734,54.398-65.974,107.503-65.974v-2.422
<path fill="#D9AF82" enable-background="new " d="M315.05,115.063c-50.514,0-83.218,15.021-109.641,64.839
c-2.502,4.713-0.232,14.337-2.796,19.152c-13.845,26.007-37.089,48.236-37.089,71.707c0,34.337,19.1,65.637,42.505,89.297
c12.185,71.644,34.7,151.593,104.339,151.593"/>
<path fill="#010101" d="M203.271,178.766c-1.519,2.855-1.59,6.774-1.656,10.562c-0.062,3.283-0.123,6.677-1.14,8.588
c-4.537,8.519-10.146,16.707-15.577,24.624c-11.21,16.353-21.797,31.798-21.797,48.221c0,30.307,15.166,62.382,42.666,90.413
c12.578,73.606,36.115,150.477,106.6,150.477v-1.546c-67.084,0-89.722-78.554-101.95-150.453l-0.127-0.748l-0.54-0.549
c-26.957-27.255-41.805-58.361-41.805-87.594c0-14.923,10.174-29.766,20.949-45.482c5.501-8.027,11.192-16.327,15.857-25.087
c1.56-2.935,1.636-6.92,1.707-10.773c0.057-3.221,0.118-6.551,1.088-8.381c24.256-45.734,54.398-65.974,107.503-65.974v-2.422
C259.849,112.641,228.506,131.181,203.271,178.766z"/>
</g>
<path fill="#8B654B" d="M312.368,511.65c72.045,0,92.163-79.949,104.338-151.595c23.405-23.657,42.514-54.959,42.514-89.296
c0-37.004-22.588-49.51-38.609-77.154c-5.681-9.798-1.496-24.634-8.084-33.382c-26.905-35.728-53.772-45.162-97.477-45.162"/>
<path fill="#8B654B" d="M312.368,511.65c72.045,0,92.163-79.949,104.338-151.593c23.405-23.66,42.512-54.96,42.512-89.297
c0-37.004-22.588-49.51-38.609-77.154c-5.681-9.798-1.496-24.634-8.084-33.382c-26.905-35.728-53.772-45.162-97.475-45.162"/>
<ellipse fill="#D9AF82" cx="313.792" cy="343.947" rx="21.906" ry="68.144"/>
<path fill="#8B654B" d="M342.916,373.455c0,7.812-14.979,12.535-27.273,12.535c-12.293,0-27.81-4.736-27.81-12.549
c3.432-3.433,15.246,4.885,27.544,4.885C334.789,378.326,342.916,312.496,342.916,373.455z"/>
<path fill="#D9AF82" d="M335.697,435.216c0,37.637-9.81,68.832-21.91,68.832c-12.096,0-21.899-31.195-21.899-68.832
c0-37.639,9.882-50.258,21.977-50.258C325.962,384.958,335.697,397.578,335.697,435.216z"/>
<path opacity="0.36" fill="#8A644B" enable-background="new " d="M328.365,281.605c-1.826,24.682-14.186-7.573-34.757,20.975
c-8.672,12.025-23.23,10.877-38.845,10.877c-39.61,0-66.544-26.031-67.859-38.869c-2.517-24.557,29.024-39.586,71.464-39.586
<path fill="#8B654B" d="M342.916,373.454c0,7.813-14.98,12.535-27.275,12.535c-12.293,0-27.808-4.735-27.808-12.549
c3.43-3.43,15.246,4.886,27.544,4.886C334.789,378.326,342.916,312.495,342.916,373.454z"/>
<path fill="#D9AF82" d="M335.697,435.217c0,37.637-9.81,68.831-21.91,68.831c-12.096,0-21.901-31.194-21.901-68.831
c0-37.639,9.882-50.259,21.977-50.259C325.962,384.958,335.697,397.578,335.697,435.217z"/>
<path opacity="0.36" fill="#8A644B" d="M328.365,281.605c-1.826,24.681-14.186-7.573-34.757,20.974
c-8.672,12.026-23.23,10.877-38.845,10.877c-39.61,0-66.544-26.03-67.859-38.868c-2.517-24.557,29.024-39.586,71.464-39.586
C297.028,235.002,329.255,269.622,328.365,281.605z"/>
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="-644.0354" y1="340.7031" x2="-568.3508" y2="340.7031" gradientTransform="matrix(1 0 0 1 858.79 0.3506)">
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="214.7554" y1="341.0537" x2="290.4385" y2="341.0537">
<stop offset="0" style="stop-color:#D9AF82"/>
<stop offset="0.0786" style="stop-color:#DFB791"/>
<stop offset="0.2053" style="stop-color:#E7C1A5"/>
@@ -201,38 +199,40 @@
<stop offset="0.6917" style="stop-color:#F4D3C7"/>
<stop offset="1" style="stop-color:#F5D4C9"/>
</linearGradient>
<path opacity="0.36" fill="url(#SVGID_12_)" enable-background="new " d="M272.246,361.529
c-28.722,19.461-56.346-24.299-57.491-43.314c15.913,13.822,62.032,18.457,75.685-2.516L272.246,361.529z"/>
<path opacity="0.36" fill="#8A644B" enable-background="new " d="M313.706,461.212c-38.167,0-61.229-13.68-61.229-31.629
c0-6.049,15.649-24.078,37.318-49.365c5.952-3.699,7.464,10.037,14.958,4.73C331.61,392.044,328.318,461.212,313.706,461.212z"/>
<path opacity="0.36" fill="url(#SVGID_12_)" d="M272.246,361.529c-28.722,19.46-56.346-24.299-57.491-43.314
c15.913,13.821,62.032,18.457,75.683-2.517L272.246,361.529z"/>
<path opacity="0.36" fill="#8A644B" d="M313.706,461.213c-38.167,0-61.231-13.681-61.231-31.63c0-6.048,15.651-24.078,37.32-49.365
c5.952-3.699,7.464,10.038,14.958,4.731C331.61,392.044,328.318,461.213,313.706,461.213z"/>
<g>
<path fill="#8A644B" d="M260.464,472.117c8.341,23.938,32.817,36.465,52.688,36.465v-4.844
C294.99,503.738,268.056,493.921,260.464,472.117L260.464,472.117z"/>
<path fill="#8A644B" d="M260.464,472.116c8.339,23.94,32.817,36.466,52.688,36.466v-4.845
C294.99,503.737,268.056,493.921,260.464,472.116L260.464,472.116z"/>
</g>
<g>
<path fill="#8A644B" d="M180.954,271.658c0,21.359,5.388,36.679,27.101,48.222c0.587,1.121,7.021,13.387,7.021,13.387
c8.916,16.375,19.021,34.939,19.021,54.406h4.844c0-20.699-10.416-39.84-19.612-56.725l-7.586-14.455l-0.709-0.426
C190.51,305.4,180.954,291.289,180.954,271.658L180.954,271.658z"/>
<path fill="#8A644B" d="M180.954,271.658c0,21.359,5.388,36.679,27.099,48.222c0.587,1.121,7.021,13.387,7.021,13.387
c8.916,16.375,19.02,34.94,19.02,54.406h4.844c0-20.699-10.416-39.839-19.612-56.725l-7.586-14.455l-0.709-0.426
C190.509,305.4,180.954,291.289,180.954,271.658L180.954,271.658z"/>
</g>
<g>
<path fill="#010101" d="M208.814,230.649l-0.104-0.97c-3.106-15.25-3.226-33.651-0.312-49.217l-4.764-0.889
<path fill="#010101" d="M208.814,230.649l-0.104-0.97c-3.108-15.25-3.226-33.651-0.312-49.217l-4.764-0.889
C200.613,195.722,205.583,214.815,208.814,230.649z"/>
</g>
<linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="-667.7327" y1="310.1709" x2="-407.218" y2="310.1709" gradientTransform="matrix(1 0 0 1 858.79 0.3506)">
<linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="191.0591" y1="310.5205" x2="451.5771" y2="310.5205">
<stop offset="0" style="stop-color:#5B3E1D"/>
<stop offset="1" style="stop-color:#010101"/>
</linearGradient>
<path fill="url(#SVGID_13_)" d="M423.943,199.054c-3.983-11.059-0.737-20.853-8.062-31.231
c-19.885-28.185-51.07-56.271-108.998-52.618l5.214,140.363c0,0-122.733-25.589-121.021,15.935c0.229,5.387,40.188,2.88,63.46,4.428
c-26.092,4.566-32.185,5.898-32.185,8.838c0,6.206,21.861,0.683,25.106,2.467c4.978,2.739-43.139,7.052-34.351,8.757
c10.057,1.951,44.474,3.086,57.442,3.086c28.931,0,41.077-25.413,41.077-4.485c7.348,27.894,14.739,59.239,13.974,69.882
c-1.477,20.661-19.62,20.188-19.62,20.188l5.089,24.285c-8.557,0.438-6.245-1.324-13.85-0.549c-14.429,0-32.354,13.03-32.354,16.055
l39.989,0.434c0,0-29.081,13.771-22.977,22.931c4.765,7.143,20.316,13.377,31.093,13.424c0,0,3.271,8.549,3.271,22.352
c0,13.812-4.035,22.564-4.035,22.564c46.171,0,67.49-49.035,80.324-118.445c6.083-32.877,20.018-58.104,36.034-71.658
c15.742-13.319,23.008-26.64,23.008-52.07C451.577,249.847,443.574,230.354,423.943,199.054z"/>
<path fill="#D9AF82" d="M325.395,252.416l-13.297,4.328c0,0-65.85-96.356-46.493-121.312c12.682-16.357,24.609-18.136,40.046-19.238
c13.519-0.965,21.294,16.525,27.302,24.271C350.375,162.927,325.395,252.416,325.395,252.416z"/>
<linearGradient id="SVGID_14_" gradientUnits="userSpaceOnUse" x1="-629.0159" y1="50.6562" x2="-540.175" y2="50.6562" gradientTransform="matrix(0.676 0.6564 -0.9247 0.9523 711.8302 511.1852)">
<path fill="url(#SVGID_13_)" d="M423.943,199.054c-3.983-11.059-0.737-20.853-8.061-31.231
c-19.885-28.185-51.072-56.27-108.998-52.618l5.212,140.363c0,0-122.733-25.589-121.021,15.935c0.227,5.387,40.188,2.88,63.46,4.428
c-26.092,4.566-32.185,5.898-32.185,8.838c0,6.206,21.863,0.683,25.108,2.467c4.976,2.739-43.139,7.052-34.351,8.757
c10.057,1.951,44.474,3.086,57.444,3.086c28.929,0,41.077-25.412,41.077-4.485c7.346,27.893,14.739,59.24,13.972,69.882
c-1.475,20.662-19.62,20.188-19.62,20.188l5.089,24.285c-8.557,0.439-6.245-1.324-13.85-0.549
c-14.427,0-32.354,13.032-32.354,16.054l39.989,0.435c0,0-29.081,13.771-22.975,22.928c4.763,7.143,20.316,13.378,31.091,13.424
c0,0,3.273,8.55,3.273,22.352c0,13.811-4.035,22.565-4.035,22.565c46.171,0,67.49-49.036,80.324-118.446
c6.083-32.876,20.018-58.106,36.034-71.657c15.742-13.321,23.008-26.641,23.008-52.071
C451.577,249.847,443.574,230.354,423.943,199.054z"/>
<path fill="#D9AF82" d="M325.395,252.416l-13.297,4.328c0,0-65.848-96.356-46.493-121.312
c12.682-16.357,24.611-18.136,40.046-19.238c13.519-0.965,21.294,16.525,27.302,24.271
C350.375,162.927,325.395,252.416,325.395,252.416z"/>
<linearGradient id="SVGID_14_" gradientUnits="userSpaceOnUse" x1="260.7119" y1="113.4033" x2="349.5527" y2="113.4033" gradientTransform="matrix(0.676 0.6564 -0.9247 0.9523 168.3961 -132.5865)">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.0769" style="stop-color:#F4E9DD"/>
<stop offset="0.1814" style="stop-color:#EBD6BF"/>
@@ -242,10 +242,10 @@
<stop offset="0.7265" style="stop-color:#DAB084"/>
<stop offset="1" style="stop-color:#D9AF82"/>
</linearGradient>
<path fill="url(#SVGID_14_)" d="M305.253,199.27c-26.745,27.542-70.168,41.961-81.281,24.357
c-14.515-22.972-12.896-47.545,13.854-75.082c26.74-27.547,64.922-33.847,85.28-14.081
<path fill="url(#SVGID_14_)" d="M305.253,199.27c-26.745,27.542-70.168,41.961-81.283,24.357
c-14.513-22.972-12.896-47.545,13.854-75.082c26.74-27.547,64.922-33.847,85.28-14.081
C343.464,154.233,332.003,171.726,305.253,199.27z"/>
<linearGradient id="SVGID_15_" gradientUnits="userSpaceOnUse" x1="-617.7107" y1="401.4551" x2="-617.7107" y2="317.8633" gradientTransform="matrix(1 0 0 1 858.79 0.3506)">
<linearGradient id="SVGID_15_" gradientUnits="userSpaceOnUse" x1="241.0796" y1="401.8057" x2="241.0796" y2="318.2148">
<stop offset="0" style="stop-color:#D9AF82"/>
<stop offset="0.1127" style="stop-color:#BD936E"/>
<stop offset="0.2679" style="stop-color:#A57C5E"/>
@@ -253,29 +253,27 @@
<stop offset="0.6554" style="stop-color:#8D664D"/>
<stop offset="1" style="stop-color:#8A644B"/>
</linearGradient>
<path fill="url(#SVGID_15_)" d="M272.246,361.529c0,46.272-35.419,42.799-45.104,36.896c0-45.752-17.229-80.211-17.229-80.211
S249.882,354.22,272.246,361.529z"/>
<linearGradient id="SVGID_16_" gradientUnits="userSpaceOnUse" x1="-925.8547" y1="344.666" x2="-972.7458" y2="361.7328" gradientTransform="matrix(-1 0 0 1 -562.3931 0.3506)">
<path fill="url(#SVGID_15_)" d="M272.246,361.529c0,46.274-35.419,42.799-45.106,36.896c0-45.751-17.227-80.21-17.227-80.21
S249.882,354.221,272.246,361.529z"/>
<linearGradient id="SVGID_16_" gradientUnits="userSpaceOnUse" x1="175.4648" y1="345.0176" x2="128.5757" y2="362.0838" gradientTransform="matrix(-1 0 0 1 538.9277 0)">
<stop offset="0" style="stop-color:#382815"/>
<stop offset="0.4081" style="stop-color:#553E2B"/>
<stop offset="1" style="stop-color:#8B654B"/>
</linearGradient>
<path fill="url(#SVGID_16_)" d="M359.338,356.349c0,46.271,21.506,44.033,31.073,44.033c7.488-45.135,35.671-81.516,35.671-81.516
S381.703,349.044,359.338,356.349z"/>
<path fill="url(#SVGID_16_)" d="M359.338,356.35c0,46.27,21.504,44.032,31.073,44.032c7.488-45.135,35.671-81.515,35.671-81.515
S381.703,349.045,359.338,356.35z"/>
<path fill="none" stroke="#010101" stroke-width="4.8437" d="M173.934,294.978"/>
<g>
<path fill="#010101" d="M311.507,115.089c53.106,0,83.247,20.214,107.505,65.948c0.902,1.702,0.902,4.883,0.902,7.96
c-0.005,4.146-0.005,8.432,2.029,11.419c16.157,23.757,31.934,48.809,31.934,70.969c0,32.38-12.817,62.458-37.073,86.969
l-0.541,0.551l-0.13,0.748c-12.222,71.897-36.672,150.451-103.765,150.451v1.518c70.499,0,95.847-76.844,108.416-150.455
c24.803-25.336,37.937-56.355,37.937-89.781c0-23.537-16.19-49.311-32.774-73.694c-1.151-1.698-1.19-5.061-1.19-8.37
c0-0.109,0.004-0.537,0.004-0.646c0-3.567-0.041-7.221-1.471-9.91C398.053,131.18,366.71,112.64,311.51,112.64v2.449H311.507
L311.507,115.089z"/>
<path fill="#010101" d="M311.507,115.089c53.106,0,83.247,20.214,107.503,65.948c0.904,1.702,0.904,4.883,0.904,7.96
c-0.005,4.146-0.005,8.432,2.029,11.419c16.157,23.757,31.933,48.809,31.933,70.969c0,32.381-12.818,62.458-37.074,86.969
l-0.541,0.549l-0.128,0.748c-12.222,71.899-36.672,150.453-103.765,150.453v1.517c70.499,0,95.847-76.845,108.416-150.456
c24.801-25.335,37.935-56.354,37.935-89.78c0-23.537-16.19-49.311-32.774-73.694c-1.153-1.698-1.192-5.061-1.192-8.37
c0-0.109,0.004-0.537,0.004-0.646c0-3.567-0.041-7.221-1.469-9.91c-25.237-47.585-56.579-66.125-111.78-66.125V115.089z"/>
</g>
<polygon fill="#010101" points="339.974,84.79 334.59,115.675 300.608,113.719 312.435,66.413 "/>
<circle fill="#010101" stroke="#010101" stroke-width="4.8437" cx="452.06" cy="492.948" r="19.204"/>
<g>
<linearGradient id="SVGID_17_" gradientUnits="userSpaceOnUse" x1="-749.6116" y1="335.9512" x2="-687.9983" y2="335.9512" gradientTransform="matrix(1 0 0 1 858.79 0.3506)">
<linearGradient id="SVGID_17_" gradientUnits="userSpaceOnUse" x1="109.1782" y1="336.3027" x2="170.7935" y2="336.3027">
<stop offset="0" style="stop-color:#571A54"/>
<stop offset="0.2641" style="stop-color:#7C5378"/>
<stop offset="0.528" style="stop-color:#A78AA3"/>
@@ -283,10 +281,10 @@
<stop offset="0.9095" style="stop-color:#EAE1E8"/>
<stop offset="1" style="stop-color:#F9F3F8"/>
</linearGradient>
<path fill="url(#SVGID_17_)" d="M109.178,338.035c9.592-7.824,34.694,4.861,34.833,4.861l26.78-8.396
C170.211,334.501,120.246,321.648,109.178,338.035z"/>
<path fill="url(#SVGID_17_)" d="M109.178,338.034c9.592-7.823,34.696,4.862,34.833,4.862l26.782-8.396
C170.211,334.501,120.246,321.648,109.178,338.034z"/>
</g>
<linearGradient id="SVGID_18_" gradientUnits="userSpaceOnUse" x1="-1081.0227" y1="320.6133" x2="-1063.3801" y2="320.6133" gradientTransform="matrix(-0.0113 -0.7169 1.2476 -0.0198 -98.6661 -397.1379)">
<linearGradient id="SVGID_18_" gradientUnits="userSpaceOnUse" x1="-102.0645" y1="221.0444" x2="-84.4219" y2="221.0444" gradientTransform="matrix(-0.0113 -0.7169 1.2476 -0.0198 36.6184 302.7065)">
<stop offset="0" style="stop-color:#D9AF82"/>
<stop offset="0.0786" style="stop-color:#DFB791"/>
<stop offset="0.2053" style="stop-color:#E7C1A5"/>
@@ -295,10 +293,10 @@
<stop offset="0.6917" style="stop-color:#F4D3C7"/>
<stop offset="1" style="stop-color:#F5D4C9"/>
</linearGradient>
<path opacity="0.36" fill="url(#SVGID_18_)" enable-background="new " d="M313.352,358.851c6.074-0.1,11.045,2.654,11.102,6.15
c0.06,3.49-4.829,6.398-10.907,6.498c-6.076,0.1-11.045-2.658-11.105-6.154C302.388,361.853,307.269,358.947,313.352,358.851z"/>
<path fill="#483218" d="M397.109,309.378c15.699-3.76,26.445-18.402,20.099-27.063c-38.738,19.354-75.295,11.369-85.529,9.147
<path opacity="0.36" fill="url(#SVGID_18_)" d="M313.352,358.852c6.074-0.1,11.045,2.653,11.102,6.149
c0.058,3.49-4.829,6.399-10.907,6.498c-6.078,0.101-11.045-2.657-11.107-6.153C302.388,361.854,307.269,358.946,313.352,358.852z"/>
<path fill="#483218" d="M397.109,309.378c15.699-3.759,26.445-18.402,20.099-27.063c-38.74,19.354-75.295,11.369-85.531,9.147
C368.014,309.492,371.117,315.595,397.109,309.378z"/>
<path fill="#B4B4B4" d="M310.92,73.714c-38.372,0-93.116,22.758-117.549,74.944c-6.089,12.999-6.656,32.87,0.64,45.014
c0,0,18.604-81.43,108.229-86.494"/>
<path fill="#B4B4B4" d="M310.92,73.714c-38.372,0-93.118,22.758-117.549,74.944c-6.089,12.999-6.656,32.87,0.638,45.014
c0,0,18.604-81.43,108.231-86.494"/>
</svg>

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 563 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -91,11 +91,6 @@ var TomahawkResolver = {
var configJson = JSON.stringify( config );
window.localStorage[ this.scriptPath() ] = configJson;
this.newConfigSaved();
},
newConfigSaved: function()
{
},
resolve: function( qid, artist, album, title )
{
@@ -184,21 +179,6 @@ Tomahawk.syncRequest = function(url)
}
};
Tomahawk.asyncRequest = function(url, callback)
{
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open('GET', url, true);
xmlHttpRequest.onreadystatechange = function() {
if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) {
callback.call(window, xmlHttpRequest);
} else if (xmlHttpRequest.readyState === 4) {
Tomahawk.log("Failed to do GET request: to: " + url);
Tomahawk.log("Status Code was: " + xmlHttpRequest.status);
}
}
xmlHttpRequest.send(null);
};
/**
*
* Secure Hash Algorithm (SHA256)

View File

@@ -1,10 +0,0 @@
-- Script to migate from db version 6 to 27
-- Nothing to do
CREATE TABLE IF NOT EXISTS collection_attributes (
id INTEGER REFERENCES source(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED, -- source id, null for local source
k TEXT NOT NULL,
v TEXT NOT NULL
);
UPDATE settings SET v = '27' WHERE k == 'schema_version';

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@
<file>data/images/avatar-dude.png</file>
<file>data/images/back-pressed.png</file>
<file>data/images/back-rest.png</file>
<file>data/images/cover-shadow.png</file>
<file>data/images/filter.png</file>
<file>data/images/loved.png</file>
<file>data/images/not-loved.png</file>
@@ -12,7 +13,6 @@
<file>data/images/track-placeholder.png</file>
<file>data/images/now-playing-panel.png</file>
<file>data/images/now-playing-speaker.png</file>
<file>data/images/now-playing-speaker-dark.png</file>
<file>data/images/pause-pressed.png</file>
<file>data/images/pause-rest.png</file>
<file>data/images/play-pressed.png</file>
@@ -72,7 +72,6 @@
<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>
<file>data/images/supercollection.png</file>
@@ -86,18 +85,8 @@
<file>data/images/automatic-playlist.png</file>
<file>data/images/station.png</file>
<file>data/images/new-additions.png</file>
<file>data/images/charts.png</file>
<file>data/images/loved_playlist.png</file>
<file>data/images/dashboard.png</file>
<file>data/images/artist-icon.png</file>
<file>data/images/album-icon.png</file>
<file>data/images/search-icon.png</file>
<file>data/images/star-hover.png</file>
<file>data/images/starred.png</file>
<file>data/images/star-unstarred.png</file>
<file>data/images/track-icon-22x22.png</file>
<file>data/images/track-icon-32x32.png</file>
<file>data/images/track-icon-16x16.png</file>
<file>data/stylesheets/topbar-radiobuttons.css</file>
<file>data/icons/tomahawk-icon-16x16.png</file>
<file>data/icons/tomahawk-icon-32x32.png</file>
@@ -105,6 +94,9 @@
<file>data/icons/tomahawk-icon-128x128.png</file>
<file>data/icons/tomahawk-icon-256x256.png</file>
<file>data/icons/tomahawk-icon-512x512.png</file>
<file>data/icons/audio-x-generic-22x22.png</file>
<file>data/icons/audio-x-generic-32x32.png</file>
<file>data/icons/audio-x-generic-16x16.png</file>
<file>data/www/auth.html</file>
<file>data/www/auth.na.html</file>
<file>data/www/tomahawk_banner_small.png</file>
@@ -112,23 +104,7 @@
<file>data/sql/dbmigrate-23_to_24.sql</file>
<file>data/sql/dbmigrate-24_to_25.sql</file>
<file>data/sql/dbmigrate-25_to_26.sql</file>
<file>data/sql/dbmigrate-26_to_27.sql</file>
<file>data/js/tomahawk.js</file>
<file>data/images/avatar_frame.png</file>
<file>data/images/drop-all-songs.png</file>
<file>data/images/drop-local-songs.png</file>
<file>data/images/drop-top-songs.png</file>
<file>data/images/drop-song.png</file>
<file>data/images/drop-album.png</file>
<file>data/images/spotify-logo.png</file>
<file>data/images/itunes.png</file>
<file>data/images/uploading.png</file>
<file>data/images/downloading.png</file>
<file>data/images/headphones.png</file>
<file>data/images/headphones-off.png</file>
<file>data/images/headphones-sidebar.png</file>
<file>data/images/headphones-bigger.png</file>
<file>data/images/no-album-no-case.png</file>
<file>data/images/rdio.png</file>
</qresource>
</RCC>

View File

@@ -1,3 +1,8 @@
SET( OS_SPECIFIC_LINK_LIBRARIES
${OS_SPECIFIC_LINK_LIBRARIES}
tomahawklib
)
FILE( GLOB _icons "${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon-*.png" )
FOREACH( _file ${_icons} )
STRING( REPLACE "${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon-" "" _res ${_file} )
@@ -5,6 +10,6 @@ FOREACH( _file ${_icons} )
INSTALL( FILES ${_file} RENAME tomahawk.png DESTINATION share/icons/hicolor/${_res}/apps )
ENDFOREACH( _file )
INSTALL( FILES ${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon.svg RENAME tomahawk.svg DESTINATION share/icons/hicolor/scalable/apps )
INSTALL( FILES ${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon.svg RENAME tomahawk.svg DESTINATION share/icons/hicolor/scalable )
INSTALL( FILES ${CMAKE_SOURCE_DIR}/admin/unix/tomahawk.desktop DESTINATION share/applications )

View File

@@ -1,11 +1,10 @@
SET( TOMAHAWK_LIBRARIES tomahawklib )
SET( TOMAHAWK_LIBRARIES tomahawklib )
SET( OS_SPECIFIC_LINK_LIBRARIES
${OS_SPECIFIC_LINK_LIBRARIES}
${COREAUDIO_LIBRARY}
${COREFOUNDATION_LIBRARY}
crypto
SPMediaKeyTap
/System/Library/Frameworks/AppKit.framework
@@ -27,15 +26,12 @@ if (APPLE)
# Uses Darwin kernel version.
# 9.8.0 -> 10.5/Leopard
# 10.4.0 -> 10.6/Snow Leopard
# 11.x.x -> Lion
string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${CMAKE_HOST_SYSTEM_VERSION})
if (DARWIN_VERSION GREATER 10)
SET(LION 1)
elseif (DARWIN_VERSION GREATER 9)
if (DARWIN_VERSION GREATER 9)
SET(SNOW_LEOPARD 1)
elseif (DARWIN_VERSION GREATER 8)
SET(LEOPARD 1)
endif (DARWIN_VERSION GREATER 10)
endif (DARWIN_VERSION GREATER 9)
# Use two different sparkle update tracks for debug and release
# We have to change the URL in the Info.plist file :-/

View File

@@ -37,6 +37,9 @@ ENDIF()
SET( tomahawkSources ${tomahawkSources}
web/api_v1.cpp
resolvers/scriptresolver.cpp
resolvers/qtscriptresolver.cpp
musicscanner.cpp
shortcuthandler.cpp
scanmanager.cpp
@@ -54,17 +57,14 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
sourcetree/sourcesmodel.cpp
sourcetree/sourcesproxymodel.cpp
sourcetree/sourcetreeview.cpp
sourcetree/sourcedelegate.cpp
sourcetree/animationhelper.cpp
sourcetree/items/sourcetreeitem.cpp
sourcetree/items/collectionitem.cpp
sourcetree/items/playlistitems.cpp
sourcetree/items/categoryitems.cpp
sourcetree/items/genericpageitems.cpp
sourcetree/items/temporarypageitem.cpp
breakpad/BreakPad.cpp
transferview.cpp
PipelineStatusView.cpp
tomahawktrayicon.cpp
audiocontrols.cpp
settingsdialog.cpp
@@ -75,7 +75,6 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
settingslistdelegate.cpp
resolversmodel.cpp
tomahawkwindow.cpp
LoadXSPFDialog.cpp
)
SET( tomahawkHeaders ${tomahawkHeaders}
@@ -83,6 +82,9 @@ SET( tomahawkHeaders ${tomahawkHeaders}
web/api_v1.h
resolvers/scriptresolver.h
resolvers/qtscriptresolver.h
musicscanner.h
scanmanager.h
shortcuthandler.h
@@ -94,26 +96,19 @@ IF(LIBLASTFM_FOUND)
)
ENDIF(LIBLASTFM_FOUND)
IF(LIBATTICA_FOUND)
SET( tomahawkSources ${tomahawkSources} GetNewStuffDialog.cpp GetNewStuffDelegate.cpp GetNewStuffModel.cpp )
SET( tomahawkHeaders ${tomahawkHeaders} 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/collectionitem.h
sourcetree/items/playlistitems.h
sourcetree/items/categoryitems.h
sourcetree/items/genericpageitems.h
sourcetree/items/temporarypageitem.h
transferview.h
PipelineStatusView.h
tomahawktrayicon.h
audiocontrols.h
settingsdialog.h
@@ -125,7 +120,6 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
resolversmodel.h
delegateconfigwrapper.h
tomahawkwindow.h
LoadXSPFDialog.h
)
SET( tomahawkUI ${tomahawkUI}
@@ -133,11 +127,9 @@ SET( tomahawkUI ${tomahawkUI}
diagnosticsdialog.ui
stackedsettingsdialog.ui
proxydialog.ui
searchbox.ui
audiocontrols.ui
GetNewStuffDialog.ui
LoadXSPFDialog.ui
)
INCLUDE_DIRECTORIES(
@@ -158,7 +150,6 @@ INCLUDE_DIRECTORIES(
${THIRDPARTY_DIR}/qxt/qxtweb-standalone/qxtweb
${THIRDPARTY_DIR}/qtweetlib/qtweetlib/src
${THIRDPARTY_DIR}/qtweetlib/tomahawk-custom
${THIRDPARTY_DIR}/breakpad
${TAGLIB_INCLUDES}
${PHONON_INCLUDES}
@@ -179,12 +170,13 @@ ENDIF( UNIX )
IF( APPLE )
INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/thirdparty/SPMediaKeyTap )
SET( tomahawkHeaders ${tomahawkHeaders} mac/tomahawkapp_mac.h mac/macshortcuthandler.h )
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)
@@ -194,10 +186,6 @@ IF(GLOOX_FOUND)
ENDIF(GLOOX_FOUND)
ADD_SUBDIRECTORY( sip )
IF(QCA2_FOUND)
INCLUDE_DIRECTORIES( ${QCA2_INCLUDE_DIR} )
ENDIF(QCA2_FOUND)
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} )
@@ -237,12 +225,8 @@ ENDIF(LIBLASTFM_FOUND)
IF(GLOOX_FOUND)
SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${GLOOX_LIBRARIES} )
ENDIF(GLOOX_FOUND)
IF(QCA2_FOUND)
SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} )
ENDIF(QCA2_FOUND)
TARGET_LINK_LIBRARIES( tomahawk
tomahawk_breakpad
${LINK_LIBRARIES}
${TOMAHAWK_LIBRARIES}
${PHONON_LIBS}
@@ -255,6 +239,7 @@ TARGET_LINK_LIBRARIES( tomahawk
${TAGLIB_LIBRARIES}
)
IF( APPLE )
IF(HAVE_SPARKLE)
MESSAGE("Sparkle Found, installing framekwork in bundle")

View File

@@ -4,7 +4,7 @@ ADD_DEFINITIONS( -g )
ADD_DEFINITIONS( -fno-operator-names )
ADD_DEFINITIONS( -fPIC )
SET( QXTWEB_LIBRARIES qxtweb-standalone )
SET( QXTWEB_LIBRARIES qxtweb-standalone )
IF( APPLE )
INCLUDE( "CMakeLists.osx.txt" )

View File

@@ -3,7 +3,6 @@ SET( CMAKE_BUILD_TYPE "Release" )
ADD_DEFINITIONS( /DNOMINMAX )
ADD_DEFINITIONS( /DWIN32_LEAN_AND_MEAN )
ADD_DEFINITIONS( -static-libgcc )
ADD_DEFINITIONS( -DUNICODE )
SET( QXTWEB_LIBRARIES qxtweb-standalone )

View File

@@ -1,323 +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 "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;
}

View File

@@ -1,50 +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 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

View File

@@ -1,53 +0,0 @@
/* === 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 );
#ifdef Q_WS_MAC
setMinimumSize( 510, 350 );
setMaximumSize( 510, 350 );
setSizeGripEnabled( false );
ui->listView->setAttribute( Qt::WA_MacShowFocusRect, false );
#endif
}
GetNewStuffDialog::~GetNewStuffDialog()
{
delete ui;
}

View File

@@ -1,41 +0,0 @@
/* === 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

View File

@@ -1,67 +0,0 @@
<?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>

View File

@@ -1,156 +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 "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;
}

View File

@@ -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 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

View File

@@ -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/>.
*/
#include "LoadXSPFDialog.h"
#include "ui_LoadXSPFDialog.h"
#include <QFileDialog>
LoadXSPFDialog::LoadXSPFDialog( QWidget* parent, Qt::WindowFlags f )
: QDialog( parent, f )
, m_ui( new Ui_LoadXSPF )
{
m_ui->setupUi( this );
#ifdef Q_WS_MAC
m_ui->horizontalLayout->setContentsMargins( 0, 0, 0, 0 );
m_ui->horizontalLayout->setSpacing( 5 );
m_ui->verticalLayout->setContentsMargins( 0, 10, 0, 0 );
m_ui->verticalLayout->setSpacing( 0 );
#endif
connect( m_ui->buttonBox, SIGNAL( accepted() ), SLOT( accept() ) );
connect( m_ui->buttonBox, SIGNAL( rejected() ), SLOT( reject() ) );
connect( m_ui->navigateButton, SIGNAL( clicked( bool ) ), this, SLOT( getLocalFile() ) );
}
LoadXSPFDialog::~LoadXSPFDialog()
{
}
void
LoadXSPFDialog::getLocalFile()
{
QString url = QFileDialog::getOpenFileName( this, tr( "Load XSPF File" ), QDir::homePath(), ".xspf" );
m_ui->lineEdit->setText( url );
}
QString
LoadXSPFDialog::xspfUrl() const
{
return m_ui->lineEdit->text();
}
bool
LoadXSPFDialog::autoUpdate() const
{
return m_ui->autoUpdate->isChecked();
}

View File

@@ -1,43 +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 LOADXSPFDIALOG_H
#define LOADXSPFDIALOG_H
#include <QDialog>
class Ui_LoadXSPF;
class LoadXSPFDialog : public QDialog
{
Q_OBJECT
public:
explicit LoadXSPFDialog( QWidget* parent = 0, Qt::WindowFlags f = 0 );
virtual ~LoadXSPFDialog();
QString xspfUrl() const;
bool autoUpdate() const;
public slots:
void getLocalFile();
private:
Ui_LoadXSPF* m_ui;
};
#endif // LOADXSPFDIALOG_H

View File

@@ -1,102 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LoadXSPF</class>
<widget class="QDialog" name="LoadXSPF">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>444</width>
<height>121</height>
</rect>
</property>
<property name="windowTitle">
<string>Load XSPF</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Playlist Url</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="placeholderText">
<string>Enter URL...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="navigateButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="autoUpdate">
<property name="text">
<string>Automatically update</string>
</property>
</widget>
</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>LoadXSPF</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>LoadXSPF</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>

View File

@@ -1,7 +1,6 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@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
@@ -17,7 +16,7 @@
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "JobStatusView.h"
#include "PipelineStatusView.h"
#include <QHeaderView>
#include <QVBoxLayout>
@@ -29,7 +28,7 @@
using namespace Tomahawk;
JobStatusView::JobStatusView( AnimatedSplitter* parent )
PipelineStatusView::PipelineStatusView( AnimatedSplitter* parent )
: AnimatedWidget( parent )
, m_parent( parent )
{
@@ -77,7 +76,7 @@ JobStatusView::JobStatusView( AnimatedSplitter* parent )
void
JobStatusView::onPipelineUpdate( const query_ptr& query )
PipelineStatusView::onPipelineUpdate( const query_ptr& query )
{
QTreeWidgetItem* ti = m_tree->invisibleRootItem()->child( 0 );
@@ -101,7 +100,7 @@ JobStatusView::onPipelineUpdate( const query_ptr& query )
QSize
JobStatusView::sizeHint() const
PipelineStatusView::sizeHint() const
{
unsigned int y = 0;
y += m_tree->header()->height();

View File

@@ -1,7 +1,6 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@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
@@ -17,24 +16,23 @@
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef JOBSTATUSVIEW_H
#define JOBSTATUSVIEW_H
#ifndef PIPELINESTATUSVIEW_H
#define PIPELINESTATUSVIEW_H
#include <QTreeWidget>
#include "typedefs.h"
#include "widgets/animatedsplitter.h"
#include "query.h"
#include "utils/animatedsplitter.h"
class StreamConnection;
class JobStatusView : public AnimatedWidget
class PipelineStatusView : public AnimatedWidget
{
Q_OBJECT
public:
explicit JobStatusView( AnimatedSplitter* parent );
virtual ~JobStatusView()
explicit PipelineStatusView( AnimatedSplitter* parent );
virtual ~PipelineStatusView()
{
}
@@ -44,8 +42,8 @@ private slots:
void onPipelineUpdate( const Tomahawk::query_ptr& query = Tomahawk::query_ptr() );
private:
QTreeView* m_tree;
QTreeWidget* m_tree;
AnimatedSplitter* m_parent;
};
#endif // JOBSTATUSVIEW_H
#endif // TRANSFERVIEW_H

View File

@@ -24,16 +24,18 @@
#include <QMouseEvent>
#include "audio/audioengine.h"
#include "viewmanager.h"
#include "playlist/playlistview.h"
#include "database/database.h"
#include "database/databasecommand_socialaction.h"
#include "widgets/imagebutton.h"
#include "album.h"
#include "utils/imagebutton.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#include "album.h"
#include <globalactionmanager.h>
#include "dropjob.h"
#include "globalactionmanager.h"
#include "viewmanager.h"
using namespace Tomahawk;
@@ -93,11 +95,6 @@ AudioControls::AudioControls( QWidget* parent )
ui->volumeSlider->setRange( 0, 100 );
ui->volumeSlider->setValue( AudioEngine::instance()->volume() );
m_sliderTimeLine.setCurveShape( QTimeLine::LinearCurve );
ui->seekSlider->setTimeLine( &m_sliderTimeLine );
connect( &m_sliderTimeLine, SIGNAL( frameChanged( int ) ), ui->seekSlider, SLOT( setValue( int ) ) );
connect( ui->seekSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( seek( int ) ) );
connect( ui->volumeSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( setVolume( int ) ) );
connect( ui->prevButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( previous() ) );
@@ -124,11 +121,10 @@ AudioControls::AudioControls( QWidget* parent )
connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( onPlaybackPaused() ) );
connect( AudioEngine::instance(), SIGNAL( resumed() ), SLOT( onPlaybackResumed() ) );
connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ) );
connect( AudioEngine::instance(), SIGNAL( seeked( qint64 ) ), SLOT( onPlaybackSeeked( qint64 ) ) );
connect( AudioEngine::instance(), SIGNAL( timerMilliSeconds( qint64 ) ), SLOT( onPlaybackTimer( qint64 ) ) );
connect( AudioEngine::instance(), SIGNAL( volumeChanged( int ) ), SLOT( onVolumeChanged( int ) ) );
m_defaultCover = QPixmap( RESPATH "images/no-album-no-case.png" )
m_defaultCover = QPixmap( RESPATH "images/no-album-art-placeholder.png" )
.scaled( ui->coverImage->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
connect( Tomahawk::InfoSystem::InfoSystem::instance(),
@@ -185,36 +181,16 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
{
tDebug( LOGEXTRA ) << Q_FUNC_INFO;
if ( result.isNull() )
return;
onPlaybackLoading( result );
if ( m_currentTrack.isNull() || ( !m_currentTrack.isNull() && m_currentTrack.data()->id() != result.data()->id() ) )
onPlaybackLoading( result );
qint64 duration = AudioEngine::instance()->currentTrackTotalTime();
if ( duration == -1 )
duration = result.data()->duration() * 1000;
ui->seekSlider->setRange( 0, duration );
ui->seekSlider->setValue( 0 );
m_sliderTimeLine.stop();
m_sliderTimeLine.setDuration( duration );
m_sliderTimeLine.setFrameRange( 0, duration );
m_sliderTimeLine.setCurrentTime( 0 );
m_seekMsecs = -1;
ui->seekSlider->setVisible( true );
Tomahawk::InfoSystem::InfoStringHash trackInfo;
Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
trackInfo["artist"] = result->artist()->name();
trackInfo["album"] = result->album()->name();
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = s_acInfoIdentifier;
requestData.type = Tomahawk::InfoSystem::InfoAlbumCoverArt;
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo );
requestData.customData = QVariantMap();
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData );
@@ -276,7 +252,11 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result )
ui->coverImage->setPixmap( m_defaultCover );
ui->timeLabel->setText( TomahawkUtils::timeToString( 0 ) );
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( result.data()->duration() ) );
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( result->duration() ) );
ui->seekSlider->setRange( 0, m_currentTrack->duration() * 1000 );
ui->seekSlider->setValue( 0 );
ui->seekSlider->setVisible( true );
ui->stackedLayout->setCurrentWidget( ui->pauseButton );
@@ -313,35 +293,20 @@ AudioControls::socialActionsLoaded()
void
AudioControls::onPlaybackPaused()
{
tDebug( LOGEXTRA ) << Q_FUNC_INFO;
ui->stackedLayout->setCurrentWidget( ui->playPauseButton );
m_sliderTimeLine.setPaused( true );
}
void
AudioControls::onPlaybackResumed()
{
tDebug( LOGEXTRA ) << Q_FUNC_INFO;
ui->stackedLayout->setCurrentWidget( ui->pauseButton );
ui->loveButton->setVisible( true );
m_sliderTimeLine.resume();
}
void
AudioControls::onPlaybackSeeked( qint64 msec )
{
tDebug( LOGEXTRA ) << Q_FUNC_INFO << " setting current timer to " << msec;
m_sliderTimeLine.setPaused( true );
m_sliderTimeLine.setCurrentTime( msec );
m_seekMsecs = msec;
}
void
AudioControls::onPlaybackStopped()
{
tDebug( LOGEXTRA ) << Q_FUNC_INFO;
m_currentTrack.clear();
ui->artistTrackLabel->setText( "" );
@@ -351,8 +316,6 @@ AudioControls::onPlaybackStopped()
ui->timeLeftLabel->setText( "" );
ui->coverImage->setPixmap( QPixmap() );
ui->seekSlider->setVisible( false );
m_sliderTimeLine.stop();
m_sliderTimeLine.setCurrentTime( 0 );
ui->stackedLayout->setCurrentWidget( ui->playPauseButton );
ui->loveButton->setEnabled( false );
@@ -363,7 +326,6 @@ AudioControls::onPlaybackStopped()
void
AudioControls::onPlaybackTimer( qint64 msElapsed )
{
//tDebug( LOGEXTRA ) << Q_FUNC_INFO << " msElapsed = " << msElapsed << " and timer current time = " << m_sliderTimeLine.currentTime() << " and m_seekMsecs = " << m_seekMsecs;
if ( m_currentTrack.isNull() )
return;
@@ -372,25 +334,7 @@ AudioControls::onPlaybackTimer( qint64 msElapsed )
const int seconds = msElapsed / 1000;
ui->timeLabel->setText( TomahawkUtils::timeToString( seconds ) );
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( m_currentTrack->duration() - seconds ) );
if ( m_sliderTimeLine.currentTime() > msElapsed || m_seekMsecs != -1 )
{
m_sliderTimeLine.setPaused( true );
m_sliderTimeLine.setCurrentTime( msElapsed );
m_seekMsecs = -1;
if ( AudioEngine::instance()->state() != AudioEngine::Paused )
m_sliderTimeLine.resume();
}
else if ( m_sliderTimeLine.duration() > msElapsed && m_sliderTimeLine.state() == QTimeLine::NotRunning )
{
ui->seekSlider->setEnabled( AudioEngine::instance()->canSeek() );
m_sliderTimeLine.resume();
}
else if ( m_sliderTimeLine.state() == QTimeLine::Paused && AudioEngine::instance()->state() != AudioEngine::Paused )
{
ui->seekSlider->setEnabled( AudioEngine::instance()->canSeek() );
m_sliderTimeLine.resume();
}
ui->seekSlider->setValue( msElapsed );
ui->seekSlider->blockSignals( false );
}
@@ -538,7 +482,6 @@ AudioControls::dropEvent( QDropEvent* e )
if ( DropJob::acceptsMimeData( e->mimeData() ) )
{
DropJob *dj = new DropJob();
dj->setDropAction( DropJob::Append );
connect( dj, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( droppedTracks( QList<Tomahawk::query_ptr> ) ) );
dj->tracksFromMimeData( e->mimeData() );
@@ -552,8 +495,8 @@ AudioControls::droppedTracks( QList< query_ptr > tracks )
{
if ( !tracks.isEmpty() )
{
// queue and play the first no matter what
GlobalActionManager::instance()->handlePlayTrack( tracks.first() );
// queue and play the first if nothign is playing
GlobalActionManager::instance()->handleOpenTrack( tracks.first() );
// just queue the rest
for ( int i = 1; i < tracks.size(); i++ )
@@ -567,7 +510,7 @@ AudioControls::droppedTracks( QList< query_ptr > tracks )
void
AudioControls::onLoveButtonClicked( bool checked )
{
Tomahawk::InfoSystem::InfoStringHash trackInfo;
Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
trackInfo["title"] = m_currentTrack->track();
trackInfo["artist"] = m_currentTrack->artist()->name();
trackInfo["album"] = m_currentTrack->album()->name();
@@ -576,7 +519,7 @@ AudioControls::onLoveButtonClicked( bool checked )
{
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
s_acInfoIdentifier, Tomahawk::InfoSystem::InfoLove,
QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ) );
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) );
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction( m_currentTrack, QString( "Love" ), QString( "true") );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
@@ -586,7 +529,7 @@ AudioControls::onLoveButtonClicked( bool checked )
{
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
s_acInfoIdentifier, Tomahawk::InfoSystem::InfoUnLove,
QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ) );
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) );
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction( m_currentTrack, QString( "Love" ), QString( "false" ) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );

View File

@@ -20,17 +20,14 @@
#define AUDIOCONTROLS_H
#include <QWidget>
#include <QTimeLine>
#include "result.h"
#include "playlistinterface.h"
#include "infosystem/infosystem.h"
#include "query.h"
class QDropEvent;
class QDragEnterEvent;
class QDragMoveEvent;
namespace Ui
{
class AudioControls;
@@ -63,7 +60,6 @@ private slots:
void onPlaybackLoading( const Tomahawk::result_ptr& result );
void onPlaybackPaused();
void onPlaybackResumed();
void onPlaybackSeeked( qint64 msec );
void onPlaybackStopped();
void onPlaybackTimer( qint64 msElapsed );
@@ -83,7 +79,6 @@ private slots:
void droppedTracks( QList<Tomahawk::query_ptr> );
void socialActionsLoaded();
private:
Ui::AudioControls *ui;
@@ -92,9 +87,6 @@ private:
Tomahawk::result_ptr m_currentTrack;
Tomahawk::PlaylistInterface::RepeatMode m_repeatMode;
bool m_shuffled;
QTimeLine m_sliderTimeLine;
qint64 m_seekMsecs;
};
#endif // AUDIOCONTROLS_H

View File

@@ -261,56 +261,21 @@
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="ownerLabel">
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
<widget class="ImageButton" name="loveButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="text">
<string>Owner</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTop</set>
</property>
<property name="margin">
<number>0</number>
<string>love</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="socialLayout">
<item>
<spacer name="socialSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="ImageButton" name="loveButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="text">
<string>love</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
@@ -319,13 +284,31 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
<height>13</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="ownerLabel">
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Owner</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="margin">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -554,12 +537,12 @@
<customwidget>
<class>ImageButton</class>
<extends>QPushButton</extends>
<header>widgets/imagebutton.h</header>
<header>utils/imagebutton.h</header>
</customwidget>
<customwidget>
<class>QueryLabel</class>
<extends>QLabel</extends>
<header>widgets/querylabel.h</header>
<header>utils/querylabel.h</header>
</customwidget>
</customwidgets>
<resources/>

View File

@@ -1,145 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, 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 "BreakPad.h"
#include <QCoreApplication>
#include <QString>
#include <string.h>
#define CRASH_REPORTER_BINARY "CrashReporter"
#ifndef WIN32
#include <unistd.h>
static bool
LaunchUploader( const char* dump_dir, const char* minidump_id, void* that, bool succeeded )
{
// DON'T USE THE HEAP!!!
// So that indeed means, no QStrings, no qDebug(), no QAnything, seriously!
if ( !succeeded )
return false;
const char* crashReporter = static_cast<BreakPad*>(that)->crashReporter();
pid_t pid = fork();
if ( pid == -1 ) // fork failed
return false;
if ( pid == 0 )
{
// we are the fork
execl( crashReporter,
crashReporter,
dump_dir,
minidump_id,
minidump_id,
(char*) 0 );
// execl replaces this process, so no more code will be executed
// unless it failed. If it failed, then we should return false.
printf( "Error: Can't launch CrashReporter!\n" );
return false;
}
// we called fork()
return true;
}
BreakPad::BreakPad( const QString& path )
#ifdef Q_OS_LINUX
: google_breakpad::ExceptionHandler( path.toStdString(), 0, LaunchUploader, this, true )
#else
: google_breakpad::ExceptionHandler( path.toStdString(), 0, LaunchUploader, this, true, 0 )
#endif
{
QString reporter = QString( "%1/%2" ).arg( qApp->applicationDirPath() ).arg( CRASH_REPORTER_BINARY );
char* creporter;
std::string sreporter = reporter.toStdString();
creporter = new char[ sreporter.size() + 1 ];
strcpy( creporter, sreporter.c_str() );
m_crashReporter = creporter;
}
#else
static bool
LaunchUploader( const wchar_t* dump_dir, const wchar_t* minidump_id, void* that, EXCEPTION_POINTERS *exinfo, MDRawAssertionInfo *assertion, bool succeeded )
{
if ( !succeeded )
return false;
// DON'T USE THE HEAP!!!
// So that indeed means, no QStrings, no qDebug(), no QAnything, seriously!
// broken in mingw, hardcode it for now
// const char* productName = static_cast<BreakPad*>(that)->productName();s
// convert productName to widechars, which sadly means the product name must be Latin1
wchar_t product_name[ 256 ] = L"tomahawk";;
// char* out = (char*)product_name;
// const char* in = productName - 1;
// do {
// *out++ = *++in; //latin1 chars fit in first byte of each wchar
// *out++ = '\0'; //every second byte is NULL
// }
// while (*in);
wchar_t command[MAX_PATH * 3 + 6];
wcscpy( command, CRASH_REPORTER_BINARY L" \"" );
wcscat( command, dump_dir );
wcscat( command, L"\" \"" );
wcscat( command, minidump_id );
wcscat( command, L"\" \"" );
wcscat( command, product_name );
wcscat( command, L"\"" );
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof( si ) );
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
ZeroMemory( &pi, sizeof(pi) );
if (CreateProcess( NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
TerminateProcess( GetCurrentProcess(), 1 );
}
return false;
}
BreakPad::BreakPad( const QString& path )
: google_breakpad::ExceptionHandler( path.toStdWString(), 0, LaunchUploader, this, true )
{
}
#endif // WIN32

View File

@@ -1,47 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, 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 <QString>
#ifdef __APPLE__
# include "client/mac/handler/exception_handler.h"
#elif defined WIN32
# include "client/windows/handler/exception_handler.h"
#elif defined __linux__
# include "client/linux/handler/exception_handler.h"
#endif
class BreakPad : public google_breakpad::ExceptionHandler
{
const char* m_productName; // yes! It MUST be const char[]
const char* m_crashReporter; // again, const char[]
public:
BreakPad( const QString &dump_write_dirpath );
~BreakPad()
{}
void setProductName( const char* s ) { m_productName = s; };
const char* productName() const { return m_productName; }
void setCrashReporter( const char* s ) { m_crashReporter = s; };
const char* crashReporter() const { return m_crashReporter; }
};
#undef char

View File

@@ -1,20 +0,0 @@
PROJECT( CrashReporter )
FIND_PACKAGE( Qt4 REQUIRED )
SET( QT_USE_QTNETWORK TRUE )
SET( crashreporter_SOURCES main.cpp CrashReporter.cpp )
SET( crashreporter_HEADERS CrashReporter.h )
SET( crashreporter_UI CrashReporter.ui )
SET( crashreporter_RC ../../../resources.qrc )
QT4_WRAP_CPP( crashreporter_HEADERS_MOC ${crashreporter_HEADERS} )
QT4_WRAP_UI( crashreporter_UI_HEADERS ${crashreporter_UI} )
QT4_ADD_RESOURCES( crashreporter_RC_RCC ${crashreporter_RC} )
INCLUDE( ${QT_USE_FILE} )
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/src ../../libtomahawk )
ADD_DEFINITIONS( ${QT_DEFINITIONS} )
ADD_EXECUTABLE( CrashReporter WIN32 ${crashreporter_SOURCES} ${crashreporter_HEADERS_MOC} ${crashreporter_UI_HEADERS} ${crashreporter_RC_RCC} )
TARGET_LINK_LIBRARIES( CrashReporter ${QT_LIBRARIES} tomahawklib )

View File

@@ -1,186 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, 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 "CrashReporter.h"
#include <QIcon>
#include <QDebug>
#include <QTimer>
#include <QDir>
#include <QDateTime>
#include <QHttp>
#include "utils/tomahawkutils.h"
#define LOGFILE TomahawkUtils::appLogDir().filePath( "Tomahawk.log" ).toLocal8Bit()
#define RESPATH ":/data/"
CrashReporter::CrashReporter( const QStringList& args )
{
setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
ui.setupUi( this );
ui.logoLabel->setPixmap( QPixmap( RESPATH "icons/tomahawk-icon-128x128.png" ).scaled( QSize( 55, 55 ), Qt::KeepAspectRatio, Qt::SmoothTransformation ) );
ui.progressBar->setRange( 0, 100 );
ui.progressBar->setValue( 0 );
ui.progressLabel->setPalette( Qt::gray );
#ifdef Q_WS_MAC
QFont f = ui.bottomLabel->font();
f.setPointSize( 10 );
ui.bottomLabel->setFont( f );
f.setPointSize( 11 );
ui.progressLabel->setFont( f );
ui.progressLabel->setIndent( 3 );
#else
ui.vboxLayout->setSpacing( 16 );
ui.progressBar->setTextVisible( false );
ui.progressLabel->setIndent( 1 );
ui.bottomLabel->setDisabled( true );
ui.bottomLabel->setIndent( 1 );
// adjust the spacer since we adjusted the spacing above
for ( int x = 0; x < ui.vboxLayout->count(); ++x )
{
if ( QSpacerItem* spacer = ui.vboxLayout->itemAt( x )->spacerItem() )
{
spacer->changeSize( 6, 2, QSizePolicy::Minimum, QSizePolicy::Fixed );
break;
}
}
#endif //Q_WS_MAC
m_http = new QHttp( "oops.tomahawk-player.org", 80, this );
connect( m_http, SIGNAL( done( bool ) ), SLOT( onDone() ), Qt::QueuedConnection );
connect( m_http, SIGNAL( dataSendProgress( int, int ) ), SLOT( onProgress( int, int ) ) );
m_dir = args.value( 1 );
m_minidump = m_dir + '/' + args.value( 2 ) + ".dmp";
m_product_name = args.value( 3 );
setFixedSize( sizeHint() );
QTimer::singleShot( 0, this, SLOT( send() ) );
}
static QByteArray
contents( const QString& path )
{
QFile f( path );
f.open( QFile::ReadOnly );
return f.readAll();
}
void
CrashReporter::send()
{
QByteArray body;
// socorro expects a 10 digit build id
QRegExp rx( "(\\d+\\.\\d+\\.\\d+).(\\d+)" );
rx.exactMatch( TomahawkUtils::appFriendlyVersion() );
QString const version = rx.cap( 1 );
QString const buildId = rx.cap( 2 ).leftJustified( 10, '0' );
// add parameters
typedef QPair<QByteArray, QByteArray> Pair;
QList<Pair> pairs;
pairs << Pair( "BuildID", buildId.toUtf8() )
<< Pair( "ProductName", m_product_name.toUtf8() )
<< Pair( "Version", TomahawkUtils::appFriendlyVersion().toLocal8Bit() )
<< Pair( "Vendor", "Tomahawk" )
<< Pair( "timestamp", QByteArray::number( QDateTime::currentDateTime().toTime_t() ) );
foreach ( Pair const pair, pairs )
{
body += "--thkboundary\r\n";
body += "Content-Disposition: form-data; name=\"" +
pair.first + "\"\r\n\r\n" +
pair.second + "\r\n";
}
// add minidump file
body += "--thkboundary\r\n";
body += "Content-Disposition: form-data; name=\"upload_file_minidump\"; filename=\""
+ QFileInfo( m_minidump ).fileName() + "\"\r\n";
body += "Content-Type: application/octet-stream\r\n";
body += "\r\n";
body += contents( m_minidump );
body += "\r\n";
// add logfile
body += "--thkboundary\r\n";
body += "Content-Disposition: form-data; name=\"upload_file_tomahawklog\"; filename=\"Tomahawk.log\"\r\n";
body += "Content-Type: application/x-gzip\r\n";
body += "\r\n";
body += qCompress( contents( LOGFILE ) );
body += "\r\n";
body += "--thkboundary--\r\n";
QHttpRequestHeader header( "POST", "/addreport.php" );
header.setContentType( "multipart/form-data; boundary=thkboundary" );
header.setValue( "HOST", "oops.tomahawk-player.org" );
m_http->request( header, body );
}
void
CrashReporter::onProgress( int done, int total )
{
if ( total )
{
QString const msg = tr( "Uploaded %L1 of %L2 KB." ).arg( done / 1024 ).arg( total / 1024 );
ui.progressBar->setMaximum( total );
ui.progressBar->setValue( done );
ui.progressLabel->setText( msg );
}
}
void
CrashReporter::onDone()
{
QByteArray data = m_http->readAll();
ui.progressBar->setValue( ui.progressBar->maximum() );
ui.button->setText( tr( "Close" ) );
QString const response = QString::fromUtf8( data );
if ( m_http->error() != QHttp::NoError || !response.startsWith( "CrashID=" ) )
{
onFail( m_http->error(), m_http->errorString() );
}
else
ui.progressLabel->setText( tr( "Sent! <b>Many thanks</b>." ) );
}
void
CrashReporter::onFail( int error, const QString& errorString )
{
ui.button->setText( tr( "Close" ) );
ui.progressLabel->setText( tr( "Failed to send crash info." ) );
qDebug() << "Error:" << error << errorString;
}

View File

@@ -1,52 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, 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 CRASHREPORTER_H
#define CRASHREPORTER_H
#include <QDialog>
#include <QFile>
#include "ui_CrashReporter.h"
class CrashReporter : public QDialog
{
Q_OBJECT
public:
CrashReporter( const QStringList& argv );
private:
Ui::CrashReporter ui;
QString m_minidump;
QString m_dir;
QString m_product_name;
class QHttp* m_http;
public slots:
void send();
private slots:
void onDone();
void onProgress( int done, int total );
void onFail( int error, const QString& errorString );
};
#endif // CRASHREPORTER_H

View File

@@ -1,223 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CrashReporter</class>
<widget class="QDialog" name="CrashReporter">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>438</width>
<height>196</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Tomahawk Crash Reporter</string>
</property>
<property name="modal">
<bool>false</bool>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>9</number>
</property>
<item>
<layout class="QHBoxLayout">
<property name="spacing">
<number>12</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="logoLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>55</width>
<height>55</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>55</width>
<height>55</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="topLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;p&gt;&lt;b&gt;Sorry!&lt;/b&gt;&amp;nbsp;Tomahawk crashed. Information about the crash is now being sent to Tomahawk HQ so that we can fix the bug.&lt;/p&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>6</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="progressLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout">
<property name="spacing">
<number>9</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>24</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="button">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Abort</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="bottomLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>You can disable sending crash reports in the configuration dialog.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>button</sender>
<signal>clicked()</signal>
<receiver>CrashReporter</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>424</x>
<y>154</y>
</hint>
<hint type="destinationlabel">
<x>247</x>
<y>195</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -1,56 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, 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 "CrashReporter.h"
#include <QTranslator>
#include <iostream>
const char* k_usage =
"Usage:\n"
" CrashReporter <logDir> <dumpFileName> <productName>\n";
int main( int argc, char* argv[] )
{
// used by some Qt stuff, eg QSettings
// leave first! As Settings object is created quickly
QCoreApplication::setApplicationName( "Tomahawk" );
QCoreApplication::setOrganizationName( "Tomahawk" );
QCoreApplication::setOrganizationDomain( "tomahawk-player.org" );
QApplication app( argc, argv );
QString langCode;
QTranslator translatorApp;
QTranslator translatorQt;
/* app.installTranslator( &translatorApp );
app.installTranslator( &translatorQt );*/
if ( app.arguments().size() != 4 )
{
std::cout << k_usage;
return 1;
}
CrashReporter reporter( app.arguments() );
reporter.show();
return app.exec();
}

View File

@@ -11,14 +11,11 @@
#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
#define CMAKE_SYSTEM "${CMAKE_SYSTEM}"
#cmakedefine LION
#cmakedefine SNOW_LEOPARD
#cmakedefine LEOPARD
#cmakedefine HAVE_SPARKLE
#cmakedefine LIBLASTFM_FOUND
#cmakedefine GLOOX_FOUND
#cmakedefine QCA2_FOUND
#cmakedefine LIBATTICA_FOUND
#endif // CONFIG_H_IN

View File

@@ -30,7 +30,7 @@ public:
DelegateConfigWrapper( QWidget* conf, const QString& title, QWidget* parent, Qt::WindowFlags flags = 0 ) : QDialog( parent, flags ), m_widget( conf )
{
m_widget->setWindowFlags( Qt::Sheet );
#ifdef Q_WS_MAC
#ifdef Q_OS_MAC
m_widget->setVisible( true );
#endif
@@ -47,7 +47,7 @@ public:
setLayout( v );
#ifdef Q_WS_MAC
#ifdef Q_OS_MAC
setSizeGripEnabled( false );
setMinimumSize( sizeHint() );
setMaximumSize( sizeHint() ); // to remove the resize grip on osx this is the only way
@@ -86,8 +86,7 @@ public slots:
m_widget->setVisible( false );
}
void updateSizeHint()
{
void updateSizeHint() {
hide();
setSizeGripEnabled( false );
setMinimumSize( sizeHint() );

View File

@@ -123,7 +123,6 @@ void DiagnosticsDialog::updateLogView()
Q_FOREACH( const QString &peerId, sip->peersOnline() )
{
/* enable this again, when we check the source has this peerId
bool connected = false;
Q_FOREACH( const Tomahawk::source_ptr &source, sources )
{
@@ -132,35 +131,33 @@ void DiagnosticsDialog::updateLogView()
connected = true;
break;
}
}*/
}
QString versionString = SipHandler::instance()->versionString( peerId );
SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId );
if( !sipInfo.isValid() )
log.append(
QString(" %1: %2 %3" /*"(%4)"*/ "\n")
QString(" %1: %2 (%3) %4\n")
.arg( peerId )
.arg( "sipinfo invalid" )
.arg( connected ? "connected" : "not connected")
.arg( versionString )
// .arg( connected ? "connected" : "not connected")
);
else if( sipInfo.isVisible() )
log.append(
QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n")
QString(" %1: %2:%3 (%4) %5\n")
.arg( peerId )
.arg( sipInfo.host().hostName() )
.arg( sipInfo.port() )
.arg( connected ? "connected" : "not connected")
.arg( versionString )
// .arg( connected ? "connected" : "not connected")
);
else
log.append(
QString(" %1: visible: false %2" /*" (%3)"*/ "\n")
QString(" %1: visible: false (%2) %3\n")
.arg( peerId )
.arg( connected ? "connected" : "not connected")
.arg( versionString )
// .arg( connected ? "connected" : "not connected")
);
}
log.append("\n");

View File

@@ -1,557 +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 "AtticaManager.h"
#include "utils/tomahawkutils.h"
#include "tomahawksettings.h"
#include "pipeline.h"
#include <attica/downloaditem.h>
#include <quazip.h>
#include <quazipfile.h>
#include <QNetworkReply>
#include <QTemporaryFile>
#include <QDir>
#include <QTimer>
#include "utils/logger.h"
using namespace Attica;
AtticaManager* AtticaManager::s_instance = 0;
AtticaManager::AtticaManager( QObject* parent )
: QObject( parent )
{
connect( &m_manager, SIGNAL( providerAdded( Attica::Provider ) ), this, SLOT( providerAdded( Attica::Provider ) ) );
// resolvers
m_manager.addProviderFile( QUrl( "http://bakery.tomahawk-player.org:10480/resolvers/providers.xml" ) );
}
AtticaManager::~AtticaManager()
{
savePixmapsToCache();
}
void
AtticaManager::loadPixmapsFromCache()
{
QDir cacheDir = TomahawkUtils::appDataDir();
if ( !cacheDir.cd( "atticacache" ) ) // doesn't exist, no cache
return;
qDebug() << "Loading resolvers from cache dir:" << cacheDir.absolutePath();
qDebug() << "Currently we know about these resolvers:" << m_resolverStates.keys();
foreach ( const QString& file, cacheDir.entryList( QStringList() << "*.png", QDir::Files | QDir::NoSymLinks ) )
{
// load all the pixmaps
QFileInfo info( file );
if ( !m_resolverStates.contains( info.baseName() ) )
{
tLog() << "Found resolver icon cached for resolver we no longer see in synchrotron repo:" << info.baseName();
continue;
}
QPixmap* icon = new QPixmap( cacheDir.absoluteFilePath( file ) );
m_resolverStates[ info.baseName() ].pixmap = icon;
}
}
void
AtticaManager::savePixmapsToCache()
{
QDir cacheDir = TomahawkUtils::appDataDir();
if ( !cacheDir.cd( "atticacache" ) ) // doesn't exist, create
{
cacheDir.mkdir( "atticacache" );
cacheDir.cd( "atticache" );
}
foreach( const QString& id, m_resolverStates.keys() )
{
if ( !m_resolverStates[ id ].pixmap )
continue;
const QString filename = cacheDir.absoluteFilePath( QString( "%1.png" ).arg( id ) );
if ( !m_resolverStates[ id ].pixmap->save( filename ) )
{
tLog() << "Failed to open cache file for writing:" << filename;
continue;
}
}
}
QPixmap
AtticaManager::iconForResolver( const Content& resolver )
{
if ( !m_resolverStates[ resolver.id() ].pixmap )
return QPixmap();
return *m_resolverStates.value( resolver.id() ).pixmap;
}
Content::List
AtticaManager::resolvers() const
{
return m_resolvers;
}
AtticaManager::ResolverState
AtticaManager::resolverState ( const Content& resolver ) const
{
if ( !m_resolverStates.contains( resolver.id() ) )
{
return AtticaManager::Uninstalled;
}
return m_resolverStates[ resolver.id() ].state;
}
bool
AtticaManager::resolversLoaded() const
{
return !m_resolvers.isEmpty();
}
QString
AtticaManager::pathFromId( const QString& resolverId ) const
{
if ( !m_resolverStates.contains( resolverId ) )
return QString();
return m_resolverStates.value( resolverId ).scriptPath;
}
void
AtticaManager::uploadRating( const Content& c )
{
m_resolverStates[ c.id() ].userRating = c.rating();
for ( int i = 0; i < m_resolvers.count(); i++ )
{
if ( m_resolvers[ i ].id() == c.id() )
{
Attica::Content atticaContent = m_resolvers[ i ];
atticaContent.setRating( c.rating() );
m_resolvers[ i ] = atticaContent;
break;
}
}
TomahawkSettings::instance()->setAtticaResolverStates( m_resolverStates );
PostJob* job = m_resolverProvider.voteForContent( c.id(), (uint)c.rating() );
connect( job, SIGNAL( finished( Attica::BaseJob* ) ), job, SLOT( deleteLater() ) );
job->start();
emit resolverStateChanged( c.id() );
}
bool
AtticaManager::userHasRated( const Content& c ) const
{
return m_resolverStates[ c.id() ].userRating != -1;
}
void
AtticaManager::providerAdded( const Provider& provider )
{
if ( provider.name() == "Tomahawk Resolvers" )
{
m_resolverProvider = provider;
ListJob< Content >* job = m_resolverProvider.searchContents( Category::List(), QString(), Provider::Downloads, 0, 30 );
connect( job, SIGNAL( finished( Attica::BaseJob* ) ), this, SLOT( resolversList( Attica::BaseJob* ) ) );
job->start();
}
}
void
AtticaManager::resolversList( BaseJob* j )
{
ListJob< Content >* job = static_cast< ListJob< Content >* >( j );
m_resolvers = job->itemList();
m_resolverStates = TomahawkSettings::instance()->atticaResolverStates();
// load icon cache from disk, and fetch any we are missing
loadPixmapsFromCache();
foreach ( Content resolver, m_resolvers )
{
if ( !m_resolverStates.contains( resolver.id() ) )
m_resolverStates.insert( resolver.id(), Resolver() );
if ( !m_resolverStates.value( resolver.id() ).pixmap && !resolver.icons().isEmpty() && !resolver.icons().first().url().isEmpty() )
{
QNetworkReply* fetch = TomahawkUtils::nam()->get( QNetworkRequest( resolver.icons().first().url() ) );
fetch->setProperty( "resolverId", resolver.id() );
connect( fetch, SIGNAL( finished() ), this, SLOT( resolverIconFetched() ) );
}
}
syncServerData();
}
void
AtticaManager::resolverIconFetched()
{
QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
Q_ASSERT( reply );
const QString resolverId = reply->property( "resolverId" ).toString();
if ( !reply->error() == QNetworkReply::NoError )
{
tLog() << "Failed to fetch resolver icon image:" << reply->errorString();
return;
}
QByteArray data = reply->readAll();
QPixmap* icon = new QPixmap;
icon->loadFromData( data );
m_resolverStates[ resolverId ].pixmap = icon;
}
void
AtticaManager::syncServerData()
{
// look for any newer. m_resolvers has list from server, and m_resolverStates will contain any locally installed ones
// also update ratings
foreach ( const QString& id, m_resolverStates.keys() )
{
Resolver r = m_resolverStates[ id ];
for ( int i = 0; i < m_resolvers.size(); i++ )
{
Attica::Content upstream = m_resolvers[ i ];
// same resolver
if ( id != upstream.id() )
continue;
// Update our rating with the server's idea of rating if we haven't rated it
if ( m_resolverStates[ id ].userRating != -1 )
{
upstream.setRating( m_resolverStates[ id ].userRating );
m_resolvers[ i ] = upstream;
}
// DO we need to upgrade?
if ( ( r.state == Installed || r.state == NeedsUpgrade ) &&
!upstream.version().isEmpty() )
{
if ( newerVersion( r.version, upstream.version() ) )
{
m_resolverStates[ id ].state = NeedsUpgrade;
}
}
}
}
}
bool
AtticaManager::newerVersion( const QString& older, const QString& newer ) const
{
// Dumb version comparison. Expects two strings, X.Y and Z.V. Returns true if Z > v || Z == V && V > Y
// DOES NOT support X.Y.Z version strings
if ( older.isEmpty() || newer.isEmpty() )
return false;
QPair<int, int> oldVer, newVer;
QStringList parts = older.split( "." );
if ( parts.size() == 1 )
{
oldVer.first = parts[ 0 ].toInt();
oldVer.second = 0;
}
else if ( parts.size() == 2 )
{
oldVer.first = parts[ 0 ].toInt();
oldVer.second = parts[ 1 ].toInt();;
}
else
return false;
parts = newer.split( "." );
if ( parts.size() == 1 )
{
newVer.first = parts[ 0 ].toInt();
newVer.second = 0;
}
else if ( parts.size() == 2 )
{
newVer.first = parts[ 0 ].toInt();
newVer.second = parts[ 1 ].toInt();;
}
else
return false;
// Do the comparison
if ( newVer.first > oldVer.first )
return true;
if ( newVer.first == oldVer.first &&
newVer.second > oldVer.second )
return true;
return false;
}
void
AtticaManager::installResolver( const Content& resolver )
{
Q_ASSERT( !resolver.id().isNull() );
if ( m_resolverStates[ resolver.id() ].state != Upgrading )
m_resolverStates[ resolver.id() ].state = Installing;
m_resolverStates[ resolver.id() ].scriptPath = resolver.attribute( "mainscript" );
m_resolverStates[ resolver.id() ].version = resolver.version();
emit resolverStateChanged( resolver.id() );
ItemJob< DownloadItem >* job = m_resolverProvider.downloadLink( resolver.id() );
connect( job, SIGNAL( finished( Attica::BaseJob* ) ), this, SLOT( resolverDownloadFinished( Attica::BaseJob* ) ) );
job->setProperty( "resolverId", resolver.id() );
job->start();
}
void
AtticaManager::upgradeResolver( const Content& resolver )
{
Q_ASSERT( m_resolverStates.contains( resolver.id() ) );
Q_ASSERT( m_resolverStates[ resolver.id() ].state == NeedsUpgrade );
if ( !m_resolverStates.contains( resolver.id() ) || m_resolverStates[ resolver.id() ].state != NeedsUpgrade )
return;
m_resolverStates[ resolver.id() ].state = Upgrading;
emit resolverStateChanged( resolver.id() );
uninstallResolver( resolver );
installResolver( resolver );
}
void
AtticaManager::resolverDownloadFinished ( BaseJob* j )
{
ItemJob< DownloadItem >* job = static_cast< ItemJob< DownloadItem >* >( j );
if ( job->metadata().error() == Attica::Metadata::NoError )
{
DownloadItem item = job->result();
QUrl url = item.url();
// download the resolver itself :)
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
connect( reply, SIGNAL( finished() ), this, SLOT( payloadFetched() ) );
reply->setProperty( "resolverId", job->property( "resolverId" ) );
}
else
{
tLog() << "Failed to do resolver download job!" << job->metadata().error();
}
}
void
AtticaManager::payloadFetched()
{
QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() );
Q_ASSERT( reply );
// we got a zip file, save it to a temporary file, then unzip it to our destination data dir
if ( reply->error() == QNetworkReply::NoError )
{
QTemporaryFile f( QDir::tempPath() + QDir::separator() + "tomahawkattica_XXXXXX.zip" );
if ( !f.open() )
{
tLog() << "Failed to write zip file to temp file:" << f.fileName();
return;
}
f.write( reply->readAll() );
f.close();
QString resolverId = reply->property( "resolverId" ).toString();
QDir dir( extractPayload( f.fileName(), resolverId ) );
QString resolverPath = dir.absoluteFilePath( m_resolverStates[ resolverId ].scriptPath );
if ( !resolverPath.isEmpty() )
{
// update with absolute, not relative, path
m_resolverStates[ resolverId ].scriptPath = resolverPath;
// Do the install / add to tomahawk
Tomahawk::Pipeline::instance()->addScriptResolver( resolverPath, true );
m_resolverStates[ resolverId ].state = Installed;
TomahawkSettings::instance()->setAtticaResolverStates( m_resolverStates );
emit resolverInstalled( resolverId );
emit resolverStateChanged( resolverId );
}
}
else
{
tLog() << "Failed to download attica payload...:" << reply->errorString();
}
}
QString
AtticaManager::extractPayload( const QString& filename, const QString& resolverId ) const
{
// uses QuaZip to extract the temporary zip file to the user's tomahawk data/resolvers directory
QuaZip zipFile( filename );
if ( !zipFile.open( QuaZip::mdUnzip ) )
{
tLog() << "Failed to QuaZip open:" << zipFile.getZipError();
return QString();
}
if ( !zipFile.goToFirstFile() )
{
tLog() << "Failed to go to first file in zip archive: " << zipFile.getZipError();
return QString();
}
QDir resolverDir = TomahawkUtils::appDataDir();
if ( !resolverDir.mkpath( QString( "atticaresolvers/%1" ).arg( resolverId ) ) )
{
tLog() << "Failed to mkdir resolver save dir: " << TomahawkUtils::appDataDir().absoluteFilePath( QString( "atticaresolvers/%1" ).arg( resolverId ) );
return QString();
}
resolverDir.cd( QString( "atticaresolvers/%1" ).arg( resolverId ) );
tDebug() << "Installing resolver to:" << resolverDir.absolutePath();
QuaZipFile fileInZip( &zipFile );
do
{
QuaZipFileInfo info;
zipFile.getCurrentFileInfo( &info );
if ( !fileInZip.open( QIODevice::ReadOnly ) )
{
tLog() << "Failed to open file inside zip archive:" << info.name << zipFile.getZipName() << "with error:" << zipFile.getZipError();
continue;
}
QFile out( resolverDir.absoluteFilePath( fileInZip.getActualFileName() ) );
QStringList parts = fileInZip.getActualFileName().split( "/" );
if ( parts.size() > 1 )
{
QStringList dirs = parts.mid( 0, parts.size() - 1 );
QString dirPath = dirs.join( "/" ); // QDir translates / to \ internally if necessary
resolverDir.mkpath( dirPath );
}
// make dir if there is one needed
QDir d( fileInZip.getActualFileName() );
tDebug() << "Writing to output file..." << out.fileName();
if ( !out.open( QIODevice::WriteOnly ) )
{
tLog() << "Failed to open resolver extract file:" << out.errorString() << info.name;
continue;
}
out.write( fileInZip.readAll() );
out.close();
fileInZip.close();
} while ( zipFile.goToNextFile() );
return resolverDir.absolutePath();
}
void
AtticaManager::uninstallResolver( const QString& pathToResolver )
{
// User manually removed a resolver not through attica dialog, simple remove
QRegExp r( ".*([^/]*)/contents/code/main.js" );
r.indexIn( pathToResolver );
const QString& atticaId = r.cap( 1 );
tDebug() << "Got resolver ID to remove:" << atticaId;
if ( !atticaId.isEmpty() ) // this is an attica-installed resolver, mark as uninstalled
{
foreach ( const Content& resolver, m_resolvers )
{
if ( resolver.id() == atticaId ) // this is the one
{
m_resolverStates[ atticaId ].state = Uninstalled;
TomahawkSettings::instance()->setAtticaResolverState( atticaId, Uninstalled );
doResolverRemove( atticaId );
}
}
}
}
void
AtticaManager::uninstallResolver( const Content& resolver )
{
if ( m_resolverStates[ resolver.id() ].state != Upgrading )
{
emit resolverUninstalled( resolver.id() );
emit resolverStateChanged( resolver.id() );
m_resolverStates[ resolver.id() ].state = Uninstalled;
TomahawkSettings::instance()->setAtticaResolverState( resolver.id(), Uninstalled );
}
Tomahawk::Pipeline::instance()->removeScriptResolver( pathFromId( resolver.id() ) );
doResolverRemove( resolver.id() );
}
void
AtticaManager::doResolverRemove( const QString& id ) const
{
// uninstalling is easy... just delete it! :)
QDir resolverDir = TomahawkUtils::appDataDir();
if ( !resolverDir.cd( QString( "atticaresolvers/%1" ).arg( id ) ) )
return;
if ( id.isEmpty() )
return;
// sanity check
if ( !resolverDir.absolutePath().contains( "atticaresolvers" ) ||
!resolverDir.absolutePath().contains( id ) )
return;
TomahawkUtils::removeDirectory( resolverDir.absolutePath() );
}

View File

@@ -1,130 +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 ATTICAMANAGER_H
#define ATTICAMANAGER_H
#include "config.h"
#include <QObject>
#include <QHash>
#include <QPixmap>
#include "dllmacro.h"
#ifdef LIBATTICA_FOUND
#include <attica/provider.h>
#include <attica/providermanager.h>
#include <attica/content.h>
#endif
class DLLEXPORT AtticaManager : public QObject
{
Q_OBJECT
public:
enum ResolverState {
Uninstalled = 0,
Installing,
Installed,
NeedsUpgrade,
Upgrading,
Failed
};
struct Resolver {
QString version, scriptPath;
int userRating; // 0-100
ResolverState state;
QPixmap* pixmap;
Resolver( const QString& v, const QString& path, int userR, ResolverState s )
: version( v ), scriptPath( path ), userRating( userR ), state( s ), pixmap( 0 ) {}
Resolver() : userRating( -1 ), state( Uninstalled ), pixmap( 0 ) {}
};
typedef QHash< QString, AtticaManager::Resolver > StateHash;
static AtticaManager* instance()
{
if ( !s_instance )
s_instance = new AtticaManager();
return s_instance;
}
explicit AtticaManager ( QObject* parent = 0 );
#ifdef LIBATTICA_FOUND
virtual ~AtticaManager();
#else
virtual ~AtticaManager() {}
#endif
#ifdef LIBATTICA_FOUND
bool resolversLoaded() const;
Attica::Content::List resolvers() const;
ResolverState resolverState( const Attica::Content& resolver ) const;
QPixmap iconForResolver( const Attica::Content& id ); // Looks up in icon cache
void installResolver( const Attica::Content& resolver );
void upgradeResolver( const Attica::Content& resolver );
void uninstallResolver( const Attica::Content& resolver );
void uninstallResolver( const QString& pathToResolver );
QString pathFromId( const QString& resolverId ) const;
void uploadRating( const Attica::Content& c );
bool userHasRated( const Attica::Content& c ) const;
signals:
void resolversReloaded( const Attica::Content::List& resolvers );
void resolverStateChanged( const QString& resolverId );
void resolverInstalled( const QString& resolverId );
void resolverUninstalled( const QString& resolverId );
private slots:
void providerAdded( const Attica::Provider& );
void resolversList( Attica::BaseJob* );
void resolverDownloadFinished( Attica::BaseJob* );
void payloadFetched();
void loadPixmapsFromCache();
void savePixmapsToCache();
void resolverIconFetched();
void syncServerData();
bool newerVersion( const QString& older, const QString& newer ) const;
private:
QString extractPayload( const QString& filename, const QString& resolverId ) const;
void doResolverRemove( const QString& id ) const;
Attica::ProviderManager m_manager;
Attica::Provider m_resolverProvider;
Attica::Content::List m_resolvers;
StateHash m_resolverStates;
#endif
static AtticaManager* s_instance;
};
#endif // ATTICAMANAGER_H

View File

@@ -18,7 +18,6 @@ set( libSources
pipeline.cpp
aclsystem.cpp
actioncollection.cpp
artist.cpp
album.cpp
collection.cpp
@@ -33,10 +32,6 @@ set( libSources
globalactionmanager.cpp
contextmenu.cpp
dropjob.cpp
playlistinterface.cpp
LatchManager.cpp
EchonestCatalogSynchronizer.cpp
sip/SipPlugin.cpp
sip/SipHandler.cpp
@@ -45,13 +40,6 @@ set( libSources
audio/audioengine.cpp
context/ContextPage.cpp
context/ContextWidget.cpp
context/pages/TopTracksContext.cpp
context/pages/RelatedArtistsContext.cpp
context/pages/WikipediaContext.cpp
context/pages/WebContext.cpp
database/database.cpp
database/fuzzyindex.cpp
database/databasecollection.cpp
@@ -69,7 +57,7 @@ set( libSources
database/databasecommand_deletefiles.cpp
database/databasecommand_dirmtimes.cpp
database/databasecommand_filemtimes.cpp
database/databasecommand_loadfiles.cpp
database/databasecommand_loadfile.cpp
database/databasecommand_logplayback.cpp
database/databasecommand_addsource.cpp
database/databasecommand_sourceoffline.cpp
@@ -79,7 +67,6 @@ set( libSources
database/databasecommand_playbackhistory.cpp
database/databasecommand_setplaylistrevision.cpp
database/databasecommand_loadallplaylists.cpp
database/databasecommand_loadallsortedplaylists.cpp
database/databasecommand_loadallsources.cpp
database/databasecommand_createplaylist.cpp
database/databasecommand_deleteplaylist.cpp
@@ -98,25 +85,15 @@ set( libSources
database/databasecommand_socialaction.cpp
database/databasecommand_loadsocialactions.cpp
database/databasecommand_genericselect.cpp
database/databasecommand_setcollectionattributes.cpp
database/databasecommand_collectionattributes.cpp
database/databasecommand_trackattributes.cpp
database/databasecommand_settrackattributes.cpp
database/database.cpp
infobar/infobar.cpp
infosystem/infosystemcache.cpp
infosystem/infosystem.cpp
infosystem/infosystemworker.cpp
infosystem/infoplugins/generic/echonestplugin.cpp
infosystem/infoplugins/generic/lastfmplugin.cpp
infosystem/infoplugins/generic/chartsplugin.cpp
infosystem/infoplugins/generic/spotifyPlugin.cpp
infosystem/infoplugins/generic/hypemPlugin.cpp
infosystem/infoplugins/generic/musixmatchplugin.cpp
infosystem/infoplugins/generic/musicbrainzPlugin.cpp
infosystem/infoplugins/generic/RoviPlugin.cpp
playlist/treemodel.cpp
playlist/treeproxymodel.cpp
@@ -144,9 +121,6 @@ set( libSources
playlist/albumview.cpp
playlist/artistview.cpp
playlist/customplaylistview.cpp
playlist/ViewHeader.cpp
playlist/PlaylistUpdaterInterface.cpp
playlist/XspfUpdater.cpp
playlist/topbar/topbar.cpp
playlist/topbar/clearbutton.cpp
@@ -154,13 +128,14 @@ set( libSources
playlist/topbar/lineedit.cpp
playlist/topbar/searchbutton.cpp
playlist/infobar/infobar.cpp
playlist/dynamic/DynamicPlaylist.cpp
playlist/dynamic/DynamicControl.cpp
playlist/dynamic/GeneratorFactory.cpp
playlist/dynamic/GeneratorInterface.cpp
playlist/dynamic/DynamicView.cpp
playlist/dynamic/DynamicModel.cpp
playlist/dynamic/DynamicPlaylistRevision.cpp
playlist/dynamic/echonest/EchonestGenerator.cpp
playlist/dynamic/echonest/EchonestControl.cpp
playlist/dynamic/echonest/EchonestSteerer.cpp
@@ -175,9 +150,6 @@ set( libSources
playlist/dynamic/database/DatabaseControl.cpp
playlist/dynamic/database/DatabaseGenerator.cpp
resolvers/scriptresolver.cpp
resolvers/qtscriptresolver.cpp
network/bufferiodevice.cpp
network/msgprocessor.cpp
network/streamconnection.cpp
@@ -189,57 +161,37 @@ set( libSources
network/controlconnection.cpp
utils/tomahawkutils.cpp
utils/querylabel.cpp
utils/elidedlabel.cpp
utils/imagebutton.cpp
utils/logger.cpp
utils/proxystyle.cpp
utils/widgetdragfilter.cpp
utils/animatedsplitter.cpp
utils/xspfloader.cpp
utils/xspfgenerator.cpp
utils/jspfloader.cpp
utils/spotifyparser.cpp
utils/itunesparser.cpp
utils/rdioparser.cpp
utils/shortenedlinkparser.cpp
utils/stylehelper.cpp
utils/qnr_iodevicestream.cpp
utils/dropjobnotifier.cpp
widgets/checkdirtree.cpp
widgets/querylabel.cpp
widgets/imagebutton.cpp
widgets/animatedsplitter.cpp
widgets/elidedlabel.cpp
widgets/newplaylistwidget.cpp
widgets/searchwidget.cpp
widgets/SeekSlider.cpp
widgets/playlisttypeselectordlg.cpp
widgets/welcomewidget.cpp
widgets/whatshotwidget.cpp
widgets/RecentlyPlayedPlaylistsModel.cpp
widgets/RecentPlaylistsModel.cpp
widgets/OverlayButton.cpp
widgets/welcomeplaylistmodel.cpp
widgets/overlaywidget.cpp
widgets/HeaderLabel.cpp
widgets/HeaderWidget.cpp
widgets/combobox.cpp
widgets/ToggleButton.cpp
widgets/SocialPlaylistWidget.cpp
widgets/infowidgets/sourceinfowidget.cpp
widgets/infowidgets/ArtistInfoWidget.cpp
widgets/infowidgets/AlbumInfoWidget.cpp
widgets/Breadcrumb.cpp
widgets/BreadcrumbButton.cpp
jobview/JobStatusView.cpp
jobview/JobStatusModel.cpp
jobview/JobStatusDelegate.cpp
jobview/PipelineStatusItem.cpp
jobview/TransferStatusItem.cpp
jobview/LatchedStatusItem.cpp
thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.cpp
thirdparty/kdsingleapplicationguard/kdsharedmemorylocker.cpp
thirdparty/kdsingleapplicationguard/kdtoolsglobal.cpp
thirdparty/kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp
kdsingleapplicationguard/kdsingleapplicationguard.cpp
kdsingleapplicationguard/kdsharedmemorylocker.cpp
kdsingleapplicationguard/kdtoolsglobal.cpp
kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp
)
set( libHeaders
@@ -249,7 +201,6 @@ set( libHeaders
functimeout.h
aclsystem.h
actioncollection.h
collection.h
query.h
resolver.h
@@ -260,15 +211,11 @@ set( libHeaders
globalactionmanager.h
contextmenu.h
dropjob.h
AtticaManager.h
LatchManager.h
artist.h
album.h
playlist.h
EchonestCatalogSynchronizer.h
sip/SipPlugin.h
sip/SipHandler.h
sip/SipModel.h
@@ -276,13 +223,6 @@ set( libHeaders
audio/audioengine.h
context/ContextPage.h
context/ContextWidget.h
context/pages/TopTracksContext.h
context/pages/RelatedArtistsContext.h
context/pages/WikipediaContext.h
context/pages/WebContext.h
database/database.h
database/fuzzyindex.h
database/databaseworker.h
@@ -298,7 +238,7 @@ set( libHeaders
database/databasecommand_deletefiles.h
database/databasecommand_dirmtimes.h
database/databasecommand_filemtimes.h
database/databasecommand_loadfiles.h
database/databasecommand_loadfile.h
database/databasecommand_logplayback.h
database/databasecommand_addsource.h
database/databasecommand_sourceoffline.h
@@ -308,7 +248,6 @@ set( libHeaders
database/databasecommand_playbackhistory.h
database/databasecommand_setplaylistrevision.h
database/databasecommand_loadallplaylists.h
database/databasecommand_loadallsortedplaylists.h
database/databasecommand_loadallsources.h
database/databasecommand_createplaylist.h
database/databasecommand_deleteplaylist.h
@@ -329,24 +268,14 @@ set( libHeaders
database/databasecommand_socialaction.h
database/databasecommand_loadsocialactions.h
database/databasecommand_genericselect.h
database/databasecommand_setcollectionattributes.h
database/databasecommand_collectionattributes.h
database/databasecommand_trackattributes.h
database/databasecommand_settrackattributes.h
infobar/infobar.h
infosystem/infosystem.h
infosystem/infosystemworker.h
infosystem/infosystemcache.h
infosystem/infoplugins/generic/echonestplugin.h
infosystem/infoplugins/generic/lastfmplugin.h
infosystem/infoplugins/generic/chartsplugin.h
infosystem/infoplugins/generic/spotifyPlugin.h
infosystem/infoplugins/generic/hypemPlugin.h
infosystem/infoplugins/generic/musixmatchplugin.h
infosystem/infoplugins/generic/musicbrainzPlugin.h
infosystem/infoplugins/generic/RoviPlugin.h
network/bufferiodevice.h
network/msgprocessor.h
@@ -384,9 +313,6 @@ set( libHeaders
playlist/albumview.h
playlist/artistview.h
playlist/customplaylistview.h
playlist/ViewHeader.h
playlist/PlaylistUpdaterInterface.h
playlist/XspfUpdater.h
playlist/topbar/topbar.h
playlist/topbar/clearbutton.h
@@ -395,6 +321,8 @@ set( libHeaders
playlist/topbar/lineedit_p.h
playlist/topbar/searchbutton.h
playlist/infobar/infobar.h
playlist/dynamic/DynamicPlaylist.h
playlist/dynamic/DynamicControl.h
playlist/dynamic/GeneratorInterface.h
@@ -414,58 +342,33 @@ set( libHeaders
playlist/dynamic/database/DatabaseControl.h
playlist/dynamic/database/DatabaseGenerator.h
resolvers/scriptresolver.h
resolvers/qtscriptresolver.h
utils/querylabel.h
utils/elidedlabel.h
utils/animatedcounterlabel.h
utils/imagebutton.h
utils/widgetdragfilter.h
utils/animatedsplitter.h
utils/xspfloader.h
utils/xspfgenerator.h
utils/jspfloader.h
utils/spotifyparser.h
utils/itunesparser.h
utils/rdioparser.h
utils/shortenedlinkparser.h
utils/qnr_iodevicestream.h
utils/dropjobnotifier.h
widgets/checkdirtree.h
widgets/querylabel.h
widgets/animatedcounterlabel.h
widgets/imagebutton.h
widgets/animatedsplitter.h
widgets/elidedlabel.h
widgets/newplaylistwidget.h
widgets/searchwidget.h
widgets/SeekSlider.h
widgets/playlisttypeselectordlg.h
widgets/welcomewidget.h
widgets/whatshotwidget.h
widgets/RecentlyPlayedPlaylistsModel.h
widgets/RecentPlaylistsModel.h
widgets/OverlayButton.h
widgets/welcomeplaylistmodel.h
widgets/overlaywidget.h
widgets/HeaderLabel.h
widgets/HeaderWidget.h
widgets/combobox.h
widgets/ToggleButton.h
widgets/SocialPlaylistWidget.h
widgets/infowidgets/sourceinfowidget.h
widgets/infowidgets/ArtistInfoWidget.h
widgets/infowidgets/ArtistInfoWidget_p.h
widgets/infowidgets/AlbumInfoWidget.h
widgets/Breadcrumb.h
widgets/BreadcrumbButton.h
jobview/JobStatusView.h
jobview/JobStatusModel.h
jobview/JobStatusDelegate.h
jobview/JobStatusItem.h
jobview/PipelineStatusItem.h
jobview/TransferStatusItem.h
jobview/LatchedStatusItem.h
thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.h
thirdparty/Qocoa/qsearchfield.h
kdsingleapplicationguard/kdsingleapplicationguard.h
)
set( libHeaders_NoMOC
@@ -484,15 +387,12 @@ set( libUI ${libUI}
widgets/newplaylistwidget.ui
widgets/searchwidget.ui
widgets/welcomewidget.ui
widgets/whatshotwidget.ui
widgets/SocialPlaylistWidget.ui
widgets/infowidgets/sourceinfowidget.ui
widgets/infowidgets/ArtistInfoWidget.ui
widgets/infowidgets/AlbumInfoWidget.ui
playlist/topbar/topbar.ui
playlist/queueview.ui
context/ContextWidget.ui
infobar/infobar.ui
playlist/infobar/infobar.ui
)
include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.. ..
@@ -502,6 +402,7 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.
${LIBECHONEST_INCLUDE_DIR}
${LIBECHONEST_INCLUDE_DIR}/..
${CLUCENE_INCLUDE_DIR}
${CLUCENE_LIBRARY_DIR}
${PHONON_INCLUDES}
${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src
@@ -509,38 +410,16 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.
${LIBPORTFWD_INCLUDE_DIR}
${THIRDPARTY_DIR}/qxt/qxtweb-standalone/qxtweb
${QuaZip_INCLUDE_DIR}
${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src
)
IF(QCA2_FOUND)
INCLUDE_DIRECTORIES( ${QCA2_INCLUDE_DIR} )
ENDIF(QCA2_FOUND)
IF(LIBATTICA_FOUND)
SET( libSources ${libSources} AtticaManager.cpp )
SET( libHeaders ${libHeaders} AtticaManager.h )
INCLUDE_DIRECTORIES( ${LIBATTICA_INCLUDE_DIR} )
ENDIF(LIBATTICA_FOUND)
IF( UNIX AND NOT APPLE )
SET( libSources ${libSources}
infosystem/infoplugins/unix/mprispluginrootadaptor.cpp
infosystem/infoplugins/unix/mprispluginplayeradaptor.cpp
infosystem/infoplugins/unix/mprisplugin.cpp
infosystem/infoplugins/unix/fdonotifyplugin.cpp
infosystem/infoplugins/unix/imageconverter.cpp )
SET( libHeaders ${libHeaders}
infosystem/infoplugins/unix/mprispluginrootadaptor.h
infosystem/infoplugins/unix/mprispluginplayeradaptor.h
infosystem/infoplugins/unix/mprisplugin.h
infosystem/infoplugins/unix/fdonotifyplugin.h )
IF( BUILD_GUI AND X11_FOUND )
INCLUDE_DIRECTORIES( ${THIRDPARTY_DIR}/libqnetwm )
SET( libSources ${libSources} ${THIRDPARTY_DIR}/libqnetwm/libqnetwm/netwm.cpp )
SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${X11_LIBRARIES} )
ENDIF()
ENDIF( UNIX AND NOT APPLE )
IF( WIN32 )
@@ -566,10 +445,11 @@ IF( APPLE )
SET( libSources ${libSources}
infosystem/infoplugins/mac/adium.mm
infosystem/infoplugins/mac/adiumplugin.cpp
utils/tomahawkutils_mac.mm
thirdparty/Qocoa/qsearchfield_mac.mm )
widgets/maclineedit.mm
utils/tomahawkutils_mac.mm )
SET( libHeaders ${libHeaders}
widgets/maclineedit.h
infosystem/infoplugins/mac/adium.h
infosystem/infoplugins/mac/adiumplugin.h )
@@ -583,8 +463,6 @@ IF( APPLE )
/System/Library/Frameworks/AppKit.framework
)
ELSE( APPLE )
SET( libSources ${libSources} thirdparty/Qocoa/qsearchfield.cpp )
ENDIF( APPLE )
IF(LIBLASTFM_FOUND)
@@ -596,17 +474,9 @@ qt4_wrap_cpp( libMoc ${libHeaders} )
SET( libSources ${libSources} ${libUI_H} ${libHeaders_NoMOC} )
ADD_LIBRARY( tomahawklib SHARED ${libSources} ${libMoc} )
add_library( tomahawklib SHARED ${libSources} ${libMoc} )
IF(QCA2_FOUND)
SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} )
ENDIF(QCA2_FOUND)
IF(LIBATTICA_FOUND)
SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBATTICA_LIBRARIES} ${QuaZip_LIBRARIES} )
ENDIF(LIBATTICA_FOUND)
TARGET_LINK_LIBRARIES( tomahawklib
target_link_libraries( tomahawklib
# Thirdparty shipped with tomahawk
${LIBPORTFWD_LIBRARIES}

View File

@@ -1,366 +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 "EchonestCatalogSynchronizer.h"
#include "collection.h"
#include "database/database.h"
#include "database/databasecommand_genericselect.h"
#include "database/databasecommand_setcollectionattributes.h"
#include "database/databasecommand_loadfiles.h"
#include "tomahawksettings.h"
#include "sourcelist.h"
#include "query.h"
#include <echonest/CatalogUpdateEntry.h>
#include <echonest/Config.h>
using namespace Tomahawk;
EchonestCatalogSynchronizer* EchonestCatalogSynchronizer::s_instance = 0;
EchonestCatalogSynchronizer::EchonestCatalogSynchronizer( QObject *parent )
: QObject( parent )
{
m_syncing = TomahawkSettings::instance()->enableEchonestCatalogs();
qRegisterMetaType<QList<QStringList> >("QList<QStringList>");
connect( TomahawkSettings::instance(), SIGNAL( changed() ), this, SLOT( checkSettingsChanged() ) );
connect( SourceList::instance()->getLocal()->collection().data(), SIGNAL( tracksAdded( QList<unsigned int> ) ), this, SLOT( tracksAdded( QList<unsigned int> ) ), Qt::QueuedConnection );
connect( SourceList::instance()->getLocal()->collection().data(), SIGNAL( tracksRemoved( QList<unsigned int> ) ), this, SLOT( tracksRemoved( QList<unsigned int> ) ), Qt::QueuedConnection );
const QByteArray artist = TomahawkSettings::instance()->value( "collection/artistCatalog" ).toByteArray();
const QByteArray song = TomahawkSettings::instance()->value( "collection/songCatalog" ).toByteArray();
if ( !artist.isEmpty() )
m_artistCatalog.setId( artist );
if ( !song.isEmpty() )
m_songCatalog.setId( song );
// Sanity check
if ( !song.isEmpty() && !m_syncing )
{
// Not syncing but have a catalog id... lets fix this
QNetworkReply* r = m_songCatalog.deleteCatalog();
connect( r, SIGNAL( finished() ), this, SLOT( catalogDeleted() ) );
r->setProperty( "type", "song" );
}
if ( !artist.isEmpty() && !m_syncing )
{
QNetworkReply* r = m_artistCatalog.deleteCatalog();
connect( r, SIGNAL( finished() ), this, SLOT( catalogDeleted() ) );
r->setProperty( "type", "artist" );
}
}
void
EchonestCatalogSynchronizer::checkSettingsChanged()
{
if ( TomahawkSettings::instance()->enableEchonestCatalogs() && !m_syncing )
{
// enable, and upload whole db
m_syncing = true;
tDebug() << "Echonest Catalog sync pref changed, uploading!!";
uploadDb();
} else if ( !TomahawkSettings::instance()->enableEchonestCatalogs() && m_syncing )
{
tDebug() << "Found echonest change, doing catalog deletes!";
// delete all track nums and catalog ids from our peers
{
DatabaseCommand_SetTrackAttributes* cmd = new DatabaseCommand_SetTrackAttributes( DatabaseCommand_SetTrackAttributes::EchonestCatalogId );
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
}
{
DatabaseCommand_SetCollectionAttributes* cmd = new DatabaseCommand_SetCollectionAttributes( DatabaseCommand_SetCollectionAttributes::EchonestSongCatalog, true );
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
}
if ( !m_songCatalog.id().isEmpty() )
{
QNetworkReply* r = m_songCatalog.deleteCatalog();
connect( r, SIGNAL( finished() ), this, SLOT( catalogDeleted() ) );
r->setProperty( "type", "song" );
}
if ( !m_artistCatalog.id().isEmpty() )
{
QNetworkReply* r = m_artistCatalog.deleteCatalog();
connect( r, SIGNAL( finished() ), this, SLOT( catalogDeleted() ) );
r->setProperty( "type", "artist" );
}
m_syncing = false;
}
}
void
EchonestCatalogSynchronizer::catalogDeleted()
{
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
Q_ASSERT( r );
QString toDel = QString( "collection/%1Catalog" ).arg( r->property( "type" ).toString() );
try
{
// HACK libechonest bug, should be a static method but it's not. Doesn't actually use any instance vars though
m_songCatalog.parseDelete( r );
// If we didn't throw, no errors, so clear our config
TomahawkSettings::instance()->setValue( toDel, QString() );
} catch ( const Echonest::ParseError& e )
{
tLog() << "Error in libechonest parsing catalog delete:" << e.what();
}
}
void
EchonestCatalogSynchronizer::uploadDb()
{
// create two catalogs: uuid_song, and uuid_artist.
QNetworkReply* r = Echonest::Catalog::create( QString( "%1_song" ).arg( Database::instance()->dbid() ), Echonest::CatalogTypes::Song );
connect( r, SIGNAL( finished() ), this, SLOT( songCreateFinished() ) );
// r = Echonest::Catalog::create( QString( "%1_artist" ).arg( Database::instance()->dbid() ), Echonest::CatalogTypes::Artist );
// connect( r, SIGNAL( finished() ), this, SLOT( artistCreateFinished() ) );
}
void
EchonestCatalogSynchronizer::songCreateFinished()
{
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
Q_ASSERT( r );
tDebug() << "Finished creating song catalog, updating data now!!";
try
{
m_songCatalog = Echonest::Catalog::parseCreate( r );
TomahawkSettings::instance()->setValue( "collection/songCatalog", m_songCatalog.id() );
QSharedPointer< DatabaseCommand > cmd( new DatabaseCommand_SetCollectionAttributes( DatabaseCommand_SetCollectionAttributes::EchonestSongCatalog,
m_songCatalog.id() ) );
Database::instance()->enqueue( cmd );
} catch ( const Echonest::ParseError& e )
{
tLog() << "Echonest threw an exception parsing song catalog create:" << e.what();
return;
}
QString sql( "SELECT file.id, track.name, artist.name, album.name "
"FROM file, artist, track, file_join "
"LEFT OUTER JOIN album "
"ON file_join.album = album.id "
"WHERE file.id = file_join.file "
"AND file_join.artist = artist.id "
"AND file_join.track = track.id "
"AND file.source IS NULL");
DatabaseCommand_GenericSelect* cmd = new DatabaseCommand_GenericSelect( sql, DatabaseCommand_GenericSelect::Track, true );
connect( cmd, SIGNAL( rawData( QList< QStringList > ) ), this, SLOT( rawTracksAdd( QList< QStringList > ) ) );
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
}
void
EchonestCatalogSynchronizer::artistCreateFinished()
{
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
Q_ASSERT( r );
// We don't support artist catalogs at the moment
return;
/*
try
{
m_artistCatalog = Echonest::Catalog::parseCreate( r );
TomahawkSettings::instance()->setValue( "collection/artistCatalog", m_artistCatalog.id() );
// QSharedPointer< DatabaseCommand > cmd( new DatabaseCommand_SetCollectionAttributes( SourceList::instance()->getLocal(),
// DatabaseCommand_SetCollectionAttributes::EchonestSongCatalog,
// m_songCatalog.id() ) );
// Database::instance()->enqueue( cmd );
} catch ( const Echonest::ParseError& e )
{
tLog() << "Echonest threw an exception parsing artist catalog create:" << e.what();
return;
}*/
}
void
EchonestCatalogSynchronizer::rawTracksAdd( const QList< QStringList >& tracks )
{
tDebug() << "Got raw tracks, num:" << tracks.size();
// int limit = ( tracks.size() < 1000 ) ? tracks.size() : 1000;
int cur = 0;
while ( cur < tracks.size() )
{
int prev = cur;
cur = ( cur + 2000 > tracks.size() ) ? tracks.size() : cur + 2000;
tDebug() << "Enqueueing a batch of tracks to upload to echonest catalog:" << cur - prev;
Echonest::CatalogUpdateEntries entries;
for ( int i = prev; i < cur; i++ )
{
if ( tracks[i][1].isEmpty() || tracks[i][2].isEmpty() )
continue;
entries.append( entryFromTrack( tracks[i], Echonest::CatalogTypes::Update ) );
}
tDebug() << "Done queuing:" << entries.size() << "tracks";
m_queuedUpdates.enqueue( entries );
}
doUploadJob();
}
void
EchonestCatalogSynchronizer::doUploadJob()
{
if ( m_queuedUpdates.isEmpty() )
return;
Echonest::CatalogUpdateEntries entries = m_queuedUpdates.dequeue();
tDebug() << "Updating number of entries:" << entries.count();
QNetworkReply* updateJob = m_songCatalog.update( entries );
connect( updateJob, SIGNAL( finished() ), this, SLOT( songUpdateFinished() ) );
}
Echonest::CatalogUpdateEntry
EchonestCatalogSynchronizer::entryFromTrack( const QStringList& track, Echonest::CatalogTypes::Action action ) const
{
//qDebug() << "UPLOADING:" << track[0] << track[1] << track[2];
Echonest::CatalogUpdateEntry entry;
entry.setAction( action );
entry.setItemId(track[ 0 ].toLatin1() ); // track dbid
entry.setSongName( escape( track[ 1 ] ) );
entry.setArtistName( escape( track[ 2 ] ) );
entry.setRelease( escape( track[ 3 ] ) );
return entry;
}
void
EchonestCatalogSynchronizer::songUpdateFinished()
{
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
Q_ASSERT( r );
try
{
QByteArray ticket = m_songCatalog.parseTicket( r );
QNetworkReply* tJob = m_songCatalog.status( ticket );
connect( tJob, SIGNAL( finished() ), this, SLOT( checkTicket() ) );
} catch ( const Echonest::ParseError& e )
{
tLog() << "Echonest threw an exception parsing catalog update finished:" << e.what();
}
doUploadJob();
}
void
EchonestCatalogSynchronizer::checkTicket()
{
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
Q_ASSERT( r );
try
{
Echonest::CatalogStatus status = m_songCatalog.parseStatus( r );
tLog() << "Catalog status update:" << status.status << status.details << status.items;
} catch ( const Echonest::ParseError& e )
{
tLog() << "Echonest threw an exception parsing catalog create:" << e.what();
return;
}
}
void
EchonestCatalogSynchronizer::tracksAdded( const QList< unsigned int >& tracks )
{
if ( !m_syncing || m_songCatalog.id().isEmpty() || tracks.isEmpty() )
return;
qDebug() << Q_FUNC_INFO << "Got tracks added from db, fetching metadata" << tracks;
// Get the result_ptrs from the tracks
DatabaseCommand_LoadFiles* cmd = new DatabaseCommand_LoadFiles( tracks );
connect( cmd, SIGNAL( results( QList<Tomahawk::result_ptr> ) ), this, SLOT( loadedResults( QList<Tomahawk::result_ptr> ) ) );
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
}
void
EchonestCatalogSynchronizer::loadedResults( const QList<result_ptr>& results )
{
QList< QStringList > rawTracks;
qDebug() << Q_FUNC_INFO << "Got track metadata..." << results.size();
foreach( const result_ptr& result, results )
{
if ( result.isNull() )
continue;
qDebug() << "Metadata for item:" << result->fileId();
const QString artist = result->artist().isNull() ? QString() : result->artist()->name();
const QString album = result->album().isNull() ? QString() : result->album()->name();
rawTracks << ( QStringList() << QString::number( result->fileId() ) << result->track() << artist << album );
}
rawTracksAdd( rawTracks );
}
void
EchonestCatalogSynchronizer::tracksRemoved( const QList< unsigned int >& trackIds )
{
if ( !m_syncing || m_songCatalog.id().isEmpty() || trackIds.isEmpty() )
return;
Echonest::CatalogUpdateEntries entries;
entries.reserve( trackIds.size() );
foreach ( unsigned int id, trackIds )
{
tDebug() << "Deleting item with id:" << id;
Echonest::CatalogUpdateEntry e( Echonest::CatalogTypes::Delete );
e.setItemId( QString::number( id ).toLatin1() );
entries.append( e );
}
QNetworkReply* reply = m_songCatalog.update( entries );
connect( reply, SIGNAL( finished() ), this, SLOT( songUpdateFinished() ) );
}
QByteArray
EchonestCatalogSynchronizer::escape( const QString &in ) const
{
// TODO echonest chokes on some chars in the output. But if we percent-encode those chars it works
// We can't percent-encode the whole string, because then any UTF-8 chars that have been url-encoded, fail.
// God this sucks. It's going to break...
QString clean = in;
clean.replace( "&", "%25" );
clean.replace( ";", "%3B" );
return clean.toUtf8();
//return QUrl::toPercentEncoding( in. );
}

View File

@@ -1,91 +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 ECHONESTCATALOGSYNCHRONIZER_H
#define ECHONESTCATALOGSYNCHRONIZER_H
#include "dllmacro.h"
#include "query.h"
#include "database/databasecommand_trackattributes.h"
#include <echonest/Catalog.h>
#include <QObject>
#include <QQueue>
namespace Tomahawk
{
class DLLEXPORT EchonestCatalogSynchronizer : public QObject
{
Q_OBJECT
public:
static EchonestCatalogSynchronizer* instance() {
if ( !s_instance )
{
s_instance = new EchonestCatalogSynchronizer;
}
return s_instance;
}
explicit EchonestCatalogSynchronizer(QObject *parent = 0);
Echonest::Catalog songCatalog() const { return m_songCatalog; }
Echonest::Catalog artistCatalog() const { return m_artistCatalog; }
signals:
void knownCatalogsChanged();
private slots:
void checkSettingsChanged();
void tracksAdded( const QList<unsigned int>& );
void tracksRemoved( const QList<unsigned int>& );
void loadedResults( const QList<Tomahawk::result_ptr>& results );
// Echonest slots
void songCreateFinished();
void artistCreateFinished();
void songUpdateFinished();
void catalogDeleted();
void checkTicket();
void rawTracksAdd( const QList< QStringList >& tracks );
private:
void uploadDb();
QByteArray escape( const QString& in ) const;
Echonest::CatalogUpdateEntry entryFromTrack( const QStringList&, Echonest::CatalogTypes::Action action ) const;
void doUploadJob();
bool m_syncing;
Echonest::Catalog m_songCatalog;
Echonest::Catalog m_artistCatalog;
QQueue< Echonest::CatalogUpdateEntries > m_queuedUpdates;
static EchonestCatalogSynchronizer* s_instance;
friend class ::DatabaseCommand_SetCollectionAttributes;
};
}
#endif // ECHONESTCATALOGSYNCHRONIZER_H

View File

@@ -1,139 +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 "LatchManager.h"
#include "actioncollection.h"
#include "audio/audioengine.h"
#include "database/database.h"
#include <QtCore/QStateMachine>
#include <QtCore/QState>
#include "sourcelist.h"
#include "database/databasecommand_socialaction.h"
#include "sourceplaylistinterface.h"
using namespace Tomahawk;
LatchManager::LatchManager( QObject* parent )
: QObject( parent )
, m_state( NotLatched )
{
connect( AudioEngine::instance(), SIGNAL( playlistChanged( Tomahawk::PlaylistInterface* ) ), this, SLOT( playlistChanged( Tomahawk::PlaylistInterface* ) ) );
}
LatchManager::~LatchManager()
{
}
bool
LatchManager::isLatched( const source_ptr& src )
{
return m_state == Latched && m_latchedOnTo == src;
}
void
LatchManager::latchRequest( const source_ptr& source )
{
qDebug() << Q_FUNC_INFO;
if ( isLatched( source ) )
return;
m_state = Latching;
m_waitingForLatch = source;
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
}
void
LatchManager::playlistChanged( PlaylistInterface* )
{
// If we were latched on and changed, send the listening along stop
if ( m_latchedOnTo.isNull() )
{
if ( m_waitingForLatch.isNull() )
return; // Neither latched on nor waiting to be latched on, no-op
m_latchedOnTo = m_waitingForLatch;
m_latchedInterface = m_waitingForLatch->getPlaylistInterface();
m_waitingForLatch.clear();
m_state = Latched;
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction();
cmd->setSource( SourceList::instance()->getLocal() );
cmd->setAction( "latchOn");
cmd->setComment( m_latchedOnTo->userName() );
cmd->setTimestamp( QDateTime::currentDateTime().toTime_t() );
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
ActionCollection::instance()->getAction( "latchOn" )->setText( tr( "&Catch Up" ) );
// If not, then keep waiting
return;
}
// We're current latched, and the user changed playlist, so stop
SourcePlaylistInterface* origsourcepi = dynamic_cast< SourcePlaylistInterface* >( m_latchedInterface.data() );
Q_ASSERT( origsourcepi );
const source_ptr source = origsourcepi->source();
DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction();
cmd->setSource( SourceList::instance()->getLocal() );
cmd->setAction( "latchOff");
cmd->setComment( source->userName() );
cmd->setTimestamp( QDateTime::currentDateTime().toTime_t() );
Database::instance()->enqueue( QSharedPointer< DatabaseCommand >( cmd ) );
if ( !m_waitingForLatch.isNull() &&
m_waitingForLatch != m_latchedOnTo )
{
// We are asked to latch on immediately to another source
m_latchedOnTo.clear();
m_latchedInterface.clear();
// call ourselves to hit the "create latch" condition
playlistChanged( 0 );
return;
}
m_latchedOnTo.clear();
m_waitingForLatch.clear();
m_latchedInterface.clear();
m_state = NotLatched;
ActionCollection::instance()->getAction( "latchOn" )->setText( tr( "&Listen Along" ) );
}
void
LatchManager::catchUpRequest()
{
//it's a catch-up -- logic in audioengine should take care of it
AudioEngine::instance()->next();
}
void
LatchManager::unlatchRequest( const source_ptr& source )
{
Q_UNUSED( source );
AudioEngine::instance()->stop();
AudioEngine::instance()->setPlaylist( 0 );
ActionCollection::instance()->getAction( "latchOn" )->setText( tr( "&Listen Along" ) );
}

Some files were not shown because too many files have changed in this diff Show More