1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-09-16 17:02:04 +02:00

Compare commits

..

11 Commits

Author SHA1 Message Date
Michael Zanetti
a78a25baa6 remove unused old code 2011-09-24 15:26:40 +02:00
Michael Zanetti
375ffd1445 speedup animation a bit to match the other dropmenu's duration 2011-09-24 15:26:15 +02:00
Michael Zanetti
c3d223d8cb completed dropmenu in audio controls area 2011-09-24 15:20:44 +02:00
Michael Zanetti
b2f3dedaff more work the dropmenu for the audiocontrols 2011-09-04 20:56:10 +02:00
Christian Muehlhaeuser
a3ae74dc10 * Some more cleanups. 2011-09-04 20:56:10 +02:00
Christian Muehlhaeuser
4dfb989676 * Don't react to hover events unless TrackView is in Detailed mode. 2011-09-04 20:56:10 +02:00
Christian Muehlhaeuser
e0d1289a16 * Resize ContextPage's columns. 2011-09-04 20:56:10 +02:00
Christian Muehlhaeuser
cc5ba35a08 * Add forgotten ui file. 2011-09-04 20:56:10 +02:00
Christian Muehlhaeuser
e0e79c09a4 * Removed ugly queue button for good. 2011-09-04 20:56:10 +02:00
Christian Muehlhaeuser
03f726f46c * Added initial ContextView. Yikes. 2011-09-04 20:56:10 +02:00
Michael Zanetti
c0edc3a989 initial try on a dragndrop menu for audiocontrols 2011-09-04 01:54:13 +02:00
1787 changed files with 12906 additions and 492951 deletions

1
.gitignore vendored
View File

@@ -17,4 +17,3 @@ 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 99 )
#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}" )
@@ -84,8 +85,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")
@@ -104,39 +105,14 @@ macro_log_feature(Boost_FOUND "Boost" "Provides free peer-reviewed portable C++
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
#macro_optional_find_package(LibLastFm 0.3.3)
#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 +125,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 +147,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 +158,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 +195,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,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,67 +1,6 @@
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:

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 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

After

Width:  |  Height:  |  Size: 1.0 MiB

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

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

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

@@ -184,21 +184,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>
@@ -92,9 +91,6 @@
<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>
@@ -112,7 +108,6 @@
<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>
@@ -120,15 +115,5 @@
<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
@@ -63,8 +66,8 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
sourcetree/items/genericpageitems.cpp
sourcetree/items/temporarypageitem.cpp
breakpad/BreakPad.cpp
transferview.cpp
PipelineStatusView.cpp
tomahawktrayicon.cpp
audiocontrols.cpp
settingsdialog.cpp
@@ -75,7 +78,6 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
settingslistdelegate.cpp
resolversmodel.cpp
tomahawkwindow.cpp
LoadXSPFDialog.cpp
)
SET( tomahawkHeaders ${tomahawkHeaders}
@@ -83,6 +85,9 @@ SET( tomahawkHeaders ${tomahawkHeaders}
web/api_v1.h
resolvers/scriptresolver.h
resolvers/qtscriptresolver.h
musicscanner.h
scanmanager.h
shortcuthandler.h
@@ -94,12 +99,6 @@ 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
@@ -114,6 +113,8 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
sourcetree/items/genericpageitems.h
sourcetree/items/temporarypageitem.h
transferview.h
PipelineStatusView.h
tomahawktrayicon.h
audiocontrols.h
settingsdialog.h
@@ -125,7 +126,8 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
resolversmodel.h
delegateconfigwrapper.h
tomahawkwindow.h
LoadXSPFDialog.h
Qocoa/qsearchfield.h
)
SET( tomahawkUI ${tomahawkUI}
@@ -135,9 +137,6 @@ SET( tomahawkUI ${tomahawkUI}
proxydialog.ui
audiocontrols.ui
GetNewStuffDialog.ui
LoadXSPFDialog.ui
)
INCLUDE_DIRECTORIES(
@@ -158,7 +157,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 +177,14 @@ 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 Qocoa/qsearchfield_mac.mm )
IF(HAVE_SPARKLE)
SET( tomahawkHeaders ${tomahawkHeaders} ${SPARKLE}/Headers )
ENDIF(HAVE_SPARKLE)
ELSE( APPLE )
SET( tomahawkSources ${tomahawkSources} Qocoa/qsearchfield.cpp )
ENDIF( APPLE )
IF(GLOOX_FOUND)
@@ -237,12 +237,12 @@ 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}

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

@@ -29,7 +29,7 @@ THE SOFTWARE.
#include "playlist/topbar/searchlineedit.h"
#include "utils/tomahawkutils.h"
class DLLEXPORT QSearchFieldPrivate
class QSearchFieldPrivate
{
public:
QSearchFieldPrivate(SearchLineEdit *lineEdit) : lineEdit(lineEdit) {}
@@ -51,17 +51,10 @@ QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
TomahawkUtils::unmarginLayout(layout);
setContentsMargins(0, 0, 0, 0);
lineEdit->setStyleSheet( "QLineEdit { border: 1px solid gray; border-radius: 6px; }" );
#ifdef Q_WS_MAC
lineEdit->setStyleSheet( "QLineEdit { border: 1px solid gray; border-radius: 6px; margin-right: 2px; }" );
lineEdit->setContentsMargins(0, 0, 0, 0);
lineEdit->setMinimumHeight(27);
setFixedHeight(27);
#else
lineEdit->setContentsMargins(2, 2, 2, 2);
lineEdit->setMinimumHeight(27);
#endif
}
void QSearchField::setText(const QString &text)

View File

@@ -3,10 +3,8 @@
#include <QWidget>
#include "dllmacro.h"
class QSearchFieldPrivate;
class DLLEXPORT QSearchField : public QWidget
class QSearchField : public QWidget
{
Q_OBJECT
public:

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;
@@ -45,6 +47,7 @@ AudioControls::AudioControls( QWidget* parent )
, ui( new Ui::AudioControls )
, m_repeatMode( PlaylistInterface::NoRepeat )
, m_shuffled( false )
, m_dropAreaExpanded( false )
{
ui->setupUi( this );
setAcceptDrops( true );
@@ -88,7 +91,7 @@ AudioControls::AudioControls( QWidget* parent )
ui->ownerLabel->setForegroundRole( QPalette::Dark );
ui->metaDataArea->setStyleSheet( "QWidget#metaDataArea {\nborder-width: 4px;\nborder-image: url(" RESPATH "images/now-playing-panel.png) 4 4 4 4 stretch stretch; }" );
ui->seekSlider->setEnabled( true );
ui->volumeSlider->setRange( 0, 100 );
ui->volumeSlider->setValue( AudioEngine::instance()->volume() );
@@ -97,7 +100,7 @@ AudioControls::AudioControls( QWidget* parent )
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() ) );
@@ -128,7 +131,7 @@ AudioControls::AudioControls( QWidget* parent )
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(),
@@ -146,6 +149,46 @@ AudioControls::AudioControls( QWidget* parent )
ui->stackedLayout->setSizeConstraint( QLayout::SetFixedSize );
onPlaybackStopped(); // initial state
m_dragAnimation = new QPropertyAnimation( this, "dropAreaSize", this );
m_dragAnimation->setStartValue( 0 );
m_dragAnimation->setDuration( 300 );
m_dragAnimation->setEasingCurve( QEasingCurve::Linear );
connect( m_dragAnimation, SIGNAL( finished() ), SLOT(dragAnimationFinished()));
m_dropAreaCollapseTimer.setInterval( 300 );
m_dropAreaCollapseTimer.setSingleShot( true );
connect( &m_dropAreaCollapseTimer, SIGNAL( timeout() ), this, SLOT( collapseDropMenu() ) );
connect( ui->metaDataDropArea, SIGNAL( dropReceived( QDropEvent* ) ), this, SLOT( dropReceived( QDropEvent* ) ) );
connect( ui->metaDataDropArea, SIGNAL( mouseLeft() ), &m_dropAreaCollapseTimer, SLOT( start() ) );
DropMenuEntry *trackEntry = new DropMenuEntry( QPixmap(":/data/images/drop-song.png" ).scaledToWidth( 32, Qt::SmoothTransformation ),
"Track",
DropJob::DropFlagTrack );
ui->metaDataDropArea->addEntry( trackEntry, true );
DropMenuEntry *albumEntry = new DropMenuEntry( QPixmap(":/data/images/drop-album.png" ).scaledToWidth( 32, Qt::SmoothTransformation ),
"Album",
DropJob::DropFlagAlbum );
ui->metaDataDropArea->addEntry( albumEntry );
DropMenuEntry *artistEntry = new DropMenuEntry( QPixmap(":/data/images/drop-all-songs.png" ).scaledToWidth( 32, Qt::SmoothTransformation ),
"Artist",
DropJob::DropFlagArtist );
ui->metaDataDropArea->addEntry( artistEntry );
DropMenuEntry *localEntry = new DropMenuEntry( QPixmap(":/data/images/drop-local-songs.png" ).scaledToWidth( 32, Qt::SmoothTransformation ),
"Local",
DropJob::DropFlagAlbum | DropJob::DropFlagLocal );
ui->metaDataDropArea->addEntry( localEntry );
DropMenuEntry *top10Entry = new DropMenuEntry( QPixmap(":/data/images/drop-top-songs.png" ).scaledToWidth( 32, Qt::SmoothTransformation ),
"Top 10",
DropJob::DropFlagArtist | DropJob::DropFlagTop10 );
ui->metaDataDropArea->addEntry( top10Entry );
}
@@ -187,7 +230,7 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
if ( result.isNull() )
return;
if ( m_currentTrack.isNull() || ( !m_currentTrack.isNull() && m_currentTrack.data()->id() != result.data()->id() ) )
onPlaybackLoading( result );
@@ -195,7 +238,7 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
if ( duration == -1 )
duration = result.data()->duration() * 1000;
ui->seekSlider->setRange( 0, duration );
ui->seekSlider->setValue( 0 );
@@ -206,15 +249,15 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
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 );
@@ -372,7 +415,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 );
@@ -519,7 +562,36 @@ void
AudioControls::dragEnterEvent( QDragEnterEvent* e )
{
if ( DropJob::acceptsMimeData( e->mimeData() ) )
{
e->acceptProposedAction();
m_dropAreaCollapseTimer.stop();
DropJob::DropFlags flags = DropJob::DropFlagsNone;
if ( e->mimeData()->hasFormat( "application/tomahawk.query.list" )
|| e->mimeData()->hasFormat( "application/tomahawk.result.list" )
|| e->mimeData()->hasFormat( "application/tomahawk.result" ) )
flags = DropJob::DropFlagsAll;
if ( e->mimeData()->hasFormat( "application/tomahawk.metadata.album" ) )
flags = DropJob::DropFlagAlbum | DropJob::DropFlagArtist | DropJob::DropFlagLocal | DropJob::DropFlagTop10;
if ( e->mimeData()->hasFormat( "application/tomahawk.metadata.artist" ) )
flags = DropJob::DropFlagArtist | DropJob::DropFlagLocal | DropJob::DropFlagTop10;
ui->metaDataDropArea->setFilter( flags );
if( !m_dropAreaExpanded )
{
m_dragAnimation->stop();
m_dragAnimation->setDirection( QAbstractAnimation::Forward );
m_dragAnimation->setStartValue( dropAreaSize() );
m_dragAnimation->setEndValue( ui->metaDataArea->height() );
m_dragAnimation->start();
m_dropAreaExpanded = true;
}
}
}
@@ -531,6 +603,32 @@ AudioControls::dragMoveEvent( QDragMoveEvent* /* e */ )
}
void
AudioControls::dragLeaveEvent( QDragLeaveEvent * )
{
qDebug() << "******************************** dragLeaveEvent" << ui->metaDataDropArea->hovered();
if( !ui->metaDataDropArea->hovered() )
m_dropAreaCollapseTimer.start();
}
void
AudioControls::collapseDropMenu()
{
// Check if the menu is hovered now...
if( ui->metaDataDropArea->hovered() )
return;
m_dropAreaExpanded = false;
m_dragAnimation->stop();
// m_dragAnimation->setDirection( QAbstractAnimation::Backward );
m_dragAnimation->setStartValue( dropAreaSize() );
m_dragAnimation->setEndValue( 0 );
m_dragAnimation->start();
}
void
AudioControls::dropEvent( QDropEvent* e )
{
@@ -538,10 +636,12 @@ 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->setDropFlags( ui->metaDataDropArea->activeEntry()->dropFlags() );
dj->tracksFromMimeData( e->mimeData() );
QTimer::singleShot( 0, this, SLOT( collapseDropMenu() ) );
e->accept();
}
}
@@ -552,8 +652,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 +667,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 +676,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 +686,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) );
@@ -594,3 +694,28 @@ AudioControls::onLoveButtonClicked( bool checked )
}
}
void
AudioControls::dragAnimationFinished()
{
}
int
AudioControls::dropAreaSize()
{
return ui->metaDataDropArea->maximumHeight();
}
void
AudioControls::setDropAreaSize( int size )
{
ui->metaDataDropArea->setMaximumHeight( size );
ui->metaDataInfoArea->setMaximumHeight( ui->metaDataArea->height() - size );
}
void
AudioControls::dropReceived( QDropEvent *event )
{
dropEvent( event );
}

View File

@@ -21,16 +21,17 @@
#include <QWidget>
#include <QTimeLine>
#include <QPropertyAnimation>
#include <QTimer>
#include "result.h"
#include "playlistinterface.h"
#include "infosystem/infosystem.h"
#include "query.h"
#include "utils/dropmenu.h"
class QDropEvent;
class QDragEnterEvent;
class QDragMoveEvent;
namespace Ui
{
class AudioControls;
@@ -39,6 +40,7 @@ namespace Ui
class AudioControls : public QWidget
{
Q_OBJECT
Q_PROPERTY( int dropAreaSize READ dropAreaSize WRITE setDropAreaSize )
public:
AudioControls( QWidget* parent = 0 );
@@ -56,8 +58,12 @@ protected:
void changeEvent( QEvent* e );
void dragEnterEvent ( QDragEnterEvent* );
void dragMoveEvent ( QDragMoveEvent* );
void dragLeaveEvent( QDragLeaveEvent * );
void dropEvent ( QDropEvent* );
int dropAreaSize();
void setDropAreaSize( int size );
private slots:
void onPlaybackStarted( const Tomahawk::result_ptr& result );
void onPlaybackLoading( const Tomahawk::result_ptr& result );
@@ -84,6 +90,10 @@ private slots:
void socialActionsLoaded();
void collapseDropMenu();
void dragAnimationFinished();
void dropReceived( QDropEvent *event );
private:
Ui::AudioControls *ui;
@@ -95,6 +105,10 @@ private:
QTimeLine m_sliderTimeLine;
qint64 m_seekMsecs;
QPropertyAnimation *m_dragAnimation;
bool m_dropAreaExpanded;
QTimer m_dropAreaCollapseTimer;
};
#endif // AUDIOCONTROLS_H

View File

@@ -84,14 +84,14 @@
<property name="spacing">
<number>0</number>
</property>
<item>
<item row="0" column="0">
<widget class="ImageButton" name="playPauseButton">
<property name="text">
<string>Play</string>
</property>
</widget>
</item>
<item>
<item row="0" column="0">
<widget class="ImageButton" name="pauseButton">
<property name="text">
<string>Pause</string>
@@ -125,265 +125,269 @@
</item>
<item>
<widget class="QWidget" name="metaDataArea" native="true">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>74</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="coverImage">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>58</width>
<height>58</height>
</size>
</property>
<widget class="DropMenu" name="metaDataDropArea" native="true">
<property name="maximumSize">
<size>
<width>58</width>
<height>58</height>
<width>16777215</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>4</number>
<widget class="QWidget" name="metaDataInfoArea" native="true">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>74</height>
</size>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,0">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="trackLabelLayout">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QueryLabel" name="artistTrackLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="text">
<string>Artist</string>
</property>
</widget>
</item>
<item>
<widget class="QueryLabel" name="albumLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="text">
<string>Album</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>4</width>
<height>8</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<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::AlignRight|Qt::AlignTop</set>
</property>
<property name="margin">
<number>0</number>
</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">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>4</number>
</property>
<item>
<widget class="QLabel" name="timeLabel">
<property name="text">
<string>Time</string>
</property>
</widget>
</item>
<item>
<widget class="SeekSlider" name="seekSlider">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>20</height>
</size>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="timeLeftLabel">
<property name="text">
<string>Time Left</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="coverImage">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>58</width>
<height>58</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>58</width>
<height>58</height>
</size>
</property>
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,0,0">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="trackLabelLayout">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QueryLabel" name="artistTrackLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="text">
<string>Artist</string>
</property>
</widget>
</item>
<item>
<widget class="QueryLabel" name="albumLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="text">
<string>Album</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>4</width>
<height>8</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<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>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<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>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>4</number>
</property>
<item>
<widget class="QLabel" name="timeLabel">
<property name="text">
<string>Time</string>
</property>
</widget>
</item>
<item>
<widget class="SeekSlider" name="seekSlider">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>20</height>
</size>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="timeLeftLabel">
<property name="text">
<string>Time Left</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
<zorder>metaDataInfoArea</zorder>
<zorder>metaDataDropArea</zorder>
</widget>
</item>
<item>
@@ -554,12 +558,18 @@
<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>
<customwidget>
<class>DropMenu</class>
<extends>QWidget</extends>
<header>utils/dropmenu.h</header>
<container>1</container>
</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,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,7 +11,6 @@
#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
#define CMAKE_SYSTEM "${CMAKE_SYSTEM}"
#cmakedefine LION
#cmakedefine SNOW_LEOPARD
#cmakedefine LEOPARD
#cmakedefine HAVE_SPARKLE
@@ -19,6 +18,5 @@
#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
@@ -69,7 +64,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
@@ -98,25 +93,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 +129,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 +136,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 +158,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,25 +169,22 @@ 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
utils/dropmenu.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
@@ -216,30 +193,24 @@ set( libSources
widgets/whatshotwidget.cpp
widgets/RecentlyPlayedPlaylistsModel.cpp
widgets/RecentPlaylistsModel.cpp
widgets/OverlayButton.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
widgets/kbreadcrumbselectionmodel.cpp
widgets/breadcrumbbar.cpp
widgets/breadcrumbbuttonbase.cpp
widgets/headerbreadcrumb.cpp
widgets/siblingcrumbbutton.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 +220,6 @@ set( libHeaders
functimeout.h
aclsystem.h
actioncollection.h
collection.h
query.h
resolver.h
@@ -260,15 +230,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
@@ -298,7 +264,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
@@ -329,24 +295,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 +340,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 +348,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,26 +369,21 @@ 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
utils/stylehelper.h
utils/dropmenu.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
@@ -442,30 +392,22 @@ set( libHeaders
widgets/whatshotwidget.h
widgets/RecentlyPlayedPlaylistsModel.h
widgets/RecentPlaylistsModel.h
widgets/OverlayButton.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
widgets/kbreadcrumbselectionmodel.h
widgets/kbreadcrumbselectionmodel_p.h
widgets/breadcrumbbar.h
widgets/breadcrumbbuttonbase.h
widgets/headerbreadcrumb.h
widgets/siblingcrumbbutton.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
@@ -490,9 +432,9 @@ set( libUI ${libUI}
widgets/infowidgets/ArtistInfoWidget.ui
widgets/infowidgets/AlbumInfoWidget.ui
playlist/topbar/topbar.ui
playlist/infobar/infobar.ui
playlist/queueview.ui
context/ContextWidget.ui
infobar/infobar.ui
)
include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.. ..
@@ -502,6 +444,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,19 +452,9 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.
${LIBPORTFWD_INCLUDE_DIR}
${THIRDPARTY_DIR}/qxt/qxtweb-standalone/qxtweb
${QuaZip_INCLUDE_DIR}
)
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
@@ -566,8 +499,7 @@ IF( APPLE )
SET( libSources ${libSources}
infosystem/infoplugins/mac/adium.mm
infosystem/infoplugins/mac/adiumplugin.cpp
utils/tomahawkutils_mac.mm
thirdparty/Qocoa/qsearchfield_mac.mm )
utils/tomahawkutils_mac.mm )
SET( libHeaders ${libHeaders}
infosystem/infoplugins/mac/adium.h
@@ -583,8 +515,6 @@ IF( APPLE )
/System/Library/Frameworks/AppKit.framework
)
ELSE( APPLE )
SET( libSources ${libSources} thirdparty/Qocoa/qsearchfield.cpp )
ENDIF( APPLE )
IF(LIBLASTFM_FOUND)
@@ -596,17 +526,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" ) );
}

View File

@@ -1,65 +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 LATCHMANAGER_H
#define LATCHMANAGER_H
#include "dllmacro.h"
#include "source.h"
#include <QtCore/QObject>
class QState;
class QStateMachine;
namespace Tomahawk
{
class DLLEXPORT LatchManager : public QObject
{
Q_OBJECT
public:
explicit LatchManager( QObject* parent = 0 );
virtual ~LatchManager();
bool isLatched( const source_ptr& src );
public slots:
void latchRequest( const Tomahawk::source_ptr& source );
void unlatchRequest( const Tomahawk::source_ptr& source );
void catchUpRequest();
private slots:
void playlistChanged( Tomahawk::PlaylistInterface* );
private:
enum State {
NotLatched = 0,
Latching,
Latched
};
State m_state;
source_ptr m_latchedOnTo;
source_ptr m_waitingForLatch;
playlistinterface_ptr m_latchedInterface;
};
}
#endif // LATCHMANAGER_H

View File

@@ -21,7 +21,7 @@
#include <QMutexLocker>
#include <QVariant>
#include "tomahawksettings.h"
#include <tomahawksettings.h>
#include "utils/logger.h"

View File

@@ -1,64 +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 "actioncollection.h"
#include <tomahawksettings.h>
#include <utils/tomahawkutils.h>
ActionCollection* ActionCollection::s_instance = 0;
ActionCollection* ActionCollection::instance()
{
return s_instance;
}
ActionCollection::ActionCollection( QObject *parent )
: QObject( parent )
{
s_instance = this;
initActions();
}
void
ActionCollection::initActions()
{
m_actionCollection[ "latchOn" ] = new QAction( tr( "&Listen Along" ), this );
m_actionCollection[ "latchOff" ] = new QAction( tr( "&Stop Listening Along" ), this );
bool isPublic = TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::PublicListening;
QAction *privacyToggle = new QAction( tr( QString( isPublic ? "&Listen Privately" : "&Listen Publicly" ).toAscii().constData() ), this );
privacyToggle->setIcon( QIcon( RESPATH "images/private-listening.png" ) );
privacyToggle->setIconVisibleInMenu( isPublic );
m_actionCollection[ "togglePrivacy" ] = privacyToggle;
}
ActionCollection::~ActionCollection()
{
s_instance = 0;
foreach( QString key, m_actionCollection.keys() )
delete m_actionCollection[ key ];
}
QAction*
ActionCollection::getAction( const QString& name )
{
return m_actionCollection.contains( name ) ? m_actionCollection[ name ] : 0;
}

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/>.
*/
#ifndef TOMAHAWKACTIONCOLLECTION_H
#define TOMAHAWKACTIONCOLLECTION_H
#include "dllmacro.h"
#include <QtGui/QAction>
class DLLEXPORT ActionCollection : public QObject
{
Q_OBJECT
public:
static ActionCollection* instance();
ActionCollection( QObject *parent);
~ActionCollection();
void initActions();
QAction* getAction( const QString &name );
private:
static ActionCollection* s_instance;
QHash< QString, QAction* > m_actionCollection;
};
#endif

View File

@@ -18,24 +18,20 @@
#include "album.h"
#include "artist.h"
#include "collection.h"
#include "database/database.h"
#include "database/databaseimpl.h"
#include "database/databasecommand_alltracks.h"
#include "query.h"
#include "utils/logger.h"
using namespace Tomahawk;
Album::Album() {}
Album::~Album() {}
album_ptr
Album::get( const Tomahawk::artist_ptr& artist, const QString& name, bool autoCreate )
{
int albid = Database::instance()->impl()->albumId( artist->id(), name, autoCreate );
if ( albid < 1 && autoCreate )
if ( albid < 1 )
return album_ptr();
return Album::get( albid, name, artist );
@@ -100,11 +96,6 @@ Album::siblingItem( int itemsAway )
return m_currentItem;
}
result_ptr
Album::currentItem() const
{
return m_currentItem;
}
bool
Album::hasNextItem()
@@ -117,11 +108,6 @@ Album::hasNextItem()
return true;
}
artist_ptr
Album::artist() const
{
return m_artist;
}
QList<Tomahawk::query_ptr>
Album::tracks()

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